Reputation: 117
I'm trying to scale canvas to/from mouse position, but it works not perfect (always goes few cells away from mouse pos). I've read all similar posts but i don't know what's wrong.
https://jsfiddle.net/shumikua/3afxtmqw/
All code is only to run snippet, it works good. Problem is in function scale.
function scale(svg, e){
let x = e.originalEvent.offsetX - canvas[0].offsetLeft;
let y = e.originalEvent.offsetY - canvas[0].offsetTop;
let deltaY = e.originalEvent.deltaY;
let scale_now = deltaY < 0 ? 1.5 : 1/1.5;
scaleFactor *= scale_now;
panX = x - (x - panX)*scale_now;
panY = y - (y - panY)*scale_now;
draw();
}
Upvotes: 1
Views: 119
Reputation: 6683
In function scale()
keep the same values for x
and y
before and after scaling. You just need to update coordinates in screen panX
and panY
.
var canvas;
var ctx;
var ww;
var wh;
var scaleFactor;
var panX;
var panY;
function draw() {
ctx.clearRect(0, 0, ww, wh);
let size = Math.min((ww - 10) / 60, (wh - 10) / 60);
let padding = {
x: ww - size * 60,
y: wh - size * 60,
}
ctx.save();
ctx.translate(panX, panY);
ctx.scale(scaleFactor, scaleFactor);
for (let i = 0; i < 60; i++) {
for (let j = 0; j < 60; j++) {
ctx.fillStyle = '#f' + i + j + 'f';
ctx.fillRect(padding.x / 2 + size * j, padding.y / 2 + size * i, size, size);
}
}
ctx.restore();
}
function scale(svg, e) {
let x = e.originalEvent.offsetX;
let y = e.originalEvent.offsetY;
let deltaY = e.originalEvent.deltaY;
let scale_now = deltaY < 0 ? 1.5 : 1 / 1.5;
scaleFactor *= scale_now;
panX = x - (x - panX) * scale_now;
panY = y - (y - panY) * scale_now;
draw();
}
function move(svg, x, y) {
panX += x;
panY += y;
draw();
}
function initialise() {
ctx = canvas.get(0).getContext('2d');
ww = canvas.outerWidth();
wh = canvas.outerHeight();
canvas.attr('width', ww);
canvas.attr('height', wh);
scaleFactor = 1.0;
panX = 0;
panY = 0;
draw();
}
$(document).ready(function() {
canvas = $('.canva');
initialise();
canvas.bind('mousewheel DOMMouseScroll', function(e) {
e.preventDefault();
});
canvas.on('mousewheel DOMMouseScroll', function(e) {
if (e.ctrlKey) {
scale($(this), e);
} else if (e.shiftKey) {
move($(this), -e.originalEvent.deltaY / 5, 0);
} else {
move($(this), 0, -e.originalEvent.deltaY / 5);
}
});
canvas.mousedown(function(e) {
if (e.which !== 2) return;
e.preventDefault();
$(this).css('cursor', 'move');
let old_x = e.offsetX;
let old_y = e.offsetY;
$(this).mousemove(function(emove) {
let x = emove.offsetX;
let y = emove.offsetY;
move($(this), emove.offsetX - old_x, emove.offsetY - old_y);
old_x = x;
old_y = y;
});
$(this).mouseup(function() {
$(this).off('mousemove');
$(this).css('cursor', 'default');
});
$(this).mouseleave(function() {
$(this).off('mousemove');
$(this).css('cursor', 'default');
});
});
});
canvas {
image-rendering: optimizeSpeed;
/* Older versions of FF */
image-rendering: -moz-crisp-edges;
/* FF 6.0+ */
image-rendering: -webkit-optimize-contrast;
/* Safari */
image-rendering: -o-crisp-edges;
/* OS X & Windows Opera (12.02+) */
image-rendering: pixelated;
/* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor;
shape-rendering: crispEdges;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" class="canva" width="200" height="200"></canvas>
Hold Ctrl and scroll wheel to scale.
Upvotes: 1