mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-22 10:57:40 +08:00
194 lines
5.6 KiB
JavaScript
194 lines
5.6 KiB
JavaScript
import { getTwoPointDistance } from '../utils'
|
|
|
|
// 手势事件支持插件
|
|
class TouchEvent {
|
|
// 构造函数
|
|
constructor({ mindMap }) {
|
|
this.mindMap = mindMap
|
|
this.touchesNum = 0
|
|
this.singleTouchstartEvent = null
|
|
this.clickNum = 0
|
|
this.touchStartScaleView = null
|
|
this.lastTouchStartPosition = null
|
|
this.lastTouchStartDistance = 0
|
|
this.bindEvent()
|
|
}
|
|
|
|
// 绑定事件
|
|
bindEvent() {
|
|
this.onTouchstart = this.onTouchstart.bind(this)
|
|
this.onTouchmove = this.onTouchmove.bind(this)
|
|
this.onTouchcancel = this.onTouchcancel.bind(this)
|
|
this.onTouchend = this.onTouchend.bind(this)
|
|
window.addEventListener('touchstart', this.onTouchstart, { passive: false })
|
|
window.addEventListener('touchmove', this.onTouchmove, { passive: false })
|
|
window.addEventListener('touchcancel', this.onTouchcancel, {
|
|
passive: false
|
|
})
|
|
window.addEventListener('touchend', this.onTouchend, { passive: false })
|
|
}
|
|
|
|
// 解绑事件
|
|
unBindEvent() {
|
|
window.removeEventListener('touchstart', this.onTouchstart)
|
|
window.removeEventListener('touchmove', this.onTouchmove)
|
|
window.removeEventListener('touchcancel', this.onTouchcancel)
|
|
window.removeEventListener('touchend', this.onTouchend)
|
|
}
|
|
|
|
// 手指按下事件
|
|
onTouchstart(e) {
|
|
this.touchesNum = e.touches.length
|
|
this.touchStartScaleView = null
|
|
if (this.touchesNum === 1) {
|
|
let touch = e.touches[0]
|
|
if (this.lastTouchStartPosition) {
|
|
this.lastTouchStartDistance = getTwoPointDistance(
|
|
this.lastTouchStartPosition.x,
|
|
this.lastTouchStartPosition.y,
|
|
touch.clientX,
|
|
touch.clientY
|
|
)
|
|
}
|
|
this.lastTouchStartPosition = {
|
|
x: touch.clientX,
|
|
y: touch.clientY
|
|
}
|
|
this.singleTouchstartEvent = touch
|
|
this.dispatchMouseEvent('mousedown', touch.target, touch)
|
|
}
|
|
}
|
|
|
|
// 手指移动事件
|
|
onTouchmove(e) {
|
|
let len = e.touches.length
|
|
if (len === 1) {
|
|
let touch = e.touches[0]
|
|
this.dispatchMouseEvent('mousemove', touch.target, touch)
|
|
} else if (len === 2) {
|
|
let { disableTouchZoom, minTouchZoomScale, maxTouchZoomScale } =
|
|
this.mindMap.opt
|
|
if (disableTouchZoom) return
|
|
minTouchZoomScale =
|
|
minTouchZoomScale === -1 ? -Infinity : minTouchZoomScale / 100
|
|
maxTouchZoomScale =
|
|
maxTouchZoomScale === -1 ? Infinity : maxTouchZoomScale / 100
|
|
let touch1 = e.touches[0]
|
|
let touch2 = e.touches[1]
|
|
let ox = touch1.clientX - touch2.clientX
|
|
let oy = touch1.clientY - touch2.clientY
|
|
let distance = Math.sqrt(Math.pow(ox, 2) + Math.pow(oy, 2))
|
|
// 以两指中心点进行缩放
|
|
let { x: touch1ClientX, y: touch1ClientY } = this.mindMap.toPos(
|
|
touch1.clientX,
|
|
touch1.clientY
|
|
)
|
|
let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(
|
|
touch2.clientX,
|
|
touch2.clientY
|
|
)
|
|
let cx = (touch1ClientX + touch2ClientX) / 2
|
|
let cy = (touch1ClientY + touch2ClientY) / 2
|
|
// 手势缩放,基于最开始的位置进行缩放(基于前一个位置缩放不是线性关系); 缩放同时支持位置拖动
|
|
const view = this.mindMap.view
|
|
if (!this.touchStartScaleView) {
|
|
this.touchStartScaleView = {
|
|
distance: distance,
|
|
scale: view.scale,
|
|
x: view.x,
|
|
y: view.y,
|
|
cx: cx,
|
|
cy: cy
|
|
}
|
|
return
|
|
}
|
|
const viewBefore = this.touchStartScaleView
|
|
let scale = viewBefore.scale * (distance / viewBefore.distance)
|
|
if (Math.abs(distance - viewBefore.distance) <= 10) {
|
|
scale = viewBefore.scale
|
|
}
|
|
scale =
|
|
scale < minTouchZoomScale
|
|
? minTouchZoomScale
|
|
: scale > maxTouchZoomScale
|
|
? maxTouchZoomScale
|
|
: scale
|
|
const ratio = 1 - scale / viewBefore.scale
|
|
view.scale = scale
|
|
view.x =
|
|
viewBefore.x +
|
|
(cx - viewBefore.x) * ratio +
|
|
(cx - viewBefore.cx) * scale
|
|
view.y =
|
|
viewBefore.y +
|
|
(cy - viewBefore.y) * ratio +
|
|
(cy - viewBefore.cy) * scale
|
|
view.transform()
|
|
this.mindMap.emit('scale', scale)
|
|
}
|
|
}
|
|
|
|
// 手指取消事件
|
|
onTouchcancel(e) {}
|
|
|
|
// 手指松开事件
|
|
onTouchend(e) {
|
|
this.dispatchMouseEvent('mouseup', e.target)
|
|
if (this.touchesNum === 1) {
|
|
// 模拟双击事件
|
|
this.clickNum++
|
|
setTimeout(() => {
|
|
this.clickNum = 0
|
|
this.lastTouchStartPosition = null
|
|
this.lastTouchStartDistance = 0
|
|
}, 300)
|
|
let ev = this.singleTouchstartEvent
|
|
if (this.clickNum > 1 && this.lastTouchStartDistance <= 5) {
|
|
this.clickNum = 0
|
|
this.dispatchMouseEvent('dblclick', ev.target, ev)
|
|
} else {
|
|
// 点击事件应该不用模拟
|
|
// this.dispatchMouseEvent('click', ev.target, ev)
|
|
}
|
|
}
|
|
this.touchesNum = 0
|
|
this.singleTouchstartEvent = null
|
|
this.touchStartScaleView = null
|
|
}
|
|
|
|
// 发送鼠标事件
|
|
dispatchMouseEvent(eventName, target, e) {
|
|
let opt = {}
|
|
if (e) {
|
|
opt = {
|
|
screenX: e.screenX,
|
|
screenY: e.screenY,
|
|
clientX: e.clientX,
|
|
clientY: e.clientY,
|
|
which: 1
|
|
}
|
|
}
|
|
let event = new MouseEvent(eventName, {
|
|
view: document.defaultView,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
...opt
|
|
})
|
|
target.dispatchEvent(event)
|
|
}
|
|
|
|
// 插件被移除前做的事情
|
|
beforePluginRemove() {
|
|
this.unBindEvent()
|
|
}
|
|
|
|
// 插件被卸载前做的事情
|
|
beforePluginDestroy() {
|
|
this.unBindEvent()
|
|
}
|
|
}
|
|
|
|
TouchEvent.instanceName = 'touchEvent'
|
|
|
|
export default TouchEvent
|