gpt4 book ai didi

javascript - Retina 上的 Canvas 弧线在某些点上太尖锐

转载 作者:行者123 更新时间:2023-11-30 15:50:55 26 4
gpt4 key购买 nike

我正在尝试创建在 HiDPI 设备上看起来不模糊的动画弧线。

这是我的弧线在 iPhone 5s 上的样子:

canvas arc

您可以看到接近 0、90、180 度的弧度变得太尖锐了。我怎样才能避免这种情况?

这是我的代码:

// Canvas arc progress
const can = document.getElementById('canvas');
const ctx = can.getContext('2d');
const circ = Math.PI * 2;
const quart = Math.PI / 2;
const canvasSize = can.offsetWidth;
const halfCanvasSize = canvasSize / 2;

let start = 0,
finish = 70,
animRequestId = null;

// Get pixel ratio
const ratio = (function() {
const dpr = window.devicePixelRatio || 1,
bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;

return dpr / bsr;
})();

// Set canvas h & w
can.width = can.height = canvasSize * ratio;
can.style.width = can.style.height = canvasSize + 'px';
ctx.scale(ratio, ratio)

ctx.beginPath();
ctx.strokeStyle = 'rgb(120,159,194)';
ctx.lineCap = 'square';
ctx.lineWidth = 8.0;
ctx.arc(halfCanvasSize, halfCanvasSize, halfCanvasSize - 4, 0, circ, false);
ctx.stroke();
ctx.closePath();

ctx.beginPath();
ctx.strokeStyle = 'rgb(244,247,255)';
ctx.lineCap = 'round';
ctx.lineWidth = 8.0;
ctx.closePath();

let imd = ctx.getImageData(0, 0, canvasSize, canvasSize);

const draw = (current) => {
ctx.putImageData(imd, 0, 0);
ctx.beginPath();
ctx.arc(halfCanvasSize, halfCanvasSize, halfCanvasSize - 4, -(quart), ((circ) * current) - quart, false);
ctx.stroke();
};

(function animateArcProgress() {
animRequestId = requestAnimationFrame(animateArcProgress);

if (start <= finish) {
draw(start / 100);
start += 2;
} else {
cancelAnimationFrame(animRequestId);
}
})();
body {
margin: 0;
}
div {
display: flex;
align-items: center;
justify-content: center;
height: 300px;
widht: 300px;
background: #85b1d7;
}
canvas {
height: 250px;
width: 250px;
}
<div>
<canvas id='canvas'></canvas>
</div>

最佳答案

您可以按照下面的代码在内部绘制 1/2 像素来柔化边缘。

我分别在 8、7.5 和 7 像素宽度 alpha 颜色值 0.25、0.5 和 1 处渲染了弧线 3 次。

你可以把它做成你想要的软度。

顺便说一句,使用 putImageData 非常慢,为什么不直接将背景渲染到另一个 Canvas 上并通过 ctx.drawImage(offScreencanvas,0,0) 绘制,这样您将使用 GPU 渲染背景而不是 CPU 通过图形端口总线。

我添加了更多代码来显示您可以获得的不同柔化效果,并添加了鼠标缩放,以便您可以更好地看到像素。

const can = document.getElementById('canvas');
const can2 = document.createElement("canvas"); // off screen canvas
const can3 = document.createElement("canvas"); // off screen canvas

const ctx = can.getContext('2d');
const ctx2 = can2.getContext('2d');
const ctx3 = can3.getContext('2d');
const circ = Math.PI * 2;
const quart = Math.PI / 2;
const canvasSize = can.offsetWidth;
const halfCanvasSize = canvasSize / 2;
const mouse = {x : null, y : null};
can.addEventListener("mousemove",function(e){
var bounds = can.getBoundingClientRect();
mouse.x = e.clientX - bounds.left;
mouse.y = e.clientY - bounds.top;
});
let start = 0,
finish = 70,
animRequestId = null;

