【问题标题】:Dynamically change feColorMatrix values for canvas动态更改画布的 feColorMatrix 值
【发布时间】:2020-12-10 00:00:43
【问题描述】:

我在画布 2D 渲染上下文中使用带有 feColorMatrix 的 SVG 过滤器。我希望能够动态更新矩阵的values 属性,以动态更改颜色映射。但是,当我使用setAttribute 更新矩阵时,它对后续对画布的绘制没有影响。

下面的例子重现了这个问题。该矩阵最初交换了红色和绿色通道,并且正确应用了此过滤器,以便左侧的正方形以绿色而不是红色绘制。预期的结果是,将过滤器的values属性更改为redToBlue矩阵后,右边的方块应该是蓝色的;实际结果是,尽管更新了矩阵值,右侧的方块仍保持绿色。

let redToBlue = '0 0 1 0 0  0 1 0 0 0  1 0 0 0 0  0 0 0 1 0';

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let filter = document.getElementById('filter');

ctx.fillStyle = 'red';
ctx.filter = 'url(#filter)';
ctx.fillRect(10, 10, 80, 80);
filter.setAttribute('values', redToBlue);
ctx.fillRect(110, 10, 80, 80);
<svg>
  <filter id="filter">
    <feColorMatrix type="matrix" values="0 1 0 0 0  1 0 0 0 0  0 0 1 0 0  0 0 0 1 0" />
  </filter>
</svg>
<canvas id="canvas" width="200" height="100"></canvas>

JSFiddle link

我试过filter.values = ...而不是setAttribute,在更新属性后重新分配ctx.filter = 'url(#filter)',并重置画布或SVG宽度以“强制”更新;这些都没有效果。

理想情况下,我正在寻找一种不需要创建新的 filterfeColorMatrix 元素并将其添加到 DOM 的解决方案。在实际应用中,矩阵值是动态计算的,因此无法预先编写不同的过滤器,只根据id在它们之间切换。

【问题讨论】:

    标签: javascript html5-canvas svg-filters


    【解决方案1】:

    您的目标是 &lt;filter&gt; 元素以设置新值。 但是你需要定位&lt;feColorMatrix&gt;

    let redToBlue = '0 0 1 0 0  0 1 0 0 0  1 0 0 0 0  0 0 0 1 0';
    
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    let filter = document.querySelector('#filter feColorMatrix');
    
    ctx.fillStyle = 'red';
    ctx.filter = 'url(#filter)';
    ctx.fillRect(10, 10, 80, 80);
    filter.setAttribute('values', redToBlue);
    ctx.fillRect(110, 10, 80, 80);
    <svg>
      <filter id="filter">
        <feColorMatrix type="matrix" values="0 1 0 0 0  1 0 0 0 0  0 0 1 0 0  0 0 0 1 0" />
      </filter>
    </svg>
    <canvas id="canvas" width="200" height="100"></canvas>

    【讨论】:

    • 我没想到会这么傻!谢谢,你给了我耳光的时刻比我自己注意到的要快得多。
    • @kaya3,乐于助人!
    【解决方案2】:

    我会在 SVG 上预加载过滤器,如下所示:

    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    
    ctx.fillStyle = 'red';
    ctx.filter = 'url(#filter)';
    ctx.fillRect(10, 10, 80, 80);
    ctx.filter = 'url(#redToBlue)';
    ctx.fillRect(110, 10, 80, 80);
    <svg>
      <filter id="filter">
        <feColorMatrix type="matrix" values="0 1 0 0 0  1 0 0 0 0  0 0 1 0 0  0 0 0 1 0" />
      </filter>
      <filter id="redToBlue">
        <feColorMatrix type="matrix" values="0 0 1 0 0  0 1 0 0 0  1 0 0 0 0  0 0 0 1 0" />
      </filter>
    </svg>
    <canvas id="canvas" width="200" height="100"></canvas>

    但这看起来你只是想绘制不同颜色的矩形,也许只是保存所有过滤并直接选择颜色

    【讨论】:

    • 在实际应用中,矩阵值是动态计算的,所以无法预先编写不同的过滤器,只根据id在它们之间切换。 I我不是简单地尝试绘制不同颜色的矩形,问题中的代码只是minimal reproducible example
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-08
    相关资源
    最近更新 更多