一、鼠标滚轮缩放的中心点设置为当前鼠标中心点 - 要点分析
鼠标指针指向界面中的 Canvas 画布某个位置 , Canvas 画布中绘制着一张超大图片 , 以该位置为中心 , 滑动鼠标滚轮时进行缩放 ;
使用鼠标滚轮缩放后 , 在 Canvas 中绘制的图片的尺寸肯定是放大或者缩小了 , 尺寸发生了改变 ;
图片缩放时 , 鼠标指针指向一个位置 , 该位置对应着一个当前 Canvas 画布中的 x, y 坐标 , 同时可以计算出当前位置对应的图片中的 水平方向的比例 和 垂直方向的比例 ;
在缩放后的图片中 , 只要保证鼠标指针指向相同的 x, y 坐标时 , 该位置对应的 水平方向的比例 和 垂直方向的比例 仍然保持不变 , 那就需要移动图片的位置 ;
- 如果放大图片就需要将图片往左上方移动 ;
- 如果缩小图片就需要将图片往右下方移动 ;
此时可以分析出 , 如果要实现 鼠标滚轮缩放的中心点设置为当前鼠标中心点 , 需要进行下面两个步骤的操作 :
- 保存当前鼠标指针指向的位置 , 以及鼠标指针指向位置对应图片中坐标位置的比例 ;
- 鼠标指针指向的位置不变 , 指向图片坐标比例不变 , 图片尺寸发生了改变 , 重新计算当前图片的放置位置 , 并设置图片位置 ;
这样图片缩放时 , 始终可以保证鼠标指向的部位保持位置不变 ;
1、保存当前鼠标指针指向的位置
首先 , 在类中定义如下成员字段 ,
- pointer_x 和 pointer_y 记录的是鼠标指针指向的界面中 Camvas 画布中的坐标位置 ;
- pointer_ratio_x 和 pointer_ratio_y 记录的是 鼠标指针指向位置对应图片中坐标位置的比例 ;
public double pointer_ratio_x;
public double pointer_ratio_y;
public int pointer_x;
public int pointer_y;
然后 , 在鼠标缩放之前 , 保存当前的鼠标位置及比例 ;
- 在鼠标滚轮事件 MouseWheelEvent 中 , 可以直接通过调用
e.getX(), e.getY()
获取到当前 鼠标指针 在 Canvas 画布的坐标 ; - 根据该 Canvas 中的坐标 , 以及画布的偏移 , 可以计算出该坐标对应图片中的坐标位置 ;
// 计算画布
double canvasX = x - offsetX;
double canvasY = y - offsetY;
- 计算出当前的图片大小 ;
// 计算图片大小
double imageWidth = image.getWidth(null) * scale; // 缩放后的图像宽度
double imageHeight = image.getHeight(null) * scale; // 缩放后的图像高度
- 有了鼠标指针在图片中的位置 , 图片的尺寸 , 就可以计算出鼠标指针在图片中的比例 ;
// 计算比例
pointer_ratio_x = canvasX / imageWidth ;
pointer_ratio_y = canvasY / imageHeight ;
完整代码示例 :
代码语言:javascript复制 /**
* 记录滚轮缩放时鼠标指针状态
*/
public void save(int x, int y){
// 记录鼠标坐标
pointer_x = x;
pointer_y = y;
// 计算画布
double canvasX = x - offsetX;
double canvasY = y - offsetY;
// 计算图片大小
double imageWidth = image.getWidth(null) * scale; // 缩放后的图像宽度
double imageHeight = image.getHeight(null) * scale; // 缩放后的图像高度
// 计算比例
pointer_ratio_x = canvasX / imageWidth ;
pointer_ratio_y = canvasY / imageHeight ;
}
2、根据鼠标指针指向的位置以及比例重新计算图片位置
在鼠标滚轮缩放完成后 , 再根据鼠标指针指向的位置和比例 , 结合图片缩放后的尺寸 , 重新计算画布偏移的位置 , 以达到鼠标指向的图片元素位置基本保持不变的目的 ;
代码语言:javascript复制 /**
* 计算新的比例
*/
public void restore(){
// 缩放后的尺寸
double imageWidth = image.getWidth(null) * scale; // 缩放后的图像宽度
double imageHeight = image.getHeight(null) * scale; // 缩放后的图像高度
// 计算整张画布宽度
double canvasX = imageWidth * pointer_ratio_x;
double canvasY = imageHeight * pointer_ratio_y;
// 计算画布偏移
offsetX = (int) (pointer_x - canvasX);
offsetY = (int) (pointer_y - canvasY);
}
二、绘制超大图像 鼠标拖动 鼠标滚轮缩放 以当前鼠标指针位置为缩放中心 示例
1、代码示例
代码语言:javascript复制import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
public class LargeCanvas extends JPanel {
// 鼠标按下时的坐标 以及 更新后的坐标
private int startX, startY;
// 当前的位置偏移
private int offsetX = 0, offsetY = 0;
// 缩放比例,默认为 1.0
private double scale = 1.0;
private Image image;
public double pointer_ratio_x;
public double pointer_ratio_y;
public int pointer_x;
public int pointer_y;
public LargeCanvas() {
// 画布大小设置为 800 x 600
// 绘制的图片是 2K 大小的图片
setPreferredSize(new Dimension(800, 600));
// 添加鼠标滚轮监听器
addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
// 保存当前的鼠标位置及比例
save(e.getX(), e.getY());
int notches = e.getWheelRotation();
if (notches < 0) {
// 滚轮向上,放大画布
scale *= 1.1;
} else {
// 滚轮向下,缩小画布
scale /= 1.1;
}
// 基于鼠标位置和比例, 计算最新的偏移
restore();
repaint(); // 重新绘制画布
}
});
// 为组件设置鼠标监听事件
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// 记录鼠标按下时的坐标
startX = e.getX();
startY = e.getY();
}
});
// 添加鼠标动作监听
addMouseMotionListener(new MouseAdapter() {
// 鼠标拖动事件
public void mouseDragged(MouseEvent e) {
// 统计本次鼠标移动的相对值
int dx = e.getX() - startX;
int dy = e.getY() - startY;
// 偏移量累加
offsetX = dx;
offsetY = dy;
// 重新绘图
repaint();
// 记录当前拖动后的位置
startX = dx;
startY = dy;
}
});
}
/**
* 记录滚轮缩放时鼠标指针状态
*/
public void save(int x, int y){
// 记录鼠标坐标
pointer_x = x;
pointer_y = y;
// 计算画布
double canvasX = x - offsetX;
double canvasY = y - offsetY;
// 计算图片大小
double imageWidth = image.getWidth(null) * scale; // 缩放后的图像宽度
double imageHeight = image.getHeight(null) * scale; // 缩放后的图像高度
// 计算比例
pointer_ratio_x = canvasX / imageWidth ;
pointer_ratio_y = canvasY / imageHeight ;
}
/**
* 计算新的比例
*/
public void restore(){
// 缩放后的尺寸
double imageWidth = image.getWidth(null) * scale; // 缩放后的图像宽度
double imageHeight = image.getHeight(null) * scale; // 缩放后的图像高度
// 计算整张画布宽度
double canvasX = imageWidth * pointer_ratio_x;
double canvasY = imageHeight * pointer_ratio_y;
// 计算画布偏移
offsetX = (int) (pointer_x - canvasX);
offsetY = (int) (pointer_y - canvasY);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// 画布进行整体偏移
Graphics2D g2 = (Graphics2D)g;
// 缩放画布
//g2.scale(scale, scale);
// 拖动画布
g2.translate(offsetX, offsetY);
// 获取图片
this.image = Toolkit.getDefaultToolkit().getImage("image.jpg");
// 绘制图形
//g2.drawImage(image, 0, 0, this);
// 绘制图像
int imageWidth = (int) (image.getWidth(null) * scale); // 缩放后的图像宽度
int imageHeight = (int) (image.getHeight(null) * scale); // 缩放后的图像高度
g2.drawImage(image, 0, 0, imageWidth, imageHeight, null);
}
public static void main(String[] args) {
// 创建 JFrame 窗口
JFrame frame = new JFrame("Large Canvas");
// 设置窗口关闭行为 点击右上角关闭按钮 关闭窗口并退出应用
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建画布
LargeCanvas canvas = new LargeCanvas();
// 将画布放入滚动布局
JScrollPane scrollPane = new JScrollPane(canvas);
// 将滚动布局放入窗口
frame.getContentPane().add(scrollPane);
// 窗口自适应
frame.pack();
// 窗口设置可见
frame.setVisible(true);
}
}
2、执行效果
执行后 , 将图像中船头的 H 标识放置在界面中心 ;
将鼠标指针放在 H 位置 , 缩放 , 发现此时缩放 , 就是以当前鼠标指针为中心进行的缩放 ;