Использование <canvas>
может помочь вам добиться более плавного поведения:
const scale = window.devicePixelRatio || 1;
const unit = 8;
const scaledUnit = unit * scale;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const offsetLeft = canvas.offsetLeft;
const offsetTop = canvas.offsetTop;
let drawing = false;
canvas.setAttribute('width', canvas.offsetWidth * scale);
canvas.setAttribute('height', canvas.offsetHeight * scale);
canvas.onmousedown = (e) => {
drawing = true;
paintPixel(Math.floor((e.pageX - offsetLeft) / unit), Math.floor((e.pageY - offsetTop) / unit));
};
canvas.onmouseup = (e) => {
drawing = false;
};
canvas.onmousemove = (e) => {
if (drawing) {
paintPixel(Math.floor((e.pageX - offsetLeft) / unit), Math.floor((e.pageY - offsetTop) / unit));
}
};
canvas.onmouseleave = (e) => {
paint = false;
};
function paintPixel(x, y) {
ctx.fillRect(x * scaledUnit, y * scaledUnit, scaledUnit, scaledUnit);
}
body {
margin: 0;
font-size: 0;
}
#canvas {
width: 100%;
height: 100vh;
}
<canvas id="canvas"></canvas>
Однако, чтобы полностью избежать этих пропусков, вам придется рисовать линию от одной позиции курсора к другой вместо рисования отдельного "пикселя".".
Я бы использовал алгоритм линии Брезенхема , чтобы вычислить все точки между последовательными событиями.Как то так:
const scale = window.devicePixelRatio || 1;
const unit = 8;
const scaledUnit = unit * scale;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const offsetLeft = canvas.offsetLeft;
const offsetTop = canvas.offsetTop;
let drawing = false;
let lastX = null;
let lastY = null;
canvas.setAttribute('width', canvas.offsetWidth * scale);
canvas.setAttribute('height', canvas.offsetHeight * scale);
canvas.onmousedown = (e) => {
drawing = true;
lastX = Math.floor((e.pageX - offsetLeft) / unit);
lastY = Math.floor((e.pageY - offsetTop) / unit);
paintPixel(lastX, lastY);
};
canvas.onmouseup = (e) => {
drawing = false;
};
canvas.onmousemove = (e) => {
if (drawing) {
const x = Math.floor((e.pageX - offsetLeft) / unit);
const y = Math.floor((e.pageY - offsetTop) / unit);
const w = Math.abs(x - lastX);
const h = Math.abs(y - lastY);
if (w === 0 && h === 0) {
paintPixel(x, y);
} else if (w > h) {
lineLandscape(lastX, lastY, x, y);
} else {
linePortrait(lastX, lastY, x, y);
}
lastX = x;
lastY = y;
}
};
canvas.onmouseleave = (e) => {
paint = false;
};
function paintPixel(x, y) {
ctx.fillRect(x * scaledUnit, y * scaledUnit, scaledUnit, scaledUnit);
}
function lineLandscape(x0, y0, x1, y1) {
if (x0 > x1) {
[x0, x1] = [x1, x0];
[y0, y1] = [y1, y0];
}
const dx = x1 - x0;
const dy = Math.abs(y1 - y0);
const yi = y0 > y1 ? -1 : 1;
let D = 2 * dy - dx;
let y = y0;
for (let x = x0; x <= x1; ++x) {
paintPixel(x, y);
if (D > 0) {
y += yi;
D -= 2 * dx;
}
D += 2 * dy;
}
}
function linePortrait(x0, y0, x1, y1) {
if (y0 > y1) {
[x0, x1] = [x1, x0];
[y0, y1] = [y1, y0];
}
const dx = Math.abs(x1 - x0);
const dy = y1 - y0;
const xi = x0 > x1 ? -1 : 1;
let D = 2 * dx - dy;
let x = x0;
for (let y = y0; y <= y1; ++y) {
paintPixel(x, y);
if (D > 0) {
x += xi;
D -= 2 * dy;
}
D += 2 * dx;
}
}
body {
margin: 0;
font-size: 0;
}
#canvas {
width: 100%;
height: 100vh;
}
<canvas id="canvas"></canvas>
Вы также можете адаптировать этот алгоритм для работы с вашим подходом, если вам действительно нужно использовать <div>
s.