const canvas = document.getElementById('canvasBuiltInScale');
const ctx = canvas.getContext('2d');
function draw(x0, y0, x1, y1) {
ctx.save();
// create a square 1x1 gradient
const gradient = ctx.createLinearGradient(0, 0, 1, 1);
gradient.addColorStop(0.4, 'yellow');
gradient.addColorStop(0.5, 'black');
gradient.addColorStop(0.6, 'red');
// scale it up to the size of the bbox
const width = x1 - x0;
const height = y1 - y0;
ctx.transform(width, 0, 0, height, x0, y0);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 1, 1);
ctx.restore();
}
draw(10, 10, 40, 30);
但是很不幸,客户不希望我使用transform方法。
我可以用原点缩放比例在画布上绘制相同的渐变。
const canvas = document.getElementById('canvasHomeRolledScale');
const ctx = canvas.getContext('2d');
function draw(x0, y0, x1, y1) {
const width = x1-x0;
const height = y1-y0;
// The problem is that with userSpace coordinates, the normal to the gradient vector from x0,y0 to x1,y1 will not go between x1,y0 and x0,y1
// I perform a home baked geometric calculation to find the normal vector to [x1-x0, y1-y0] since its normal vector will pass through [x1-x0, y1-y0]
const gradient = ctx.createLinearGradient(
x0 + (width - height) / 2,
y0 + (height - width) / 2,
x0 + (width - height) / 2 + height,
y0 + (height - width) / 2 + width
);
gradient.addColorStop(rescale(0.4), 'yellow');
gradient.addColorStop(rescale(0.5), 'black');
gradient.addColorStop(rescale(0.6), 'red');
ctx.fillStyle = gradient;
ctx.fillRect(x0, y0, width, height);
// The normal vector calculated above has the right direction, but not the right amplitude.
// Here I guy guessed that I could use pythagoras theorem to arrive at the correct scale
function rescale(percent) {
const max = Math.max(height, width)
const min = Math.min(height, width)
const f = (
Math.sqrt(
Math.pow(max, 2) + Math.pow(min, 2)
) /
Math.sqrt(
Math.pow(max, 2) + Math.pow(max, 2)
)
);
const midPoint = 0.5;
return midPoint - (midPoint-percent) * f
}
}
draw(10, 10, 40, 30);
但是我不允许更改色标的百分比。
两种情况下的反对意见都是有效的反对意见,应该对此问题有一个更简单,更优雅的解决方案。因此,我问这里的聪明人是否有解决方案:
不使用变换方法
不更改色标[这是具有使用objectBoundingBox渐变单位的线性渐变的SVG:
<canvas id=canvas width=100 height=100></canvas>
<script>
function svgimage() {
var image = `
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" version="1.1">
<defs>
<linearGradient id="myGradient" x1="0%" y1="0%" x2="100%" y2="100%" gradientUnits="objectBoundingBox">
<stop offset="40%" stop-color="yellow" />
<stop offset="50%" stop-color="black" />
<stop offset="60%" stop-color="red" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url('#myGradient')" />
</svg>`;
return encodeURIComponent(image);
}
function drawImage() {
ctx.drawImage(img, 0, 0);
}
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = drawImage
img.src = 'data:image/svg+xml;charset=utf-8,' + svgimage();
</script>
const canvas = document.getElementById('canvasBuiltInScale');
const ctx = canvas.getContext('2d');
function tcoord(x0, y0, x1, y1){
let xc = (x1 + x0) / 2;
let yc = (y1 + y0) / 2;
let dx = (x1 - x0) / 2;
let dy = (y1 - y0) / 2;
let rx0 = xc - dy;
let ry0 = yc - dx;
let rx1 = xc + dy;
let ry1 = yc + dx;
let result = [rx0,ry0,rx1,ry1];
return result;
}
function draw(x0, y0, x1, y1) {
ctx.save();
let c = tcoord(x0, y0, x0 + x1, y0 + y1);
const gradient = ctx.createLinearGradient(c[0], c[1], c[2], c[3]);
gradient.addColorStop(0.4, 'yellow');
gradient.addColorStop(0.5, 'black');
gradient.addColorStop(0.6, 'red');
ctx.fillStyle = gradient;
ctx.fillRect(x0, y0, x1, y1);
ctx.restore();
}
draw(10, 10, 80, 60);
<canvas id="canvasBuiltInScale" width="300" height="300">
</canvas>
transform
解决方案更优雅。