Ответ 1
Холст вычисляет из половины пикселя
ctx.moveTo(50,150.5);
ctx.lineTo(150,150.5);
Итак, начиная с половины, он зафиксирует его
Фиксированная версия: http://jsfiddle.net/9bMPD/357/
Этот ответ объясняет, почему он работает именно так.
В этом jsfiddle есть строка с линией шириной 1.
http://jsfiddle.net/mailrox/9bMPD/350/
например:
ctx.lineWidth = 1;
Тем не менее, линия имеет толщину 2px, когда она нарисована на холсте, как вы создаете линию толщиной 1px.
Я мог бы нарисовать прямоугольник (с высотой 1px), однако я хочу, чтобы линия также работала на диагоналях. Итак, как вы можете получить эту строку в 1px выше?
Спасибо!
Холст вычисляет из половины пикселя
ctx.moveTo(50,150.5);
ctx.lineTo(150,150.5);
Итак, начиная с половины, он зафиксирует его
Фиксированная версия: http://jsfiddle.net/9bMPD/357/
Этот ответ объясняет, почему он работает именно так.
Вы также можете перевести половину пикселя в направлениях X и Y, а затем использовать целые значения для своих координат (в некоторых случаях вам может понадобиться округлить их):
context.translate(0.5, 0.5)
context.moveTo(5,5);
context.lineTo(55,5);
Имейте в виду, что если вы измените размер своего холста, то перевод будет reset - так что вы снова будете переводить.
Этот ответ объясняет, почему он работает именно так.
Или как этот отвечает, чтобы получить ширину 1, вам нужно начинать с половины пикселя.
ctx.moveTo(50.5,150.5);
ctx.lineTo(150.5,150.5);
Вы видели, как впервые попал в Google? (найдите canvas line width 1px
).
Хотя я должен признать, что это не совсем "чистый" или "худой". Ferry Kobus решение намного лучше. Опять же: это отстой, вам нужно использовать "половинные пиксели" в первую очередь...
Холст может рисовать чистые прямые с помощью fillRect(). Прямоугольник с высотой 1px или шириной 1px выполняет задание. Не требуется полупиксельное значение:
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");
Если ни один из этих ответов не помог вам, проверьте масштаб вашего браузера. Мой был каким-то образом на 125%, поэтому каждая четвертая линия 1px была нарисована шириной 2px.
Я часами пытался выяснить, почему каждая скрипка в интернете работает, а моя - нет (масштаб был установлен только для моей вкладки разработчика)
Для меня только комбинация различных "идеальных по пикселям" техник помогла архивировать результаты:
Получить и масштабировать холст с соотношением пикселей:
pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio
Масштабируйте холст при изменении размера (избегайте растягивания холста по умолчанию).
умножьте lineWidth на pixelRatio, чтобы найти правильную "реальную" толщину линии пикселя:
context.lineWidth = толщина * pixelRatio;
Проверьте, является ли толщина линии нечетной или четной. добавьте половину 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>
Метод 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().