首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于HTML画布视频的SVG过滤器

基于HTML画布视频的SVG过滤器
EN

Stack Overflow用户
提问于 2018-03-16 17:58:01
回答 1查看 759关注 0票数 1

所以我想在画布上创造小故障效果,从网络摄像头中获取每一帧。下面的代码。在这里,只有当width: 200px height: 200px将此值更改为width: 600px height: 400px(容器大小)时,该代码才能工作,因此故障效应停止工作。下面的代码可以更改值canvas.width、canvas.height,并自己查看CodePen。有人知道,这是什么原因吗?怎么解决的?或者是对feTurbulence的一些限制?

代码语言:javascript
复制
const addEffect = (element, filter) => {
  element.style.webkitFilter = `url(#${filter})`;
  element.style.mozFilter = `url(#${filter})`;
  element.style.filter = `url(#${filter})`;
};

const runEffect = () => {
  const turb = document.querySelector('#displacement feTurbulence');
  const turbVal = { val: 0.000001 };

  const btTl = new TimelineLite({
    paused: true,
    onUpdate() {
      turb.setAttribute('baseFrequency', `0 ${turbVal.val}`);
    },
  });
  btTl.to(turbVal, 0.2, { val: 0.3 });
  btTl.to(turbVal, 0.2, { val: 0.000001 });

  btTl.restart();
};

const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
const video = document.createElement('video');

navigator.mediaDevices.getUserMedia({
  video: true,
}).then((stream) => {
  video.src = URL.createObjectURL(stream);
});

const canvas = document.querySelector('#canvas');

const ctx = canvas.getContext('2d');
addEffect(canvas, 'displacement');
setInterval(() => runEffect(), 1000);

const loop = () => {
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  requestAnimationFrame(loop);
};
loop();
代码语言:javascript
复制
.container {
  margin: 0 auto;
  width: 600px;
  height: 400px;
  margin-top: 100px;
  box-shadow: 1px 1px 20px #666;
  position: relative;
}
.container > canvas {
  position: absolute;
  background-color: red;
  mix-blend-mode: darken;
}
svg {
  position: absolute;
  width: 0;
  height: 0;
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<div class="container">
      <canvas id="canvas" width="200px" height="200px"></canvas>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="svg-filters">
        <defs>
          <filter id="displacement">
              <feTurbulence type="fractalNoise" baseFrequency="0.0" numOctaves="1" result="warp"></feTurbulence>
              <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="80" in="SourceGraphic" in2="warp" />
          </filter>
        </defs>
      </svg>
    </div>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-16 20:34:31

当画布的大小较大时,似乎有一些错误导致画布重新绘制的速度不够快。您可以通过调整CSS属性来强制它重新绘制,例如下面的示例中的不透明度。

代码语言:javascript
复制
const addEffect = (element, filter) => {
  element.style.webkitFilter = `url(#${filter})`;
  element.style.mozFilter = `url(#${filter})`;
  element.style.filter = `url(#${filter})`;
};

const runEffect = () => {
  const turb = document.querySelector('#displacement feTurbulence');
  const turbVal = { val: 0.000001 };

  const btTl = new TimelineLite({
    paused: true,
    onUpdate() {
      turb.setAttribute('baseFrequency', `0 ${turbVal.val}`);
    },
  });
  btTl.to(turbVal, 0.2, { val: 0.3 });
  btTl.to(turbVal, 0.2, { val: 0.000001 });

  btTl.restart();
};

const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
const video = document.createElement('video');

navigator.mediaDevices.getUserMedia({
  video: true,
}).then((stream) => {
  video.src = URL.createObjectURL(stream);
});

const canvas = document.querySelector('#canvas');

const ctx = canvas.getContext('2d');
addEffect(canvas, 'displacement');
setInterval(() => runEffect(), 1000);

/**
 * Use a hack to force the canvas to redraw
 */
const refreshCanvas = function(){
  let on = true;
  return () => {
    on = !on;
    canvas.style.opacity = on ? 1 : 0.999;
  }
}();


const loop = (timestamp) => {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    refreshCanvas(); // call our hack
    requestAnimationFrame(loop);
};
loop();
代码语言:javascript
复制
.container {
  margin: 0 auto;
  width: 600px;
  height: 400px;
  margin-top: 100px;
  box-shadow: 1px 1px 20px #666;
  position: relative;
}
.container > canvas {
  position: absolute;
  background-color: red;
  mix-blend-mode: darken;
}
svg {
  position: absolute;
  width: 0;
  height: 0;
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<div class="container">
      <canvas id="canvas" width="600" height="400"></canvas>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="svg-filters">
        <defs>
          <filter id="displacement">
              <feTurbulence type="fractalNoise" baseFrequency="0.0" numOctaves="1" result="warp"></feTurbulence>
              <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="80" in="SourceGraphic" in2="warp" />
          </filter>
        </defs>
      </svg>
    </div>

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49326902

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档