【问题标题】:Create Zoom effect with p5.js使用 p5.js 创建缩放效果
【发布时间】:2019-07-21 08:55:26
【问题描述】:

我知道这个问题已经被问过好几次了,但我找到的答案都没有对我有用。我需要允许用户缩放到目前为止有效的图像,这只是一个scale(factor) 调用,但现在我想通过鼠标指针进行缩放。这证明更困难,因为我可以在指针效果上创建放大,但是当鼠标移动时,图像也会移动。从这个演示中可以看出:

https://editor.p5js.org/J-Cake/sketches/1r1wmWO60

我想我会将第二个平移的坐标乘以比例因子,但这似乎也无济于事。我错过了什么?

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.com/ajax/libs/p5.js/0.9.0/p5.js"></script>

【问题讨论】:

  • @Rabbid76 我提供的示例允许您缩放图像,如果在缩放时移动鼠标,则整个物体都会移动。
  • 轮子变化导致秤更新。 p5 负责更新。

标签: javascript canvas processing p5.js


【解决方案1】:

问题是您必须逐步应用比例。

从中心点(x1y1)出发的单个比例(s1)可以通过以下方式计算:

model = translate(x1, y1) * scale(s1) * translate(-x1, -y1) 

但如果您想在中心(x2y2)周围应用新的比例(s2),那么这是:

model = translate(x2, y2) * scale(s2) * translate(-x2, -y2) * currentMode;

其中currentMode 是之前的(缩放)转换。
等同于:

model = translate(x1+x2, y1+y2) * scale(s1*s2) * translate(-(x1+x2), -(y1+y2))

距离中心(mxmy)的单个比例(sf)可以通过以下方式计算:

let tx = mx - sf * mx;
let ty = my - sf * my;
translate(tx, ty);
scale(sf);

要连续执行更多此类操作,我建议实现 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;
}

距离中心的比例可以用下面的 3x3 矩阵表示:

m = [ sf, 0,  0, 
      0,  sf, 0,
      tx, ty, 1];

这会导致以下鼠标滚轮事件:

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];
} );

在这种情况下可以简化:

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;
} );

参见示例。矩形可以通过鼠标滚轮或 +/- 键从鼠标光标位置缩放:

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);
    } 
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"&gt;&lt;/script&gt;

【讨论】:

  • 我不完全理解矩阵操作在哪里出现,或者您所说的增量是什么意思,因为 p5 在每个绘制周期后都会重置变换。
  • @JacobSchneider "incrementally" 在这种情况下意味着每个新的比例都依赖于所有以前的比例。 p5.j​​s 隐藏了矩阵乘法。 transformscale 等操作设置一个矩阵并将当前矩阵乘以新矩阵。但是在这种情况下必须要做的是将新矩阵乘以当前矩阵,这是现有操作无法做到的。
猜你喜欢
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多