export default class ZoomController {
constructor(wrapper, target, callback) {
this.scale = 1;
this.callback = callback;
this.translateX = 0;
this.translateY = 0;
this.isDragging = false;
this.startX = 0;
this.startY = 0;
this.target = target;
this.wrapper = wrapper;
// 绑定事件上下文
this.handleWheel = this.handleWheel.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.initEventListeners();
}
initEventListeners() {
// 鼠标滚轮事件
this.wrapper.addEventListener("wheel", this.handleWheel);
// 鼠标事件
this.wrapper.addEventListener("mousedown", this.handleMouseDown);
this.wrapper.addEventListener("mousemove", this.handleMouseMove);
document.body.addEventListener("mouseup", this.handleMouseUp);
}
removeEventListeners() {
this.wrapper.removeEventListener("wheel", this.handleWheel);
this.wrapper.removeEventListener("mousedown", this.handleMouseDown);
this.wrapper.removeEventListener("mousemove", this.handleMouseMove);
document.body.removeEventListener("mouseup", this.handleMouseUp);
}
handleWheel(event) {
event.preventDefault();
const rect = this.target.getBoundingClientRect();
const offsetX = event.clientX - rect.left;
const offsetY = event.clientY - rect.top;
this.wheelZoom({
scaleFactor: event.deltaY,
originX: offsetX / rect.width,
originY: offsetY / rect.height
});
}
handleMouseDown(event) {
this.isDragging = true;
this.startX = event.clientX - this.translateX;
this.startY = event.clientY - this.translateY;
this.target.style.cursor = "grabbing";
}
handleMouseMove(event) {
if (!this.isDragging) return;
this.translateX = event.clientX - this.startX;
this.translateY = event.clientY - this.startY;
this.updateTransform();
}
handleMouseUp() {
this.isDragging = false;
this.target.style.cursor = "grab";
}
reset() {
this.scale = 1;
this.translateX = 0;
this.translateY = 0;
this.isDragging = false;
this.startX = 0;
this.startY = 0;
this.target.style.transform = "translate3d(0px, 0px, 0px) scale(1)";
}
updateTransform() {
this.target.style.transform =
`translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`;
}
wheelZoom({ scaleFactor, originX = 0.5, originY = 0.5 }) {
let ratio = 1.1;
if (scaleFactor > 0) ratio = 1 / ratio;
const rect = this.target.getBoundingClientRect();
const newScale = Math.max(0.5, Math.min(this.scale * ratio, 5));
const deltaScale = newScale / this.scale;
this.translateX -= (originX - 0.5) * rect.width * (deltaScale - 1);
this.translateY -= (originY - 0.5) * rect.height * (deltaScale - 1);
this.scale = newScale;
this.callback?.(+(this.scale * 100).toFixed(0));
this.updateTransform();
}
destroy() {
this.removeEventListeners();
this.reset();
}
}
使用方式
let wrapper = document.getElementById()
let content = document.getElementById()
this.zoomController = new ZoomController(
wrapper,
content,
(percent) => {
console.log("scale", percent)
}
)