javascript - 带有 HTML5 画布的三角形每个顶点的渐变
问题描述
如何在给定每个顶点颜色的情况下使用从顶点开始的渐变填充三角形?
我正在尝试重现这样的内容:
我正在使用fill
HTML5 画布 Context2D 中的内置函数。我试图避免必须根据它们到顶点的距离来处理逐像素插值。我担心它不会像内置fill
函数(?)那样高性能。我现在也不能处理 WebGL。
我已经使用径向渐变做了一个技巧,但是,我的幼稚方法存在一些问题:
- 颜色似乎没有很好地融合
- 最后应用的渐变会覆盖其他渐变
- 变量中使用的
radius
值是任意的
OBS:我不知道它是否相关,但我正在构建一个三角形带(实际上是索引几何)。
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var v1 = { x: 100, y: 0 };
var v2 = { x: 0, y: 180 };
var v3 = { x: 200, y: 180 };
var radius = 175;
var grd1 = ctx.createRadialGradient(v1.x, v1.y, 0, v1.x, v1.y, radius);
grd1.addColorStop(0, "#FF0000FF");
grd1.addColorStop(1, "#FF000000");
var grd2 = ctx.createRadialGradient(v2.x, v2.y, 0, v2.x, v2.y, radius);
grd2.addColorStop(0, "#00FF00FF");
grd2.addColorStop(1, "#00FF0000");
var grd3 = ctx.createRadialGradient(v3.x, v3.y, 0, v3.x, v3.y, radius);
grd3.addColorStop(0, "#0000FFFF");
grd3.addColorStop(1, "#0000FF00");
ctx.beginPath();
ctx.moveTo(v1.x, v1.y);
ctx.lineTo(v2.x, v2.y);
ctx.lineTo(v3.x, v3.y);
ctx.closePath();
ctx.fillStyle = "#FFFFFFFF"; // fill with white and apply the gradients on top of it
ctx.fill();
ctx.fillStyle = grd1;
ctx.fill();
ctx.fillStyle = grd2;
ctx.fill();
ctx.fillStyle = grd3;
ctx.fill();
<canvas width="200" height="180"></canvas>
解决方案
- 颜色似乎没有很好地融合
为此,您可以globalCompositeOperation
将 2D 上下文的属性用于其混合模式之一,即使在您的情况下"lighter"
,具有黑色背景的合成模式似乎会产生最接近您的模型的结果。
- 最后应用的渐变会覆盖其他渐变
由于前面的要点,情况不再如此。
- 半径变量中使用的值是任意的
在我看来不是这样,它确实对应于等边三角形的每个点与其中心之间的距离,这很有意义。
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
// reordered to make the same as OP's image
var v1 = { x: 0, y: 180 };
var v2 = { x: 200, y: 180 };
var v3 = { x: 100, y: 0 };
var radius = 180;
var grd1 = ctx.createRadialGradient(v1.x, v1.y, 0, v1.x, v1.y, radius);
grd1.addColorStop(0, "#FF0000FF");
grd1.addColorStop(1, "#FF000000");
var grd2 = ctx.createRadialGradient(v2.x, v2.y, 0, v2.x, v2.y, radius);
grd2.addColorStop(0, "#00FF00FF");
grd2.addColorStop(1, "#00FF0000");
var grd3 = ctx.createRadialGradient(v3.x, v3.y, 0, v3.x, v3.y, radius);
grd3.addColorStop(0, "#0000FFFF");
grd3.addColorStop(1, "#0000FF00");
ctx.beginPath();
ctx.moveTo(v1.x, v1.y);
ctx.lineTo(v2.x, v2.y);
ctx.lineTo(v3.x, v3.y);
ctx.closePath();
// fill with black
ctx.fill();
// set blend mode
ctx.globalCompositeOperation = "lighter";
ctx.fillStyle = grd1;
ctx.fill();
ctx.fillStyle = grd2;
ctx.fill();
ctx.fillStyle = grd3;
ctx.fill();
// if you need to draw something else, don't forget to reset the gCO
ctx.globalCompositeOperation = "source-over";
<canvas width="200" height="180"></canvas>
推荐阅读
- winapi - 获取音频设备的图标
- r - 在 Tidyverse 中过滤事件数据的时间
- python - 在我的 SQL Server 数据库中存储 TimeDelta
- android - 在 viewpager 片段的 recyclerview 中插入原生广告
- node.js - UnhandledPromiseRejectionWarning:错误:ENOENT:没有这样的文件或目录,打开
- mongodb - 如何在Mongodb中获取属性总和达到一定值的文档组合?
- debugging - 更改对象在调试器/检查器变量值表中的显示方式
- javascript - 在 PHP 中寻找这个 JS 函数的等价物
- python - 使用 defaultlist() 创建一个函数来初始化多个字典?
- powershell - Powershell - 在查看创建新文件的文件夹时 - 如果“Register-ObjectEvent”中的语句未触发