Javascript Canvas : 在给定坐标处应用缩放
Javascript Canvas : Apply zoom at given coordinates
我正在努力实现 canvas 缩放(在鼠标滚轮上),使用 Vanilla Javascript,但没有成功。
滚动滚轮时,必须在鼠标坐标上应用缩放。
之前有人在这里问过,但是我的情况很不一样,考虑到 我不能使用 canvasContext.translate
, offsetX
和 offsetY
的值必须保留在它的绝对表示(未缩放)
我真的很感激一些光。
在下面的代码片段中,我提供了我当前的和功能失调的实现。当您放大和缩小保持相同的缩放坐标时,您将看到它是如何工作的,但是一旦您将鼠标移动到新坐标(当 scale != 1 时)并继续缩放,新的偏移量就会变得错误。
// initiate variabks : canvas ref, offsets, scale...
const context = document.getElementById('c').getContext('2d');
let scale = 1;
let scaleFactor = 0.2;
let offsetX=0;
let offsetY=0;
// Handle mousenwheel zoom
context.canvas.onwheel= function(e){
e.preventDefault();
// calculate scale direction 6 new value
let direction = e.deltaY > 0 ? 1 : -1;
scale += scaleFactor * direction;
// calculatethe new offsets (unscaled values)
offsetX = e.offsetX - (e.offsetX / scale);
offsetY = e.offsetY - (e.offsetY / scale);
// apply new scale
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(scale, scale);
}
// clear canvas and draw two boxes
// NO CHANGES CAN BE DONE IN THIS FUNCTION
function render(){
context.beginPath();
context.clearRect(0,0,context.canvas.width/scale,context.canvas.height/scale);
context.rect(100-offsetX,50-offsetY,50,50);
context.rect(200-offsetX,50-offsetY,50,50);
context.stroke();
document.getElementById("info").innerHTML=`
Scale : ${scale} <br>
Offets : ${ Math.round(offsetX) + ' , ' + Math.round(offsetY)} <br>
`;
requestAnimationFrame( render );
}
render()
<canvas id="c" width="350" height="150" style="border: 1px solid red;"></canvas>
<div id="info"></div>
主要思想是:
context.translate(cx, cy);
context.scale(scale, scale);
context.translate(-cx, -cy);
其中 cx 和 cy 是对象组中心的坐标。
观察:负比例翻转对象。这就是我使用填充红色和黑色的原因。
// global vars : canvas, scroll & scale
let info = document.getElementById("info");
const canvas = document.getElementById('c');
let cw = canvas.width = 350,cx = cw/2;
let ch = canvas.height = 150,cy = 75;
const context = c.getContext('2d');
let scrollX = 0;
let scrollY = 0;
let scale = 1;
let scaleFactor = 0.02;
// clear canvas and draw two boxes
function render(){
//context.clearRect(0, 0, canvas.width/scale, canvas.height/scale);
context.beginPath();
context.rect(100,50,50,50);
context.fillStyle = "red";
context.fill();
context.beginPath();
context.rect(200,50,50,50);
context.fillStyle = "black";
context.fill();
info.innerHTML=`Scroll: ${scrollX},${scrollY} - Scale : ${scale}`
requestAnimationFrame( render );
}
// handlencursor keys to move scroll
window.onkeydown = function(event){
event.preventDefault();
if(event.keyCode == 37) scrollX -=10;
else if(event.keyCode == 39) scrollX +=10;
else if(event.keyCode == 38) scrollY -=10;
else if(event.keyCode == 40) scrollY +=10;
};
// Handl mousenwheel zoom
canvas.onwheel= function(e){
e.preventDefault();
context.clearRect(-cw, -ch, 2 * cw, 2 * ch)
let direction = e.deltaY > 0 ? 1 : -1;
scrollX += Math.round(e.offsetX * scaleFactor * direction);
scrollY += Math.round(e.offsetY * scaleFactor * direction);
scale += scaleFactor * direction;
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(cx, cy);
context.scale(scale, scale);
context.translate(-cx, -cy);
//render()
}
render()
<canvas id="c" width="350" height="150" style="border: 1px solid red;"></canvas>
<div id="info"></div>
我终于明白了... canvas不使用context.translate()
的任意坐标缩放
我附上我的解决方案,还有一点好处:canvas 平移(光标键滚动)。
我希望对某人有用。
// initiate variables : canvas ref, offsets, scale...
const context = document.getElementById('c').getContext('2d');
let scale = 1;
let scaleFactor = 0.2;
let scrollX = 0;
let scrollY = 0;
let info = document.getElementById("info");
// Handle mousenwheel zoom
context.canvas.onwheel = function(e){
e.preventDefault();
let previousScale= scale;
// calculate scale direction 6 new scale value
let direction = e.deltaY > 0 ? 1 : -1;
scale += scaleFactor * direction;
// calculate the new scroll values
scrollX += ( e.offsetX / previousScale ) - (e.offsetX / scale);
scrollY += ( e.offsetY / previousScale ) - ( e.offsetY / scale);
// apply new scale in a non acumulative way
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(scale, scale);
}
// clear canvas and draw two boxes
function render(){
context.beginPath();
context.clearRect(0,0,context.canvas.width/scale, context.canvas.height/scale);
context.rect(100-scrollX,50-scrollY,50,50);
context.rect(200-scrollX,50-scrollY,50,50);
context.stroke();
info.innerHTML=`
Scale : ${scale} <br>
Scroll: ${scrollX},${scrollY} <br>
`
requestAnimationFrame( render );
}
// handlencursor keys to move scroll
window.onkeydown = function(event){
event.preventDefault();
if(event.keyCode == 37) scrollX -=10;
else if(event.keyCode == 39) scrollX +=10;
else if(event.keyCode == 38) scrollY -=10;
else if(event.keyCode == 40) scrollY +=10;
};
context.canvas.focus()
render()
<canvas id="c" width="400" height="150" style="border: 1px solid red;" tabindex="1"></canvas>
<div id="info"></div>
我正在努力实现 canvas 缩放(在鼠标滚轮上),使用 Vanilla Javascript,但没有成功。
滚动滚轮时,必须在鼠标坐标上应用缩放。
之前有人在这里问过,但是我的情况很不一样,考虑到 我不能使用 canvasContext.translate
, offsetX
和 offsetY
的值必须保留在它的绝对表示(未缩放)
我真的很感激一些光。
在下面的代码片段中,我提供了我当前的和功能失调的实现。当您放大和缩小保持相同的缩放坐标时,您将看到它是如何工作的,但是一旦您将鼠标移动到新坐标(当 scale != 1 时)并继续缩放,新的偏移量就会变得错误。
// initiate variabks : canvas ref, offsets, scale...
const context = document.getElementById('c').getContext('2d');
let scale = 1;
let scaleFactor = 0.2;
let offsetX=0;
let offsetY=0;
// Handle mousenwheel zoom
context.canvas.onwheel= function(e){
e.preventDefault();
// calculate scale direction 6 new value
let direction = e.deltaY > 0 ? 1 : -1;
scale += scaleFactor * direction;
// calculatethe new offsets (unscaled values)
offsetX = e.offsetX - (e.offsetX / scale);
offsetY = e.offsetY - (e.offsetY / scale);
// apply new scale
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(scale, scale);
}
// clear canvas and draw two boxes
// NO CHANGES CAN BE DONE IN THIS FUNCTION
function render(){
context.beginPath();
context.clearRect(0,0,context.canvas.width/scale,context.canvas.height/scale);
context.rect(100-offsetX,50-offsetY,50,50);
context.rect(200-offsetX,50-offsetY,50,50);
context.stroke();
document.getElementById("info").innerHTML=`
Scale : ${scale} <br>
Offets : ${ Math.round(offsetX) + ' , ' + Math.round(offsetY)} <br>
`;
requestAnimationFrame( render );
}
render()
<canvas id="c" width="350" height="150" style="border: 1px solid red;"></canvas>
<div id="info"></div>
主要思想是:
context.translate(cx, cy);
context.scale(scale, scale);
context.translate(-cx, -cy);
其中 cx 和 cy 是对象组中心的坐标。
观察:负比例翻转对象。这就是我使用填充红色和黑色的原因。
// global vars : canvas, scroll & scale
let info = document.getElementById("info");
const canvas = document.getElementById('c');
let cw = canvas.width = 350,cx = cw/2;
let ch = canvas.height = 150,cy = 75;
const context = c.getContext('2d');
let scrollX = 0;
let scrollY = 0;
let scale = 1;
let scaleFactor = 0.02;
// clear canvas and draw two boxes
function render(){
//context.clearRect(0, 0, canvas.width/scale, canvas.height/scale);
context.beginPath();
context.rect(100,50,50,50);
context.fillStyle = "red";
context.fill();
context.beginPath();
context.rect(200,50,50,50);
context.fillStyle = "black";
context.fill();
info.innerHTML=`Scroll: ${scrollX},${scrollY} - Scale : ${scale}`
requestAnimationFrame( render );
}
// handlencursor keys to move scroll
window.onkeydown = function(event){
event.preventDefault();
if(event.keyCode == 37) scrollX -=10;
else if(event.keyCode == 39) scrollX +=10;
else if(event.keyCode == 38) scrollY -=10;
else if(event.keyCode == 40) scrollY +=10;
};
// Handl mousenwheel zoom
canvas.onwheel= function(e){
e.preventDefault();
context.clearRect(-cw, -ch, 2 * cw, 2 * ch)
let direction = e.deltaY > 0 ? 1 : -1;
scrollX += Math.round(e.offsetX * scaleFactor * direction);
scrollY += Math.round(e.offsetY * scaleFactor * direction);
scale += scaleFactor * direction;
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(cx, cy);
context.scale(scale, scale);
context.translate(-cx, -cy);
//render()
}
render()
<canvas id="c" width="350" height="150" style="border: 1px solid red;"></canvas>
<div id="info"></div>
我终于明白了... canvas不使用context.translate()
的任意坐标缩放我附上我的解决方案,还有一点好处:canvas 平移(光标键滚动)。 我希望对某人有用。
// initiate variables : canvas ref, offsets, scale...
const context = document.getElementById('c').getContext('2d');
let scale = 1;
let scaleFactor = 0.2;
let scrollX = 0;
let scrollY = 0;
let info = document.getElementById("info");
// Handle mousenwheel zoom
context.canvas.onwheel = function(e){
e.preventDefault();
let previousScale= scale;
// calculate scale direction 6 new scale value
let direction = e.deltaY > 0 ? 1 : -1;
scale += scaleFactor * direction;
// calculate the new scroll values
scrollX += ( e.offsetX / previousScale ) - (e.offsetX / scale);
scrollY += ( e.offsetY / previousScale ) - ( e.offsetY / scale);
// apply new scale in a non acumulative way
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(scale, scale);
}
// clear canvas and draw two boxes
function render(){
context.beginPath();
context.clearRect(0,0,context.canvas.width/scale, context.canvas.height/scale);
context.rect(100-scrollX,50-scrollY,50,50);
context.rect(200-scrollX,50-scrollY,50,50);
context.stroke();
info.innerHTML=`
Scale : ${scale} <br>
Scroll: ${scrollX},${scrollY} <br>
`
requestAnimationFrame( render );
}
// handlencursor keys to move scroll
window.onkeydown = function(event){
event.preventDefault();
if(event.keyCode == 37) scrollX -=10;
else if(event.keyCode == 39) scrollX +=10;
else if(event.keyCode == 38) scrollY -=10;
else if(event.keyCode == 40) scrollY +=10;
};
context.canvas.focus()
render()
<canvas id="c" width="400" height="150" style="border: 1px solid red;" tabindex="1"></canvas>
<div id="info"></div>