123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import {mathUtil} from "@/graphic/Util/MathUtil";
- import {computed, onUnmounted, ref, Ref, watchEffect} from "vue";
- import {getPostionByTarget} from "@/components/base/utils";
- // @ts-ignore
- import matruces from '@/utils/matruces'
- type Point = { x: number, y: number }
- type PointStore = [Point] | [Point, Point]
- enum Mode {
- move,
- scale,
- angle
- }
- export const HandMode = {
- MoveAndScale: [Mode.move, Mode.scale],
- AngleAndScale: [Mode.angle, Mode.scale],
- Move: [Mode.move],
- Scale: [Mode.scale],
- Angle: [Mode.angle]
- }
- export const useHand = (
- targetRef: Ref<HTMLElement>,
- mode: Mode[],
- callback = () => {},
- oldMatrix = matruces.translateMatrix(0,0,0)
- ) => {
- const parent = document.documentElement
- const matrix = ref(oldMatrix)
- let translate: Point;
- let scale: {center: Point, scale: number}
- let angle: number
- let startPos: PointStore
- let currentPos: PointStore
- const getScrollPos = (dom: HTMLElement) => {
- let x = 0, y = 0;
- while (dom && dom !== parent) {
- x += dom.scrollLeft
- y += dom.scrollTop
- dom = dom.offsetParent as HTMLElement
- }
- return {x, y}
- }
- const getPointByEvent = (ev: TouchEvent | MouseEvent): PointStore => {
- if (ev instanceof TouchEvent) {
- const point1 = {
- x: ev.touches[0].pageX,
- y: ev.touches[0].pageY
- }
- return ev.touches.length > 1
- ? [
- point1,
- {
- x: ev.touches[1].pageX,
- y: ev.touches[1].pageY
- }
- ]
- : [point1]
- } else {
- return [{ x: ev.pageX, y: ev.pageY }]
- }
- }
- let targetPosition, pageCenter, domCenter, pageStart;
- const start = (ev: TouchEvent | MouseEvent) => {
- const scrollPos = getScrollPos(targetRef.value)
- startPos = getPointByEvent(ev)
- targetPosition = getPostionByTarget(targetRef.value, parent)
- domCenter = {
- x: targetRef.value.offsetWidth / 2,
- y: targetRef.value.offsetHeight / 2
- }
- pageStart = {
- x: targetPosition.x - scrollPos.x,
- y: targetPosition.y - scrollPos.y
- }
- pageCenter = {
- x: pageStart.x + domCenter.x,
- y: pageStart.y + domCenter.y
- }
- if (ev instanceof TouchEvent) {
- parent.addEventListener("touchmove", move)
- parent.addEventListener("touchend", end)
- } else {
- parent.addEventListener("mousemove", move)
- parent.addEventListener("mouseup", end)
- }
- ev.stopPropagation()
- ev.preventDefault()
- }
- const move = (ev: MouseEvent | TouchEvent) => {
- if ((currentPos = getPointByEvent(ev)).length != startPos.length) {
- return startPos = currentPos
- }
- if (startPos.length !== 2) {
- if (mode.includes(Mode.move)) {
- translate = {
- x: currentPos[0].x - startPos[0].x,
- y: currentPos[0].y - startPos[0].y
- }
- } else if (mode.includes(Mode.angle)) {
- const angleAngle = mathUtil.Angle(pageCenter, startPos[0], currentPos[0]) * (Math.PI / 180)
- const isClock = mathUtil.isClockwise([pageCenter, startPos[0], currentPos[0]])
- angle = isClock ? -angleAngle : angleAngle
- }
- } else if (mode.includes(Mode.scale)) {
- const center = scale?.center || {
- x: (startPos[0].x - pageStart.x + startPos[1].x - pageStart.x) / 2,
- y: (startPos[0].y - pageStart.y + startPos[1].y - pageStart.y) / 2,
- }
- scale = {
- scale: mathUtil.getDistance(...currentPos) / mathUtil.getDistance(...startPos),
- center
- }
- }
- updateMatrix()
- startPos = currentPos
- }
- const end = (ev: MouseEvent | TouchEvent) => {
- callback()
- translate = scale = angle = null;
- if (ev instanceof TouchEvent) {
- parent.removeEventListener("touchmove", move)
- parent.removeEventListener("touchend", end)
- } else {
- parent.removeEventListener("mousemove", move)
- parent.removeEventListener("mouseup", end)
- }
- }
- const updateMatrix = () => {
- let currentMatrix
- if (translate) {
- currentMatrix = matruces.translateMatrix(
- translate.x / matrix.value[0],
- translate.y / matrix.value[0],
- 0
- )
- translate = null
- } else if (scale) {
- const offset = {
- x: (scale.center.x - domCenter.x) / (matrix.value[0] * scale.scale),
- y: (scale.center.y - domCenter.y) / (matrix.value[0] * scale.scale)
- }
- currentMatrix = matruces.multiplyMatrices(
- matruces.multiplyMatrices(
- matruces.translateMatrix(offset.x, offset.y, 0),
- matruces.scaleMatrix(scale.scale, scale.scale, 1)
- ),
- matruces.translateMatrix(-offset.x, -offset.y, 0)
- )
- scale = null
- } else if (angle) {
- currentMatrix = matruces.rotateZMatrix(angle)
- angle = null
- }
- if (currentMatrix) {
- matrix.value = matruces.multiplyMatrices(
- matrix.value,
- currentMatrix
- )
- }
- }
- const stop = watchEffect((onCleanup) => {
- if (targetRef.value) {
- targetRef.value.addEventListener("mousedown", start)
- targetRef.value.addEventListener("touchstart", start)
- }
- onCleanup(() => {
- if (targetRef.value) {
- targetRef.value.removeEventListener("mousedown", start)
- targetRef.value.removeEventListener("touchstart", start)
- }
- parent.removeEventListener("mousemove", move)
- parent.removeEventListener("mouseup", end)
- parent.removeEventListener("touchmove", move)
- parent.removeEventListener("touchend", end)
- })
- })
- const cssMatrix = computed<string>(
- () => matruces.matrixArrayToCssMatrix(matrix.value)
- )
- onUnmounted(stop)
- return {
- stop,
- matrix,
- cssMatrix
- }
- }
|