// Get pixel ratio
const ratio = (function() {
const dpr = window.devicePixelRatio || 1,
bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;

return dpr / bsr;
})();

// Set canvas h & w
can2.height = can3.height = can2.width = can3.width = can.width = can.height = canvasSize * ratio;
can.style.width = can.style.height = canvasSize + 'px';

ctx.scale(ratio, ratio)
ctx2.scale(ratio, ratio)
ctx3.scale(ratio, ratio)

ctx2.beginPath();
ctx2.strokeStyle = 'rgb(120,159,194)';
ctx2.lineCap = 'square';
ctx2.lineWidth = 8.0;
ctx2.arc(halfCanvasSize, halfCanvasSize, halfCanvasSize - 4, 0, circ, false);
ctx2.stroke();
ctx2.closePath();

ctx2.beginPath();
ctx2.strokeStyle = 'rgb(244,247,255)';
ctx2.lineCap = 'round';
ctx2.lineWidth = 8.0;
ctx2.closePath();


const draw = (current) => {
ctx3.clearRect(0,0,canvas.width,canvas.height);
ctx3.drawImage(can2,0,0);
var rad = halfCanvasSize - 4;
const drawArc = () => {
ctx3.beginPath();
ctx3.arc(halfCanvasSize, halfCanvasSize, rad, -(quart), ((circ) * current) - quart, false);
ctx3.stroke();
}
// draw soft
ctx3.strokeStyle = 'rgb(244,247,255)';
ctx3.lineWidth = 8.5;
ctx3.globalAlpha = 0.25;
drawArc();;

ctx3.lineWidth = 7.0;
ctx3.globalAlpha = 0.5;
drawArc();;

ctx3.lineWidth = 6.5;
ctx3.globalAlpha = 1;
drawArc();

// draw normal
rad -= 12;
ctx3.lineWidth = 8.0;
ctx3.globalAlpha = 1;
drawArc();;



// draw ultra soft
rad -= 12;
ctx3.strokeStyle = 'rgb(244,247,255)';
ctx3.lineWidth = 9.0;
ctx3.globalAlpha = 0.1;
drawArc();

ctx3.lineWidth = 8.0;
ctx3.globalAlpha = 0.2;
drawArc();;

ctx3.lineWidth = 7.5;
ctx3.globalAlpha = 0.5;
drawArc();

ctx3.lineWidth = 6;
ctx3.globalAlpha = 1;
drawArc();




};

const zoomW = 30;
const zoomAmount = 5;
const drawZoom = () => {
ctx.drawImage(can3,0,0);
var width = zoomW * zoomAmount;
var cx = mouse.x - width / 2;
var cy = mouse.y - width / 2;
var c1x = mouse.x - zoomW / 2;
var c1y = mouse.y - zoomW / 2;
ctx.strokeStyle = 'rgb(244,247,255)';
ctx.lineWidth = 4;
ctx.strokeRect(cx,cy,width,width);
ctx.clearRect(cx,cy,width,width);
ctx.imageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.drawImage(can3,c1x,c1y,zoomW,zoomW,cx,cy,width,width);
ctx.imageSmoothingEnabled = true;
ctx.mozImageSmoothingEnabled = true;
}
function keepUpdating(){
ctx.clearRect(0,0,can.width,can.height);
drawZoom();
requestAnimationFrame(keepUpdating);
}

(function animateArcProgress() {
ctx.clearRect(0,0,can.width,can.height);

draw(start / 100);
drawZoom();


if (start <= finish) {
start += 0.5;
requestAnimationFrame(animateArcProgress);
} else {
requestAnimationFrame(keepUpdating);
}
})();
body {
margin: 0;
}
div {
display: flex;
align-items: center;
justify-content: center;
height: 300px;
widht: 300px;
background: #85b1d7;
}
canvas {
height: 250px;
width: 250px;
}
<div>
<canvas id='canvas'></canvas>
</div>

关于javascript - Retina 上的 Canvas 弧线在某些点上太尖锐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39355632/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com