Как сделать красивую сетку на Canvas?

Рейтинг: 0Ответов: 1Опубликовано: 26.07.2023

Нужно нарисовать сетку на canvas тонкой линией. Делаю пиксельарт canvas.

Я использую ctx.lineWidth = 0.1;, тогда сетка получается размытой. Размытость видна через лупу очень сильно
При добавлении смещения на 0.5px при отрисовке сетки - всё становится неплохо, но она залезает своими краями на рисунок, и это проблема, потому что размер ячейки всего 5х5px.

Что бы сетка не рисовалась поверх пикселя я решил сместить сам рисунок на 0.5px. Получился обратный эффект - сетка чёткая и красивая, рисунок - размытый и не красивый.

Затем я решил, что проще будет нарисовать сетку в фотошопе, размером с холст (он фиксированного размера) и разместить сетку таким образом. Фотошоп категорически отказывается от рисования линий меньше 1px (оно и понятно), но всё таки я решил посмотреть что будет. В итоге - мы получаем ровную сетку, ровное изображение, но при этом каждый из пикселей теперь не 5x5, а 4х4 (кто бы мог подумать)

Вопрос: Каким образом отрисовать тонкую сетку с ячейкой 5x5px, с самой минимальной толщиной линии, что бы при этом сетка была чёткой, и само изображение не искажалось?

Сетка без смещения:

Сетка без смещения

Сетка со смещением, изображение - без:

Сетка со смещением, изображение - без

Сетка и изображение со смещением:

Сетка и изображение со смещением

// Canvas с сеткой без смещения
var canvas = document.getElementById('example1');
var ctx = canvas.getContext('2d');

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20, 20, 5, 5);
  ctx.fillRect(20, 30, 5, 5);
  ctx.fillRect(30, 30, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}

// Canvas с сеткой со смещением в 0.5
var canvas = document.getElementById('example2');
var ctx = canvas.getContext('2d');

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20, 20, 5, 5);
  ctx.fillRect(20, 30, 5, 5);
  ctx.fillRect(30, 30, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0.5; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0.5; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}

// Canvas с сеткой со смещением в 0.5
var canvas = document.getElementById('example3');
var ctx = canvas.getContext('2d');

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20.5, 20.5, 5, 5);
  ctx.fillRect(20.5, 30.5, 5, 5);
  ctx.fillRect(30.5, 30.5, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0.5; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0.5; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}
canvas{
background-color: lightgrey;
}
<p>Canvas с сеткой без смещения</p>
<canvas id="example1" width="100" height="100"></canvas>

<p>Canvas с сеткой со смещением в 0.5</p>
<canvas id="example2" width="100" height="100"></canvas>

<p>Canvas с сеткой со смещением в 0.5 и смещением изображения</p>
<canvas id="example3" width="100" height="100"></canvas>

Ответы

▲ 1Принят

Можно увеличить разрешение у canvas, сохранив при этом его размеры. увеличиваем canvas, сохраняя размеры:

canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var scale = 2;
canvas.width = canvas.width * scale;
canvas.height = canvas.height * scale;

Меняем масштаб ctx, чтобы рисовать по тем же координатам

ctx.scale(scale, scale);

Весь код:

// Canvas с сеткой без смещения
var canvas = document.getElementById('example1');
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var scale = 2;
canvas.width = canvas.width * scale;
canvas.height = canvas.height * scale;
var ctx = canvas.getContext('2d');
ctx.scale(scale, scale);

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20, 20, 5, 5);
  ctx.fillRect(20, 30, 5, 5);
  ctx.fillRect(30, 30, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}

// Canvas с сеткой со смещением в 0.5
var canvas = document.getElementById('example2');
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var scale = 2;
canvas.width = canvas.width * scale;
canvas.height = canvas.height * scale;
var ctx = canvas.getContext('2d');
ctx.scale(scale, scale);

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20, 20, 5, 5);
  ctx.fillRect(20, 30, 5, 5);
  ctx.fillRect(30, 30, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0.5; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0.5; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}

// Canvas с сеткой со смещением в 0.5
var canvas = document.getElementById('example3');
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var scale = 2;
canvas.width = canvas.width * scale;
canvas.height = canvas.height * scale;
var ctx = canvas.getContext('2d');
ctx.scale(scale, scale);

//Рисуем пиксели для наглядности
  ctx.fillStyle = "yellow";
  ctx.fillRect(20.5, 20.5, 5, 5);
  ctx.fillRect(20.5, 30.5, 5, 5);
  ctx.fillRect(30.5, 30.5, 5, 5);
  
//Задаём толщину линии и цвет
ctx.lineWidth = 0.1;
ctx.strokeStyle = "red"

// Рисуем вертикальные линии
for (var x = 0.5; x < canvas.width; x += 5) {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
}

// Рисуем горизонтальные линии
for (var y = 0.5; y < canvas.height; y += 5) {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
}
canvas {
  background-color: lightgrey;
}
<p>Canvas с сеткой без смещения</p>
<canvas id="example1" width="100px" height="100px"></canvas>

<p>Canvas с сеткой со смещением в 0.5</p>
<canvas id="example2" width="100px" height="100px"></canvas>

<p>Canvas с сеткой со смещением в 0.5 и смещением изображения</p>
<canvas id="example3" width="100px" height="100px"></canvas>