[英]Multiple points/colors gradient on HTML5 canvas
稍微搜索一下,我从 Mozilla 开发网络找到了这个例子
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var radgrad = ctx.createRadialGradient(0,0,1,0,0,150);
radgrad.addColorStop(0, '#A7D30C');
radgrad.addColorStop(1, 'rgba(1,159,98,0)');
var radgrad2 = ctx.createRadialGradient(0,150,1,0,150,150);
radgrad2.addColorStop(0, '#FF5F98');
radgrad2.addColorStop(1, 'rgba(255,1,136,0)');
var radgrad3 = ctx.createRadialGradient(150,0,1,150,0,150);
radgrad3.addColorStop(0, '#00C9FF');
radgrad3.addColorStop(1, 'rgba(0,201,255,0)');
var radgrad4 = ctx.createRadialGradient(150,150,1,150,150,150);
radgrad4.addColorStop(0, '#F4F201');
radgrad4.addColorStop(1, 'rgba(228,199,0,0)');
ctx.fillStyle = radgrad4;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad3;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad2;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad;
ctx.fillRect(0,0,150,150);
}
基于此,您可以将每个单元格绘制为径向渐变,并使用完全透明的颜色作为最后一步,以便与其他单元格更好地融合。
没有它,我认为您将需要根据它们与每个单元格的距离来计算每个像素颜色。
通常,如果在制作 voronoi 纹理时,将表面划分为网格,然后为每个顶点指定颜色,然后将像素的颜色与形成其单元格的顶点的距离进行插值。
另请参阅http://www.raymondhill.net/voronoi/rhill-voronoi.html以了解 html5 中真实 voronoi 的实现。 它是开源的,并在 MIT 许可下获得许可,因此您可以使用它。
您可以使用将初始点可以产生的所有可能的两种颜色线性渐变相乘(而不是相加)的原则。 检查我的例子: https : //codepen.io/tculda/pen/pogwpOw
function getProjectionDistance(a, b, c){
const k2 = b.x*b.x - b.x*a.x + b.y*b.y -b.y*a.y;
const k1 = a.x*a.x - b.x*a.x + a.y*a.y -b.y*a.y;
const ab2 = (a.x - b.x)*(a.x - b.x) + (a.y - b.y) * (a.y - b.y);
const kcom = (c.x*(a.x - b.x) + c.y*(a.y-b.y));
const d1 = (k1 - kcom) / ab2;
const d2 = (k2 + kcom) / ab2;
return {d1, d2};
}
function limit01(value){
if(value < 0){
return 0;
}
if(value > 1){
return 1;
}
return value;
}
function paddingleft0(v, v_length){
while( v.length < v_length){
v = '0' + v;
}
return v;
}
function getWeightedColorMix(points, ratios){
let r = 0;
let g = 0;
let b = 0;
for( [ind, point] of points.entries()){
r += Math.round(parseInt(point.c.substring(1,3), 16) * ratios[ind]);
g += Math.round(parseInt(point.c.substring(3,5), 16) * ratios[ind]);
b += Math.round(parseInt(point.c.substring(5,7), 16) * ratios[ind]);
}
let result = '#' + paddingleft0(r.toString(16),2) + paddingleft0(g.toString(16),2) + paddingleft0(b.toString(16),2);
return result;
}
/**
* Given some points with color attached, calculate the color for a new point
* @param p The new point position {x: number, y: number}
* @param points The array of given colored points [{x: nember, y: number, c: hexColor}]
* @return hex color string -- The weighted color mix
*/
function getGeometricColorMix( p, points ){
let colorRatios = new Array(points.length);
colorRatios.fill(1);
for ( [ind1, point1] of points.entries()){
for ( [ind2, point2] of points.entries()){
if( ind1 != ind2){
d = getProjectionDistance(point1, point2, p);
colorRatios[ind1] *= limit01(d.d2);
}
}
}
let totalRatiosSum = 0;
colorRatios.forEach(c => totalRatiosSum += c);
colorRatios.forEach((c,i) => colorRatios[i] /= totalRatiosSum);
c = getWeightedColorMix(points, colorRatios);
return c;
}
let points = [
{x:10, y:10, c:"#FF0000"},
{x:70, y:150, c:"#FFFF00"},
{x:224, y:300, c:"#00FF00"},
{x:121, y:100, c:"#00FFFF"},
{x:160, y:10, c:"#FF00FF"},
]; // these are the starting points for drawing the gradient
var canv = document.getElementById("myCanvas");
var ctx = canv.getContext("2d");
let xcs = points.map( p => p.x);
let ycs = points.map( p => p.y);
let xmin = Math.min(...xcs);
let xmax = Math.max(...xcs);
let ymin = Math.min(...ycs);
let ymax = Math.max(...ycs);
let x, y;
let mixColor;
// iterate all the pixels between the given points
for( x = xmin; x < xmax; x++ ){
for( y = ymin; y < ymax; y++ ){
mixColor = getGeometricColorMix({x:x, y:y}, points);
ctx.fillStyle = mixColor;
ctx.fillRect(x, y, 1, 1);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.