注意:
1、组件支持横屏,此横屏时手机的自适应横屏,是竖屏顺时针旋转90度的横屏;
2、组件支持设置svg触摸开始时的回调方法;
3、组件支持设置svg缩放比例变化时的回调方法;
/**
* @author: yiwenli
* @desc: svg移动缩放
* @date: 2023/8/15
*/
class EwlPanZoom {
/**
* 构造器
*
* @param {Element} svgElement svg元素
* @param {Object} panZoomConfig 移动缩放配置
*/
constructor(svgElement, panZoomConfig = {}) {
// 1、属性和变量初始化
// svg元素
this.svgElement = svgElement;
// viewBox初始信息
const { width, height } = this.svgElement.viewBox.animVal;
this.viewBoxInitWidth = parseFloat(width);
this.viewBoxInitHeight = parseFloat(height);
// viewBox当前信息
this.viewBoxCurrentX = '';
this.viewBoxCurrentY = '';
this.viewBoxCurrentWidth = '';
this.viewBoxCurrentHeight = '';
// 是否是移动状态
this.isMoveStatus = false;
// 移动开始坐标
this.startX = '';
this.startY = '';
// 缩放开始时两手指的距离
this.startDistance = '';
// 是否横屏 横屏认为是顺时针旋转90度(默认非横屏)
this.isHorizontal = panZoomConfig.isHorizontal || false;
// 2、添加回调函数属性
// 缩放倍数修改回调函数
this.onZoomChange = panZoomConfig.onZoomChange;
// 触摸开始回调函数
this.onTouchStart = panZoomConfig.onTouchStart;
// 3、执行初始化
this.init();
}
/**
* 初始化
*/
init() {
this.svgElement.addEventListener('touchstart', this.touchStart.bind(this), {
passive: false
});
this.svgElement.addEventListener('touchmove', this.touchMove.bind(this), {
passive: false
});
}
/**
* 触摸开始事件
*
* @param {Event} evt 事件对象
*/
touchStart(evt) {
// 阻止浏览器的默认行为
evt.preventDefault();
if (typeof this.onTouchStart === 'function') {
// 调用回调函数
this.onTouchStart();
}
// 获取当前viewBox位置信息
const viewBox = this.svgElement.viewBox.animVal;
this.viewBoxCurrentX = parseFloat(viewBox.x);
this.viewBoxCurrentY = parseFloat(viewBox.y);
this.viewBoxCurrentWidth = parseFloat(viewBox.width);
this.viewBoxCurrentHeight = parseFloat(viewBox.height);
// 记录手指按下的位置
if (this.isHorizontal) {
this.startX = evt.touches[0].clientY;
this.startY = this.viewBoxCurrentHeight - evt.touches[0].clientX;
} else {
this.startX = evt.touches[0].clientX;
this.startY = evt.touches[0].clientY;
}
// 标记为正在移动
this.isMoveStatus = true;
if (evt.touches.length === 2) {
// 双指
// 计算移动前两手指之间的距离,勾股定理
const start = evt.touches;
const startDistanceX = start[0].clientX - start[1].clientX;
const startDistanceY = start[0].clientY - start[1].clientY;
this.startDistance = Math.sqrt(startDistanceX ** 2 + startDistanceY ** 2);
}
}
/**
* 触摸移动事件
*
* @param {Event} evt 事件对象
*/
touchMove(evt) {
if (evt.touches.length === 1) {
// 单指触摸
if (this.isMoveStatus) {
// 获取当前视窗宽度高度
const screenWidth = document.body.clientWidth;
const screenHeight = document.body.clientHeight;
// 计算分辨率
const productX = (this.viewBoxCurrentWidth / screenWidth).toFixed(2);
const productY = (this.viewBoxCurrentHeight / screenHeight).toFixed(2);
// 获取当前手指位置
let endX, endY;
if (this.isHorizontal) {
endX = evt.touches[0].clientY;
endY = this.viewBoxCurrentHeight - evt.touches[0].clientX;
} else {
endX = evt.touches[0].clientX;
endY = evt.touches[0].clientY;
}
// 计算移动差值
const moveX = (endX - this.startX);
const moveY = (endY - this.startY);
// 计算viewBox移动后的位置
const viewBoxMoveX = this.viewBoxCurrentX - (moveX * productX);
const viewBoxMoveY = this.viewBoxCurrentY - (moveY * productX);
// 修改viewBox属性
this.svgElement.setAttribute('viewBox',
`${viewBoxMoveX} ${viewBoxMoveY } ${this.viewBoxCurrentWidth} ${this.viewBoxCurrentHeight}`);
}
} else if (evt.touches.length === 2) {
// 双指触摸
// 防止触发单指触摸事件
this.isMoveStatus = false;
// 计算移动后两手指之间的距离,勾股定理
const end = evt.touches;
const endDistanceX = end[0].clientX - end[1].clientX;
const endDistanceY = end[0].clientY - end[1].clientY;
const endDistance = Math.sqrt(endDistanceX ** 2 + endDistanceY ** 2);
// 计算移动前后距离比值,即为放大倍数
const zoom = endDistance / this.startDistance;
// 计算viewBox缩放后的宽高
const viewBoxScaleWidth = this.viewBoxCurrentWidth / zoom;
const viewBoxScaleHeight = this.viewBoxCurrentHeight / zoom;
// 计算viewBox偏移量
const offSetX = (this.viewBoxCurrentWidth - viewBoxScaleWidth) / 2.0;
const offSetY = (this.viewBoxCurrentHeight - viewBoxScaleHeight) / 2.0;
// 修改viewBox属性
this.svgElement.setAttribute('viewBox',
`${parseFloat(this.viewBoxCurrentX + offSetX)} ${parseFloat(this.viewBoxCurrentY + offSetY)} ${viewBoxScaleWidth} ${viewBoxScaleHeight}`
);
// 相对于初始时的缩放比例
const viewBoxZoom = this.viewBoxInitWidth / viewBoxScaleWidth;
if (typeof this.onZoomChange === 'function') {
// 调用回调函数传递当前缩放倍数
this.onZoomChange(viewBoxZoom);
}
}
}
}
export default EwlPanZoom