Как в canvas двигать шкалу с помощью мышки?
function drawLine(ctx, startX, startY, endX, endY, color) {
ctx.save();
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.restore();
}
let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
canvas.style.width = canvas.offsetWidth +'px';
canvas.style.height = canvas.offsetHeight +'px';
let canvasWidth = canvas.width = canvas.offsetWidth * 2;
let canvasHeight = canvas.height = canvas.offsetHeight * 2;
drawLine(ctx, 0, canvasHeight - 50, canvasWidth, canvasHeight - 50, '#000000');
ctx.font = '20px Arial';
let leftPx = 0;
for (let i = 0; i <= 100; i++) {
leftPx += 50;
drawLine(ctx, leftPx, canvasHeight - 50, leftPx, canvasHeight - 40, '#000000');
ctx.fillText(i, leftPx - 5, canvasHeight - 15);
}
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
//console.log("x: " + x + " y: " + y)
}
canvas.addEventListener('mousemove', function(e) {
getCursorPosition(canvas, e)
})
canvas {
border: 1px solid #ccc;
}
<canvas></canvas>
Ответы (1 шт):
В самом простом варианте движения могу предложить так. Не проверяю выходит ли за крайние значения, это можно добавить.
Так как холст по сути уменьшен вдвое, если не нравится несинхронность прокрутки, то можно изменить:
pos_x += (e.offsetX - start_x)*2;
let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
canvas.style.width = canvas.offsetWidth +'px';
canvas.style.height = canvas.offsetHeight +'px';
let canvasWidth = canvas.width = canvas.offsetWidth * 2;
let canvasHeight = canvas.height = canvas.offsetHeight * 2;
ctx.font = '20px Arial';
ctx.textAlign = 'center';
drawScala();
let pos_x = 0;
let start_x = 0;
let is_moving = false;
canvas.addEventListener('mousedown', e => {
start_x = e.offsetX;
is_moving = true;
});
canvas.addEventListener('mouseup', e => {
is_moving = false;
})
canvas.addEventListener('mouseleave', e => {
is_moving = false;
})
canvas.addEventListener('mousemove', moveScala);
function moveScala(e){
if(is_moving){
pos_x += e.offsetX - start_x;
start_x = e.offsetX;
drawScala(pos_x);
}
}
function drawScala(offset=0){
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
drawLine(ctx, 0, canvasHeight - 50, canvasWidth, canvasHeight - 50, '#000000');
ctx.save();
ctx.translate(offset,0);
let leftPx = 0;
for (let i = 0; i <= 100; i++) {
leftPx += 50;
drawLine(ctx, leftPx, canvasHeight - 50, leftPx, canvasHeight - 40, '#000000');
ctx.fillText(i, leftPx, canvasHeight - 15);
}
ctx.restore();
function drawLine(ctx, startX, startY, endX, endY, color) {
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
}
canvas {
border: 1px solid #ccc;
}
<canvas></canvas>
Если беспокоит производительность, то в этом случае можно заранее отрисовать всю шкалу на скрытом холсте соответствующего размера. При передвижении с помощью метода:
ctx.drawImage(hidden_canvas, offset, 0, canvasWidth, canvasHeight, 0, 0, canvasWidth, canvasHeigth);
На этой же стадии можно и масштабировать, а не за счет правил CSS:
ctx.drawImage(hidden_canvas, offset*scale, 0, canvasWidth*scale, canvasHeight*scale, 0, 0, canvasWidth, canvasHeigth);
Разумеется, при этом сам размер hidden_canvas должен быть в scale раз больше.
Хотя "на лету" масштабировать не рекомендуется, лучше отрисовать тогда всю шкалу на одноразовом скрытом холсте, перенести отрисованное с одновременным масштабированием на скрытый холст того же масштаба что и основной. И уже с этого скрытого холста брать данные без масштабирования напрямую, перенося по сути Map-данные графического ускорителя, это очень быстро и эффективно.