javascript - p5js - 在平移/缩放中钳制图像
问题描述
使用 p5js,我正在开发一个平移/缩放功能,它允许您平移/缩放图像,然后钳住图像的边缘。我遇到的主要问题是夹紧图像的边缘,因此您永远不能将图像拖过容器的边缘。例如:
注意未夹紧图像中的黑色背景。当我拖动图像时,它绝不应该允许我将图像角拖过画布边缘。
以下是我目前处理各种事件和 p5js 设置的方式:
/* eslint-disable no-undef, no-unused-vars */
var img;
var w, h, currentImageWidth, currentImageHeight;
var x, y, tox, toy;
var zoom = 0.01; //zoom step per mouse tick
function preload() {
img = loadImage("https://i.imgur.com/MBFJhju.jpeg", () => {});
}
function setup() {
createCanvas(600, 600);
w = currentImageWidth = 600;
h = currentImageHeight = 600;
x = tox = w / 2;
y = toy = h / 2;
}
function draw() {
background(0);
//tween/smooth motion
x = lerp(x, tox, 0.1);
y = lerp(y, toy, 0.1);
w = lerp(w, currentImageWidth, 0.1);
h = lerp(h, currentImageHeight, 0.1);
image(img, x - w / 2, y - h / 2, w, h);
}
function mouseDragged() {
let maxX = currentImageWidth;
let minX = -1 * maxX;
let maxY = currentImageHeight;
let minY = -1 * maxY;
let nextXposition = tox + mouseX - pmouseX;
let nextYposition = toy + mouseY - pmouseY;
if (
nextXposition - currentImageWidth * 0.5 < maxX &&
nextXposition - currentImageWidth * 0.5 > minX
) {
tox += mouseX - pmouseX;
}
if (
nextYposition - currentImageHeight * 0.5 < maxY &&
nextYposition - currentImageHeight * 0.5 > minY
) {
toy += mouseY - pmouseY;
}
}
function mouseWheel(event) {
var e = event.wheelDeltaY;
console.log(event);
if (e > 0) {
//zoom in
for (let i = 0; i < e; i++) {
if (currentImageWidth > 3 * width) return; //max zoom
tox -= zoom * (mouseX - tox);
toy -= zoom * (mouseY - toy);
currentImageWidth *= zoom + 1;
currentImageHeight *= zoom + 1;
}
}
if (e < 0) {
//zoom out
for (let i = 0; i < -e; i++) {
if (currentImageWidth < width) return; //min zoom
tox += (zoom / (zoom + 1)) * (mouseX - tox);
toy += (zoom / (zoom + 1)) * (mouseY - toy);
currentImageHeight /= zoom + 1;
currentImageWidth /= zoom + 1;
}
}
//adjust x and y if out of bounds
let maxX = width * 0.5;
let minX = -1 * maxX;
let maxY = height * 0.5;
let minY = -1 * maxY;
let diff = 0;
if (currentImageWidth + currentImageWidth * 0.5 <= maxX) {
diff = maxX - (tox + currentImageWidth * 0.5);
tox += diff;
}
if (currentImageWidth - currentImageWidth * 0.5 >= minX) {
diff = currentImageWidth - currentImageWidth * 0.5 - minX;
tox -= diff;
}
if (toy + currentImageHeight * 0.5 <= maxY) {
diff = maxY - (toy + currentImageHeight * 0.5);
toy += diff;
}
if (toy - currentImageHeight * 0.5 >= minY) {
diff = toy - currentImageHeight * 0.5 - minY;
toy -= diff;
}
return false;
}
目前,夹子实际上不起作用。但是您可以拖动图像并缩放。我的意图是让它像在游戏中的地图上平移/缩放一样工作。
我相信主要的痛点是mouseDragged事件处理程序,我认为我将使用mouseWheel事件处理程序处理钳位的方式将适用于缩放事件。
如果您需要任何其他信息,请告诉我!
完整演示:
https://codesandbox.io/embed/great-dirac-yvd0s?fontsize=14&hidenavigation=1&theme=dark
解决方案
我最近在 processing.org 论坛上回答了一个类似的问题。
- 为了保证图像的左边缘不比视图区域的左边缘更靠右,显示图像的x位置不能大于图像宽度除以2
- 为了保证图像的右边缘不比视图区域的右边缘更左,图像显示的x位置不能小于视图区域的宽度减去视图区域宽度的一半。图片。
- 纵轴的逻辑是一样的。图像的 y 位置必须介于视图高度减去图像高度的一半和图像宽度的一半之间。
var img;
var w, h, currentImageWidth, currentImageHeight;
var x, y, tox, toy;
var zoom = 0.01; //zoom step per mouse tick
function preload() {
img = loadImage("https://i.imgur.com/MBFJhju.jpeg");
}
function setup() {
createCanvas(300, 300);
w = currentImageWidth = 300;
h = currentImageHeight = 300;
x = tox = w / 2;
y = toy = h / 2;
}
function draw() {
background(0);
//tween/smooth motion
x = lerp(x, tox, 0.1);
y = lerp(y, toy, 0.1);
w = lerp(w, currentImageWidth, 0.1);
h = lerp(h, currentImageHeight, 0.1);
image(img, x - w / 2, y - h / 2, w, h);
}
function mouseDragged() {
let maxX = currentImageWidth / 2;
let minX = width - maxX;
let maxY = currentImageHeight / 2;
let minY = height - maxY;
console.log(JSON.stringify({minX, maxX,minY,maxY}));
tox = constrain(tox + mouseX - pmouseX, minX, maxX);
toy = constrain(toy + mouseY - pmouseY, minY, maxY);
}
function mouseWheel(event) {
var delta = event.wheelDeltaY;
// console.log(event);
// TODO: figure out where on the image the mouse cursor is
// Figure how how much that point will shift based on the scale
// Adjust the tox and toy to compensate (thus keeping the part of the image where the mouse is stationary.
currentImageWidth *= delta * zoom + 1;
currentImageHeight *= delta * zoom + 1;
// Check constraints
if (delta > 0) {
//zoom in
if (currentImageWidth > 3 * width) {
currentImageWidth = 3 * width;
currentImageHeight = 3 * height;
//max zoom
}
} else if (delta < 0) {
//zoom out
if (currentImageWidth < width) {
//min zoom
currentImageWidth = width;
currentImageHeight = height;
}
}
//adjust x and y if out of bounds
let maxX = currentImageWidth / 2;
let minX = width - maxX;
let maxY = currentImageHeight / 2;
let minY = height - maxY;
tox = constrain(tox, minX, maxX);
toy = constrain(toy, minY, maxY);
return false;
}
html,
body {
height: 100%;
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
推荐阅读
- c++ - 使用 FreeBSD 作为远程主机的 CLion 完全远程模式
- c# - 如何使用 Roslyn 在 C# 中忽略 Property Getter 和 Setter
- python - 无法添加到 lambda Python 3.6
- python - 我想预测新事件的更新次数?如何在python中做到这一点?
- typescript - 与 Strophe.js 断开连接
- python - 如何通过 odoo 10 中的 cron 作业计算天数?
- php - 太多 Ifs 来检查变量确实包含有效的 4 位数年份
- python - 有人可以建议气流 python3 的替代 HdfsSensor 吗?
- websphere - IBM Liberty 使用故障转移的消息消费
- javascript - 使用 javascript 创建自定义键盘快捷键