我正在尝试围绕画布的中心点旋转渐变,但我没有找到为实现此目的而需要进行的正确计算。
我想要做的一个例子是:http://victorblog.com/html5-canvas-gradient-creator/。旋转滑块正是我想要做的,但我已经查看了源代码,逻辑似乎可以使用cos / sin进行简化(虽然我不是这方面的专家,因此我问这个问题)。
我发现这个SO线程(Calculate rotation of canvas gradient)有点帮助,但这围绕中心点而不是像第一个例子中的旋转滑块那样坚持它。
非常感谢任何帮助者。
由于
答案 0 :(得分:1)
如果您不担心渐变拟合画布,那么简单的旋转就可以解决问题。
首先,你必须计算出渐变的最大长度,这样当它是对角线时它仍然适合画布。
const maxLength = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height);
然后您可以按如下方式创建渐变
var angle = ?; // The angle in radians
// A value of 0 if a gradient from right to left
const gradient = ctx.createLinearGradient(
// the start of the gradient added to the center
canvas.width / 2 + Math.cos(angle) * maxLength * 0.5,
canvas.height / 2 + Math.sin(angle) * maxLength * 0.5,
// the end of the gradient subtracted from the center
canvas.width / 2 - Math.cos(angle) * maxLength * 0.5,
canvas.height / 2 - Math.sin(angle) * maxLength * 0.5
)
这样可以工作但是当它不在对角线上时会剪切渐变。
const eachOf=(a,cb)=>{var i=0;const len=a.length;while(i<len)cb(a[i], i++);};
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const maxWidth = Math.sqrt(w * w + h * h) / 2;
// empty colour items are skipped when creating the gradient
const gradientColours = ["white","blue",,,,"green","yellow","green",,,,"cyan","black"];
function createRotatedGradient(angle, colors){
const g = ctx.createLinearGradient(
w / 2 + Math.cos(angle) * maxWidth, // start pos
h / 2 + Math.sin(angle) * maxWidth,
w / 2 - Math.cos(angle) * maxWidth, // end pos
h / 2 - Math.sin(angle) * maxWidth
);
// add colours
eachOf(colors,(col,i)=> col && g.addColorStop(i / (colors.length - 1), col) );
return g;
}
function update(timer){
ctx.fillStyle = createRotatedGradient(timer / 1000,gradientColours);
ctx.fillRect(0,0,w,h);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas { border : 2px solid black; }
&#13;
<canvas id="canvas"></canvas><
&#13;
可以通过将渐变的maxWidth
设置为canvas.height
或canvas.width
const eachOf=(a,cb)=>{var i=0;const len=a.length;while(i<len)cb(a[i], i++);};
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const maxWidth = h / 2;
// empty colour items are skipped when creating the gradient
const gradientColours = ["white","green",,,,"blue","cyan","blue",,,,"yellow","black"];
function createRotatedGradient(angle, colors){
const g = ctx.createLinearGradient(
w / 2 + Math.cos(angle) * maxWidth, // start pos
h / 2 + Math.sin(angle) * maxWidth,
w / 2 - Math.cos(angle) * maxWidth, // end pos
h / 2 - Math.sin(angle) * maxWidth
);
// add colours
eachOf(colors,(col,i)=> col && g.addColorStop(i / (colors.length - 1), col) );
return g;
}
function update(timer){
ctx.fillStyle = createRotatedGradient(timer / 1000,gradientColours);
ctx.fillRect(0,0,w,h);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas { border : 2px solid black; }
&#13;
<canvas id="canvas"></canvas><
&#13;
const eachOf=(a,cb)=>{var i=0;const len=a.length;while(i<len)cb(a[i], i++);};
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const maxWidth = w / 2;
// empty colour items are skipped when creating the gradient
const gradientColours = ["white","blue",,,,"yellow","green","yellow",,,,"cyan","black"];
function createRotatedGradient(angle, colors){
const g = ctx.createLinearGradient(
w / 2 + Math.cos(angle) * maxWidth, // start pos
h / 2 + Math.sin(angle) * maxWidth,
w / 2 - Math.cos(angle) * maxWidth, // end pos
h / 2 - Math.sin(angle) * maxWidth
);
// add colours
eachOf(colors,(col,i)=> col && g.addColorStop(i / (colors.length - 1), col) );
return g;
}
function update(timer){
ctx.fillStyle = createRotatedGradient(timer / 1000,gradientColours);
ctx.fillRect(0,0,w,h);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas { border : 2px solid black; }
&#13;
<canvas id="canvas"></canvas><
&#13;
要适合宽度和高度,您可以使用非常简单的y轴缩放。该比例是宽度和高度的比率。
const maxLen = canvas.width;
const aspect = canvas.height / canvas.width;
const angle = ?
const gradient = ctx.createLinearGradient(
// the start of the gradient added to the center
canvas.width / 2 + Math.cos(angle) * maxLen * 0.5,
canvas.height / 2 + Math.sin(angle) * maxLen * 0.5 * aspect,
// the end of the gradient subtracted from the center
canvas.width / 2 - Math.cos(angle) * maxLen * 0.5,
canvas.height / 2 - Math.sin(angle) * maxLen * 0.5 * aspect
)
const eachOf=(a,cb)=>{var i=0;const len=a.length;while(i<len)cb(a[i], i++);};
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const maxWidth = w / 2;
const aspect = h / w;
// empty colour items are skipped when creating the gradient
const gradientColours = ["white","red",,,,"yellow","green","yellow",,,,"red","black"];
function createRotatedGradient(angle, colors){
const g = ctx.createLinearGradient(
w / 2 + Math.cos(angle) * maxWidth, // start pos
h / 2 + Math.sin(angle) * maxWidth * aspect,
w / 2 - Math.cos(angle) * maxWidth, // end pos
h / 2 - Math.sin(angle) * maxWidth * aspect
);
// add colours
eachOf(colors,(col,i)=> col && g.addColorStop(i / (colors.length - 1), col) );
return g;
}
function update(timer){
ctx.fillStyle = createRotatedGradient(timer / 1000,gradientColours);
ctx.fillRect(0,0,w,h);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas { border : 2px solid black; }
&#13;
<canvas id="canvas"></canvas><
&#13;
你提供的example site拟合渐变,使其来自最近的边缘,这是一个更好的拟合,但仍然不是完美的拟合,因为渐变有时太短。由于你有该网站的方法,我不会在这里包含它。
最佳拟合稍微复杂一点,但总是适合画布,以便画布没有过度或不足的流动(不会在渐变之外设置像素,并且所有渐变都可以在任何角度看到)
有关信息,请参阅示例。数学是根据适合旋转图像的this answer进行调整的。
const eachOf=(a,cb)=>{var i=0;const len=a.length;while(i<len)cb(a[i], i++);};
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const maxWidth = w / 2;
const aspect = h / w;
// empty colour items are skipped when creating the gradient
const gradientColours = ["black","white",,,,"white","red",,,,,,,,,"yellow","green","yellow",,,,,,,,,"red","black",,,,"black","white"];
function bestFitGradient(angle, colors){
var dist = Math.sqrt(w * w + h * h) / 2; // get the diagonal length
var diagAngle = Math.asin((h / 2) / dist); // get the diagonal angle
// Do the symmetry on the angle (move to first quad
var a1 = ((angle % (Math.PI *2))+ Math.PI*4) % (Math.PI * 2);
if(a1 > Math.PI){ a1 -= Math.PI }
if(a1 > Math.PI / 2 && a1 <= Math.PI){ a1 = (Math.PI / 2) - (a1 - (Math.PI / 2)) }
// get angles from center to edges for along and right of gradient
var ang1 = Math.PI/2 - diagAngle - Math.abs(a1);
var ang2 = Math.abs(diagAngle - Math.abs(a1));
// get distance from center to horizontal and vertical edges
var dist1 = Math.cos(ang1) * h;
var dist2 = Math.cos(ang2) * w;
// get the max distance
var scale = Math.max(dist2, dist1) / 2;
// get the vector to the start and end of gradient
var dx = Math.cos(angle) * scale;
var dy = Math.sin(angle) * scale;
// create the gradient
const g = ctx.createLinearGradient(
w / 2 + dx, // start pos
h / 2 + dy,
w / 2 - dx, // end pos
h / 2 - dy
);
// add colours
eachOf(colors,(col,i)=> col && g.addColorStop(i / (colors.length - 1), col) );
return g;
}
function update(timer){
ctx.fillStyle = bestFitGradient(timer / 1000,gradientColours);
ctx.fillRect(0,0,w,h);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas { border : 2px solid black; }
&#13;
<canvas id="canvas"></canvas><
&#13;