I know this question has been asked several times, but none of the answers I found worked for me. I need to allow the user to scale the image which works so far, it's simply a scale(factor)
call but now I want to scale by the mouse pointer. This proves more difficult as I can create the zoom in on the pointer effect but when the mouse moves, so does the image. as can be seen in this demo:
I figured i would multiply the second translation's coordinates by the scale factor but that also doesn't seem to do anything. What am I missing?
let sf = 1; // scaleFactor
let x = 0; // pan X
let y = 0; // pan Y
let mx, my; // mouse coords;
function setup() {
createCanvas(400, 400);
}
function draw() {
mx = mouseX;
my = mouseY;
background(255);
translate(mx, my);
scale(sf);
translate(-mx, -my);
translate();
rect(100, 100, 100, 100);
if (mouseIsPressed) {
x -= pmouseX - mouseX;
y -= pmouseY - mouseY;
}
}
window.addEventListener("wheel", function(e) {
if (e.deltaY > 0)
sf *= 1.05;
else
sf *= 0.95;
});
<script src=".js/0.9.0/p5.js"></script>
I know this question has been asked several times, but none of the answers I found worked for me. I need to allow the user to scale the image which works so far, it's simply a scale(factor)
call but now I want to scale by the mouse pointer. This proves more difficult as I can create the zoom in on the pointer effect but when the mouse moves, so does the image. as can be seen in this demo:
https://editor.p5js/J-Cake/sketches/1r1wmWO60
I figured i would multiply the second translation's coordinates by the scale factor but that also doesn't seem to do anything. What am I missing?
let sf = 1; // scaleFactor
let x = 0; // pan X
let y = 0; // pan Y
let mx, my; // mouse coords;
function setup() {
createCanvas(400, 400);
}
function draw() {
mx = mouseX;
my = mouseY;
background(255);
translate(mx, my);
scale(sf);
translate(-mx, -my);
translate();
rect(100, 100, 100, 100);
if (mouseIsPressed) {
x -= pmouseX - mouseX;
y -= pmouseY - mouseY;
}
}
window.addEventListener("wheel", function(e) {
if (e.deltaY > 0)
sf *= 1.05;
else
sf *= 0.95;
});
<script src="https://cdnjs.cloudflare./ajax/libs/p5.js/0.9.0/p5.js"></script>
Share
Improve this question
edited Jul 21, 2019 at 17:08
Rabbid76
211k30 gold badges157 silver badges200 bronze badges
asked Jul 21, 2019 at 8:55
J-CakeJ-Cake
1,6381 gold badge19 silver badges38 bronze badges
3
- This might help you stackoverflow./questions/49245168/… – Nenad Vracar Commented Jul 21, 2019 at 9:03
- @Rabbid76 the example I provided allows you to scale the image, if you move the mouse while it is scaled, the whole thing moves. – J-Cake Commented Jul 21, 2019 at 9:04
- the wheel change causes the scale to update. p5 takes care of the updating. – J-Cake Commented Jul 21, 2019 at 9:10
1 Answer
Reset to default 10The issue is that you've to apply the scale incrementally.
A single scale (s1
) from a center point (x1
, y1
) can be calculated by:
model = translate(x1, y1) * scale(s1) * translate(-x1, -y1)
But if you want to apply an new scale (s2
) around the center (x2
, y2
), then this is:
model = translate(x2, y2) * scale(s2) * translate(-x2, -y2) * currentMode;
where currentMode
is the previous (scale) transformation.
This is not the same as:
model = translate(x1+x2, y1+y2) * scale(s1*s2) * translate(-(x1+x2), -(y1+y2))
A single scale (sf
) from the center (mx
, my
) can be calcualted by:
let tx = mx - sf * mx;
let ty = my - sf * my;
translate(tx, ty);
scale(sf);
To do more of this operations consecutively, I remend to implement a 3x3 Matrix multiplication:
function matMult3x3(A, B) {
C = [0, 0, 0, 0, 0, 0];
for (let k = 0; k < 3; ++ k) {
for (let j = 0; j < 3; ++ j) {
C[k*3+j] = A[0*3+j] * B[k*3+0] + A[1*3+j] * B[k*3+1] + A[2*3+j] * B[k*3+2];
}
}
return C;
}
The scale from the center can be expressed by the following 3x3 matrix:
m = [ sf, 0, 0,
0, sf, 0,
tx, ty, 1];
This leads to the following mouse wheel event:
window.addEventListener("wheel", function(e) {
let mx = mouseX;
let my = mouseY;
let s = e.deltaY > 0 ? 1.05 : 0.95;
let x = mx - s * mx;
let y = my - s * my;
m = matMult3x3([s,0,0, 0,s,0, x,y,1], [sf,0,0, 0,sf,0, tx,ty,1]);
sf = m[0];
tx = m[6];
ty = m[7];
} );
In this case this can be simplified:
window.addEventListener("wheel", function(e) {
let mx = mouseX;
let my = mouseY;
let s = e.deltaY > 0 ? 1.05 : 0.95;
sf = sf * s;
tx = mx - s * mx + s * tx;
ty = my - s * my + s * ty;
} );
See the example. The rectangle can be scaled from the mouse cursor position either by the mouse wheel or the +/- keys:
let sf = 1, tx = 0, ty = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(127);
translate(tx, ty);
scale(sf);
rect(100, 100, 100, 100);
}
function applyScale(s) {
sf = sf * s;
tx = mouseX * (1-s) + tx * s;
ty = mouseY * (1-s) + ty * s;
}
window.addEventListener("wheel", function(e) {
applyScale(e.deltaY > 0 ? 1.05 : 0.95);
} );
function keyPressed() {
if (key == '-') {
applyScale(0.95);
} else if (key == '+') {
applyScale(1.05);
}
}
<script src="https://cdnjs.cloudflare./ajax/libs/p5.js/0.9.0/p5.js"></script>