For a VueJS Project, I have a video player with HTML5 <video>
tag. In this video, I want to display some blurring spots on the bottom left corner.
I am using a canvas, pure CSS method, and none of that worked.
In CSS: I used a filter: blur(20px) on a div in front of the video and it doesn't work, the blur affects the border of the div and not the center.
Image with blur test in css
With canvas, we try the same and I never get any single blur effect on it
I just need blur effect on the red part of the images :
The red part need to be blurred
<template>
<div>
<div class="contenant">
<input type='range' v-model="width" min="0" max="1281" value="0" >
<img id='image' class="img" src="image1.jpg" alt="test">
<div id='filtre' v-bind:style="{ width: width + 'px'}"></div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
width: 0,
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this ponent only -->
<style scoped>
.contenant {
width: fit-content;
}
#filtre {
height: 96%;
background-color: red;
position: absolute;
bottom: 0;
opacity: 0.33;
top: 8px;
z-index: 2;
filter: blur(50px);
}
.img{
position:relative;
}
input[type=range] {
width: 81%;
-webkit-appearance: none;
margin: 10px 0;
position: absolute;
z-index: 3;
height: -webkit-fill-available;
background-color: transparent;
}
input[type=range]::-webkit-slider-thumb {
height: 26px;
width: 26px;
border-radius: 17px;
background: #619BFF;
cursor: pointer;
-webkit-appearance: none;
}
For a VueJS Project, I have a video player with HTML5 <video>
tag. In this video, I want to display some blurring spots on the bottom left corner.
I am using a canvas, pure CSS method, and none of that worked.
In CSS: I used a filter: blur(20px) on a div in front of the video and it doesn't work, the blur affects the border of the div and not the center.
Image with blur test in css
With canvas, we try the same and I never get any single blur effect on it
I just need blur effect on the red part of the images :
The red part need to be blurred
<template>
<div>
<div class="contenant">
<input type='range' v-model="width" min="0" max="1281" value="0" >
<img id='image' class="img" src="image1.jpg" alt="test">
<div id='filtre' v-bind:style="{ width: width + 'px'}"></div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
width: 0,
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this ponent only -->
<style scoped>
.contenant {
width: fit-content;
}
#filtre {
height: 96%;
background-color: red;
position: absolute;
bottom: 0;
opacity: 0.33;
top: 8px;
z-index: 2;
filter: blur(50px);
}
.img{
position:relative;
}
input[type=range] {
width: 81%;
-webkit-appearance: none;
margin: 10px 0;
position: absolute;
z-index: 3;
height: -webkit-fill-available;
background-color: transparent;
}
input[type=range]::-webkit-slider-thumb {
height: 26px;
width: 26px;
border-radius: 17px;
background: #619BFF;
cursor: pointer;
-webkit-appearance: none;
}
Share
Improve this question
edited Sep 8, 2020 at 0:24
Rafik Farhad
1,2022 gold badges14 silver badges21 bronze badges
asked Oct 3, 2019 at 13:50
Yann ColinYann Colin
951 gold badge2 silver badges8 bronze badges
1
- Wele to Stack Overflow! Questions seeking code help must include the shortest code necessary to reproduce it in the question itself preferably in a Stack Snippet. See How to create a Minimal, Reproducible Example – Paulie_D Commented Oct 3, 2019 at 13:50
1 Answer
Reset to default 5In supporting browsers it's as easy as using an overlapping element with a backdrop-filter: blur()
CSS property.
// just make the div follow the mouse
const mouse = {
x: 0,
y: 0,
dirty: false
};
const blurme = document.getElementById('soblurme');
document.querySelector('.container')
.addEventListener('mousemove', (evt) => {
mouse.x = evt.offsetX;
mouse.y = evt.offsetY;
// recently all UI events are already debounced by UAs,
// but all vendors didn't catch up yet
if( !mouse.dirty ) {
requestAnimationFrame( move );
}
mouse.dirty = true;
});
function move() {
blurme.style.left = (mouse.x - 25) + 'px';
blurme.style.top = (mouse.y - 25) + 'px';
mouse.dirty = false;
}
.container { position: relative; }
#soblurme {
position: absolute;
border: 1px solid white;
pointer-events: none;
width: 50px;
height: 50px;
left: 70px;
top: 20px;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
video {
width: 100%;
cursor: none;
}
<div class="container">
<video autoplay muted controls>
<source src="https://upload.wikimedia/wikipedia/mons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent./s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<div id="soblurme"></div>
</div>
For others you'll need to draw that part of the video again on a canvas:
const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
const ctx = canvas.getContext('2d');
if( ctx.filter !== "none" ) {
// in case 2DContext.filter is not supported (Safari), some libraries can do the blur for us
// I'll let the readers choose the one they prefer and implement it
console.warn( "we should use a falbback like StackBlur.js" );
}
const spread = 10;
ctx.filter = 'blur(' + spread + 'px)';
const border_width = 1; // because we add a css border around the canvas element
let playing = false;
vid.onplaying = startDrawing;
vid.onpause = stopDrawing;
function startDrawing() {
playing = true;
loop();
}
function stopDrawing() {
playing = false;
}
function loop() {
if( mouse.dirty ) {
canvas.style.left = mouse.x + 'px';
canvas.style.top = mouse.y + 'px';
mouse.dirty = false;
}
draw();
if( playing ) {
requestAnimationFrame(loop);
}
}
function draw() {
const vid_rect = vid.getBoundingClientRect();
const can_rect = canvas.getBoundingClientRect();
const s_x = (can_rect.left - vid_rect.left) + border_width;
const s_y = (can_rect.top - vid_rect.top) + border_width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// if we are lazy, we can draw the whole image
// but the blur effect is quite heavy to calculate
// ctx.drawImage(vid, -s_x, -s_y, vid_rect.width, vid_rect.height);
// so for better performances we may prefer to calculate the smallest area to draw
// because blur spreads we need to draw outside a little bit anyway
const offset = spread * 2;
const output_w = canvas.width + (offset * 2);
const output_h = canvas.height + (offset * 2);
const ratio_x = vid_rect.width / vid.videoWidth;
const ratio_y = vid_rect.height / vid.videoHeight;
ctx.drawImage(
vid,
(s_x - offset) / ratio_x, (s_y - offset) / ratio_y, output_w / ratio_x, output_h / ratio_y,
-offset, -offset, output_w, output_h
);
}
// move with mouse
const mouse = {
x: 0,
y: 0,
dirty: false
};
document.querySelector('.container')
.addEventListener( 'mousemove', ( evt ) => {
mouse.x = evt.offsetX - canvas.width / 2;
mouse.y = evt.offsetY - canvas.height / 2;
if( !mouse.dirty && !playing ) {
requestAnimationFrame( loop );
}
mouse.dirty = true;
});
.container { position: relative; }
#soblurme {
position: absolute;
border: 1px solid white;
pointer-events: none;
left: 70px;
top: 20px;
}
video {
width: 100%;
}
<div class="container">
<video autoplay muted controls>
<source src="https://upload.wikimedia/wikipedia/mons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent./s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
And to make it conditionally, we can feature detect it:
const supportsBackdropFilter = (function() {
const style = document.createElement('_').style;
style.cssText = 'backdrop-filter: blur(2px);webkit-backdrop-filter: blur(2px)';
return style.length !== 0 &&
(document.documentMode === undefined || document.documentMode > 9);
})();
So all together:
const supports_backdrop_filter = (function() {
const style = document.createElement('_').style;
style.cssText = 'backdrop-filter: blur(2px);-webkit-backdrop-filter: blur(2px);';
return style.length !== 0 &&
(document.documentMode === undefined || document.documentMode > 9);
})();
const mouse = {
x: 0,
y: 0,
dirty: false
};
const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
let playing = false;
const ctx = canvas.getContext('2d');
const spread = 10;
const border_width = 1; // because we add a css border around the canvas element
document.querySelector('.container')
.addEventListener('mousemove', (evt) => {
mouse.x = evt.offsetX;
mouse.y = evt.offsetY;
if( !mouse.dirty ) {
if( supports_backdrop_filter ) {
requestAnimationFrame( move );
}
else if( !playing ) {
requestAnimationFrame( loop );
}
}
mouse.dirty = true;
});
function move() {
canvas.style.left = (mouse.x - 25) + 'px';
canvas.style.top = (mouse.y - 25) + 'px';
mouse.dirty = false;
}
// unsupporting browsers
if( !supports_backdrop_filter ) {
ctx.filter = 'blur(' + spread + 'px)';
vid.onplaying = startDrawing;
vid.onpause = stopDrawing;
}
function startDrawing() {
playing = true;
loop();
}
function stopDrawing() {
playing = false;
}
function loop() {
if( mouse.dirty ) {
move();
}
draw();
if( playing ) {
requestAnimationFrame(loop);
}
}
function draw() {
const vid_rect = vid.getBoundingClientRect();
const can_rect = canvas.getBoundingClientRect();
const s_x = (can_rect.left - vid_rect.left) + border_width;
const s_y = (can_rect.top - vid_rect.top) + border_width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const offset = spread * 2;
const output_w = canvas.width + (offset * 2);
const output_h = canvas.height + (offset * 2);
const ratio_x = vid_rect.width / vid.videoWidth;
const ratio_y = vid_rect.height / vid.videoHeight;
ctx.drawImage(
vid,
(s_x - offset) / ratio_x, (s_y - offset) / ratio_y, output_w / ratio_x, output_h / ratio_y,
-offset, -offset, output_w, output_h
);
}
.container { position: relative; }
#soblurme {
position: absolute;
border: 1px solid white;
pointer-events: none;
left: 70px;
top: 20px;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
video {
width: 100%;
cursor: none;
}
<div class="container">
<video autoplay muted controls>
<source src="https://upload.wikimedia/wikipedia/mons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent./s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
OP asked in a ment so that the blur actually spreads instead of having a clear-cut like in the previous examples.
To do so in CSS, it should have been just a matter of adding an inner element on which we would set the backdrop-filter with half of the blurring along with some margin, and then add a blur
on the element with the other half of the blur as a simple filter
rule.
However, it seems there is a bug in current Blink where backdrop-filter
will simply be discarded if one of the ancestors already had a blur()
applied to it...
So this will currently only work in Safari:
// just make the div follow the mouse
const mouse = {
x: 0,
y: 0,
dirty: false
};
const blurme = document.getElementById('soblurme');
document.querySelector('.container')
.addEventListener('mousemove', (evt) => {
mouse.x = evt.offsetX;
mouse.y = evt.offsetY;
// recently all UI events are already debounced by UAs,
// but all vendors didn't catch up yet
if( !mouse.dirty ) {
requestAnimationFrame( move );
}
mouse.dirty = true;
});
function move() {
blurme.style.left = (mouse.x - 25) + 'px';
blurme.style.top = (mouse.y - 25) + 'px';
mouse.dirty = false;
}
.container { position: relative; }
#soblurme {
position: absolute;
pointer-events: none;
width: 50px;
height: 50px;
left: 70px;
top: 20px;
--spread: 10px;
filter: blur(calc(var(--spread) ));
}
#soblurme > div {
width: calc(100% - var(--spread));
height: calc(100% - var(--spread));
backdrop-filter: blur(calc(var(--spread) / 2));
-webkit-backdrop-filter: blur(calc(var(--spread) / 2));
padding: 10px;
}
video {
width: 100%;
cursor: none;
}
<div class="container">
<video autoplay muted controls>
<source src="https://upload.wikimedia/wikipedia/mons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent./s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<div id="soblurme"> <!-- we apply a simple blur() here -->
<div></div> <!-- this one will get the backdrop-filter -->
</div>
</div>
However the good news is that the canvas version bees way simpler.
What we'll do is to simply draw the video on the canvas, and then apply a CSS filter:blur()
on the canvas element directly from CSS.
Since we don't need to account for the spread, the calculations for drawImage are easier, but since we don't apply any filter, we can even use the lazy version that was in the ments of the second snippet:
const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
const ctx = canvas.getContext('2d');
let playing = false;
vid.onplaying = startDrawing;
vid.onpause = stopDrawing;
function startDrawing() {
playing = true;
loop();
}
function stopDrawing() {
playing = false;
}
function loop() {
if( mouse.dirty ) {
canvas.style.left = mouse.x + 'px';
canvas.style.top = mouse.y + 'px';
mouse.dirty = false;
}
draw();
if( playing ) {
requestAnimationFrame(loop);
}
}
function draw() {
const vid_rect = vid.getBoundingClientRect();
const can_rect = canvas.getBoundingClientRect();
const s_x = (can_rect.left - vid_rect.left);
const s_y = (can_rect.top - vid_rect.top);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(vid, -s_x, -s_y, vid_rect.width, vid_rect.height);
}
// move with mouse
const mouse = {
x: 0,
y: 0,
dirty: false
};
document.querySelector('.container')
.addEventListener( 'mousemove', ( evt ) => {
mouse.x = evt.offsetX - canvas.width / 2;
mouse.y = evt.offsetY - canvas.height / 2;
if( !mouse.dirty && !playing ) {
requestAnimationFrame( loop );
}
mouse.dirty = true;
});
.container { position: relative; }
#soblurme {
position: absolute;
pointer-events: none;
left: 70px;
top: 20px;
filter: blur(10px);
}
video {
width: 100%;
}
<div class="container">
<video autoplay muted controls>
<source src="https://upload.wikimedia/wikipedia/mons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent./s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745650882a4638256.html
评论列表(0条)