在这个jsfiddle中,有一条线宽为1。
http://jsfiddle.net/mailrox/9bMPD/350/
例如:
ctx.lineWidth = 1;
然而,当画在画布上时,这条线是2像素粗的,如何创建一个1像素粗的线。
我可以画一个矩形(高度为1像素),但我想让这条线也能在对角线上工作。那么,如何让这条线高度只有1像素呢?
谢谢!
在这个jsfiddle中,有一条线宽为1。
http://jsfiddle.net/mailrox/9bMPD/350/
例如:
ctx.lineWidth = 1;
然而,当画在画布上时,这条线是2像素粗的,如何创建一个1像素粗的线。
我可以画一个矩形(高度为1像素),但我想让这条线也能在对角线上工作。那么,如何让这条线高度只有1像素呢?
谢谢!
Canvas计算从半个像素开始
ctx.moveTo(50,150.5);
ctx.lineTo(150,150.5);
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
ctx.lineWidth = 1;
// linear gradient from start to end of line
var grad = ctx.createLinearGradient(50, 150, 150, 150);
grad.addColorStop(0, "red");
grad.addColorStop(1, "green");
ctx.strokeStyle = grad;
ctx.beginPath();
ctx.moveTo(50, 150.5);
ctx.lineTo(150, 150.5);
ctx.stroke();
<canvas id="canvas1" width="500" height="500"></canvas>http://jsfiddle.net/9bMPD/http://jsfiddle.net/9bMPD/
这个答案解释了为什么它能够这样工作。
context.translate(.5,.5)
将所有内容向右下方偏移半个像素。完成所需操作后,使用context.setTransform(1, 0, 0, 1, 0, 0)
来恢复偏移。 - Manngoctx.moveTo(~~x + .5, ~~y + .5);
其中~~
去掉所有小数部分,而.5
则添加半个像素以使线条始终对齐。这样,我也可以将lineWidth
设置为1。 - Jelle Blaauw您还可以在X和Y方向上将翻译调整半个像素,然后使用整数值作为坐标(某些情况下可能需要四舍五入):
context.translate(0.5, 0.5)
context.moveTo(5,5);
context.lineTo(55,5);
请记住,如果您调整画布大小,则平移将被重置 - 因此您需要再次进行平移。
您可以在此处阅读有关平移功能及其使用方法的信息:
https://www.rgraph.net/canvas/reference/translate.html
此答案解释了它为什么会这样工作。
或者如这个答案所述,要获得宽度为1,您需要从半个像素开始。
ctx.moveTo(50.5,150.5);
ctx.lineTo(150.5,150.5);
对我来说,只有不同的“完美像素”技巧的组合才能帮助达到结果:
获取并缩放具有像素比的画布:
pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio
在调整大小时缩放画布(避免画布默认的拉伸缩放)。
将线宽乘以像素比例以找到适当的“实际”像素线厚度:
context.lineWidth = thickness * pixelRatio;
检查线条厚度是奇数还是偶数,对于奇数线条值,将像素比例的一半添加到线条位置中。
x = x + pixelRatio/2;
奇数线会放置在像素的中间。上述行用于将其向右移动一点。
function getPixelRatio(context) {
dpr = window.devicePixelRatio || 1,
bsr = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return dpr / bsr;
}
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
var pixelRatio = getPixelRatio(context);
var initialWidth = canvas.clientWidth * pixelRatio;
var initialHeight = canvas.clientHeight * pixelRatio;
window.addEventListener('resize', function(args) {
rescale();
redraw();
}, false);
function rescale() {
var width = initialWidth * pixelRatio;
var height = initialHeight * pixelRatio;
if (width != context.canvas.width)
context.canvas.width = width;
if (height != context.canvas.height)
context.canvas.height = height;
context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
}
function pixelPerfectLine(x) {
context.save();
context.beginPath();
thickness = 1;
// Multiple your stroke thickness by a pixel ratio!
context.lineWidth = thickness * pixelRatio;
context.strokeStyle = "Black";
context.moveTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 0));
context.lineTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 200));
context.stroke();
context.restore();
}
function pixelPerfectRectangle(x, y, w, h, thickness, useDash) {
context.save();
// Pixel perfect rectange:
context.beginPath();
// Multiple your stroke thickness by a pixel ratio!
context.lineWidth = thickness * pixelRatio;
context.strokeStyle = "Red";
if (useDash) {
context.setLineDash([4]);
}
// use sharp x,y and integer w,h!
context.strokeRect(
getSharpPixel(thickness, x),
getSharpPixel(thickness, y),
Math.floor(w),
Math.floor(h));
context.restore();
}
function redraw() {
context.clearRect(0, 0, canvas.width, canvas.height);
pixelPerfectLine(50);
pixelPerfectLine(120);
pixelPerfectLine(122);
pixelPerfectLine(130);
pixelPerfectLine(132);
pixelPerfectRectangle();
pixelPerfectRectangle(10, 11, 200.3, 443.2, 1, false);
pixelPerfectRectangle(41, 42, 150.3, 443.2, 1, true);
pixelPerfectRectangle(102, 100, 150.3, 243.2, 2, true);
}
function getSharpPixel(thickness, pos) {
if (thickness % 2 == 0) {
return pos;
}
return pos + pixelRatio / 2;
}
rescale();
redraw();
canvas {
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-crisp-edges;
image-rendering: pixelated;
image-rendering: crisp-edges;
width: 100vh;
height: 100vh;
}
<canvas id="canvas"></canvas>
在这个示例中,调整大小事件未被触发,所以您可以在GitHub上尝试该文件。
var ctx = document.getElementById("myCanvas").getContext("2d");
ctx.drawVerticalLine = function(left, top, width, color){
this.fillStyle=color;
this.fillRect(left, top, 1, width);
};
ctx.drawHorizontalLine = function(left, top, width, color){
this.fillStyle=color;
this.fillRect(left, top, width, 1);
}
ctx.drawVerticalLine(150, 0, 300, "green");
ctx.drawHorizontalLine(0, 150, 300, "red");
canvas线条宽度1px
)
尽管我必须承认这并不是很“简洁”或“精简”。Ferry Kobus'的解决方案更好。然而,首先需要使用“半像素”,这让人感到沮丧...fillRect() 方法可以用于在画布上绘制细的水平或垂直线条(无需在坐标上应用 +0.5 的偏移):
this.fillRect(left, top, 1, height);
this.fillRect(left, top, width, 1);
你可以通过替换这段代码,让线条变得更加细小,例如:
this.fillRect(left, top, 0.7, height);
this.fillRect(left, top, width, 0.7);
这将使线条变细(倾向于达到1像素宽),但它们的颜色会有些衰减。
需要注意的是,如果我们设置ctx.lineWidth=0.7(对于经典的beginPath/moveTo/lineTo/stroke序列),在Chrome上不起作用(0.7和1被解释为相同)。因此,这个fillRect()方法很有用。