在 mousemove - 画布上应用灰度和棕褐色滤镜

Posted

技术标签:

【中文标题】在 mousemove - 画布上应用灰度和棕褐色滤镜【英文标题】:Apply grayscale and sepia filters on mousemove - canvas 【发布时间】:2020-04-05 14:39:09 【问题描述】:

我正在尝试在鼠标移动时在画布上应用灰度和棕褐色滤镜。 我正在使用 CanvasRenderingContext2D.filter 来应用过滤器。 这是示例代码

var radgrad = this.ctx.createRadialGradient(x, y, 50 / 8, x, y, 50 / 2);
radgrad.addColorStop(0, 'rgb(0, 0, 0)');
radgrad.addColorStop(1, 'rgb(0, 0, 0, 1)');

this.ctx.filter = "grayscale(100%) blur(5px) opacity(50%)";
this.ctx.fillStyle = radgrad;
this.ctx.beginPath();
this.ctx.arc(x, y, 50, 0, Math.PI * 2);
this.ctx.fill();

问题是当我尝试应用灰度时无法实现它,但 blur(5px) 正在被应用。

在上述方法中如何应用灰度或棕褐色滤镜的任何解决方案。

Here's a sample fiddle

解决方案的任何线索都会有所帮助。谢谢

【问题讨论】:

请注意rgb(0, 0, 0, 1) 无效。 那么您想要的是您当前绘制的圆圈以该圆圈的形状绘制背景图像,但经过过滤?你希望它是累积的吗? (即如果您在同一位置两次通过光标,过滤器将应用两次) 我只需要在鼠标移动的路径上获得灰度或棕褐色。现在即使应用过滤器也是全黑的。 【参考方案1】:

我不太清楚你想要什么,所以我假设你想要一些累积的东西,因为在同一位置移动两次将应用过滤器两次。

为此,最简单的方法是从您的图像创建一个CanvasPattern。这样您就可以使用该图像作为填充样式来填充子路径,同时在这个新绘图上应用您的过滤器:

const img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/1024px-Sunset_2007-1.jpg";
img.onload = begin;
const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const rad = 25;

function begin() 
  canvas.width = img.width;
  canvas.height = img.height;
  // first draw the original image
  ctx.drawImage( img, 0, 0 );
  // create a CanvasPattern from it
  const patt = ctx.createPattern(img, 'no-repeat');
  // set the fillStyle to this pattern
  ctx.fillStyle = patt;
  // and the filter
  ctx.filter = "grayscale(100%) blur(5px) opacity(50%)";
  // now at each mousemove
  document.onmousemove = e => 
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    // we just draw a new arc
    ctx.beginPath();
    ctx.arc( x, y, rad, 0, Math.PI * 2 );
    // this will use the filtered pattern
    ctx.fill();
  ;
<canvas id="canvas"></canvas>

如果您不希望它是累积的(如刮刮卡),那么您可以创建一个大子路径并在每一帧重绘所有内容。

const img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/1024px-Sunset_2007-1.jpg";
img.onload = begin;
const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const rad = 25;
const points = [];
const filter = "grayscale(100%) blur(5px) opacity(50%)";

function begin() 
  canvas.width = img.width;
  canvas.height = img.height;

  const patt = ctx.createPattern(img, 'no-repeat');
  ctx.fillStyle = patt;
  
  draw();

  // now at each mousemove
  document.onmousemove = e => 
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    // store that point
    points.push(  x, y  );
    // and redraw
    draw();
  ;

function draw() 
  // remove the filter
  ctx.filter = "none";
  // so we can draw the background untouched
  ctx.drawImage( img, 0, 0 );
  // we'll now compose a big sub-path
  ctx.beginPath();
  points.forEach( ( x, y ) => 
    ctx.moveTo( x, y );
    ctx.arc( x, y, rad, 0, Math.PI * 2 )
  );
  // with the filter
  ctx.filter = filter;
  ctx.fill();
<canvas id="canvas"></canvas>

请注意,此代码假定您使用的是现代浏览器,该浏览器确实将鼠标事件限制为帧速率。如果您的目标是较旧的浏览器,您可能需要自己做。

【讨论】:

这是我需要的,createPattern 就是我需要的东西。 除此之外,您知道如何将 ColorMatrixFilter 应用于上下文吗?? 当然,context.filter 也接受url(#filter_id) css 语法。所以你必须在你的文档中有一个 元素,附加一个 你要在其上设置一个唯一的 id 属性,并在一个 <feColorMatrix> 内。

以上是关于在 mousemove - 画布上应用灰度和棕褐色滤镜的主要内容,如果未能解决你的问题,请参考以下文章

scss 灰度和棕褐色滤镜SASS mixin(支持SVG滤镜)

粒子在mousemove上跟随光标(Javascript-画布)

使用Jquery或Javascript触发mousemove事件

使用 Jquery 或 Javascript 触发 mousemove 事件

更改 iOS 的主题组件 [关闭]

关于滤镜