如何模糊 HTML5 视频标签的特定区域?
How to blur a specific region of a HTML5 video tag?
对于 VueJS 项目,我有一个带有 HTML5 <video>
标签的视频播放器。在这个视频中,我想在左下角显示一些模糊点。
我正在使用 canvas 纯 CSS 方法,none 有效。
在 CSS 中:我在视频前面的 div 上使用了滤镜:blur(20px) 但它不起作用,模糊影响了 [=34] 的边框=] 而不是中心。
Image with blur test in css
对于 canvas,我们尝试了同样的方法,但我从来没有得到任何单一的模糊效果
我只需要对图像的红色部分进行模糊处理:
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 component 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;
}
在支持浏览器的情况下,就像使用带有 backdrop-filter: blur()
CSS 属性.
的重叠元素一样简单
// 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<div id="soblurme"></div>
</div>
对于其他人,您需要在 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
要有条件地进行,我们可以对其进行特征检测:
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);
})();
总之:
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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
OP 在评论中询问,以便模糊实际扩散而不是像前面的示例那样清晰。
在 CSS 中这样做 应该 只是添加一个内部元素,我们将在其上设置背景过滤器的一半模糊一些边距,然后在元素上添加一个 blur
,另一半模糊作为一个简单的 filter
规则。
然而,目前的 Blink 中似乎存在一个错误,如果其中一个祖先已经应用了 blur()
,backdrop-filter
将被简单地丢弃...
所以这目前只能在 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/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>
不过好消息是 canvas 版本变得更简单了。
我们要做的是简单地在 canvas 上绘制视频,然后直接从 CSS 在 canvas 元素上应用 CSS filter:blur()
。
由于我们不需要考虑传播,drawImage 的计算更容易,但由于我们不应用任何过滤器,我们甚至可以使用第二个代码段注释中的惰性版本:
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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
对于 VueJS 项目,我有一个带有 HTML5 <video>
标签的视频播放器。在这个视频中,我想在左下角显示一些模糊点。
我正在使用 canvas 纯 CSS 方法,none 有效。
在 CSS 中:我在视频前面的 div 上使用了滤镜:blur(20px) 但它不起作用,模糊影响了 [=34] 的边框=] 而不是中心。
Image with blur test in css
对于 canvas,我们尝试了同样的方法,但我从来没有得到任何单一的模糊效果
我只需要对图像的红色部分进行模糊处理:
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 component 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;
}
在支持浏览器的情况下,就像使用带有 backdrop-filter: blur()
CSS 属性.
// 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<div id="soblurme"></div>
</div>
对于其他人,您需要在 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
要有条件地进行,我们可以对其进行特征检测:
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);
})();
总之:
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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>
OP 在评论中询问,以便模糊实际扩散而不是像前面的示例那样清晰。
在 CSS 中这样做 应该 只是添加一个内部元素,我们将在其上设置背景过滤器的一半模糊一些边距,然后在元素上添加一个 blur
,另一半模糊作为一个简单的 filter
规则。
然而,目前的 Blink 中似乎存在一个错误,如果其中一个祖先已经应用了 blur()
,backdrop-filter
将被简单地丢弃...
所以这目前只能在 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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/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>
不过好消息是 canvas 版本变得更简单了。
我们要做的是简单地在 canvas 上绘制视频,然后直接从 CSS 在 canvas 元素上应用 CSS filter:blur()
。
由于我们不需要考虑传播,drawImage 的计算更容易,但由于我们不应用任何过滤器,我们甚至可以使用第二个代码段注释中的惰性版本:
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.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
<source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
</video>
<canvas id="soblurme" width="50" height="50"></canvas>
</div>