diff --git a/src/views/screen/canvas-main/datav-transform/index.ts b/src/views/screen/canvas-main/datav-transform/index.ts index 59cdeae6..33fd1829 100644 --- a/src/views/screen/canvas-main/datav-transform/index.ts +++ b/src/views/screen/canvas-main/datav-transform/index.ts @@ -77,37 +77,148 @@ export const setHover = (com: DatavComponent, hovered: boolean) => { com.hovered = hovered } +/** + * 角度转弧度 + * Math.PI = 180 度 + * @param angle + * @returns {number} + */ +function angleToRadian(angle) { + return angle * Math.PI / 180 +} +/** + * 计算根据圆心旋转后的点的坐标 + * @param {Object} point 旋转前的点坐标 + * @param {Object} center 旋转中心 + * @param {Number} rotate 旋转的角度 + * @return {Object} 旋转后的坐标 + * https://www.zhihu.com/question/67425734/answer/252724399 旋转矩阵公式 + */ +export function calculateRotatedPointCoordinate(point, center, rotate) { + /** + * 旋转公式: + * 点a(x, y) + * 旋转中心c(x, y) + * 旋转后点n(x, y) + * 旋转角度θ tan ?? + * nx = cosθ * (ax - cx) - sinθ * (ay - cy) + cx + * ny = sinθ * (ax - cx) + cosθ * (ay - cy) + cy + */ + return { + x: (point.x - center.x) * Math.cos(angleToRadian(rotate)) - (point.y - center.y) * Math.sin(angleToRadian(rotate)) + center.x, + y: (point.x - center.x) * Math.sin(angleToRadian(rotate)) + (point.y - center.y) * Math.cos(angleToRadian(rotate)) + center.y, + } +} + +export function getCenterPoint(p1, p2) { + return { + x: p1.x + ((p2.x - p1.x) / 2), + y: p1.y + ((p2.y - p1.y) / 2), + } +} + +/** + * 计算缩放后位置大小 + * @param direction 拖拽方向 + * @param style 当前位置和大小 + * @param startPoint 拖拽起始点位置 + * @param symmetricPoint 对称点坐标 + * @param endPoint 当前拖拽位置 + * @returns {{}|any} + */ +export function calcResizeInfo(direction, style, startPoint, symmetricPoint, endPoint) { + // 拖拽角上的点 + if (direction.length === 2) { + const newCenter = getCenterPoint(endPoint, symmetricPoint) + const thatPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenter, -style.rotate) + const thisPoint = calculateRotatedPointCoordinate(endPoint, newCenter, -style.rotate) + const newStyle = { + x: undefined, + y: undefined, + width: undefined, + height: undefined, + } + // 判断: 左或者右 + if (direction[0] === 'l') { + newStyle.x = Math.round(thisPoint.x / style.scale) + newStyle.width = Math.round((thatPoint.x - thisPoint.x) / style.scale) + } else if (direction[0] === 'r') { + newStyle.x = Math.round(thatPoint.x / style.scale) + newStyle.width = Math.round((thisPoint.x - thatPoint.x) / style.scale) + } + // 判断: 上或者下 + if (direction[1] === 't') { + newStyle.y = Math.round(thisPoint.y / style.scale) + newStyle.height = Math.round((thatPoint.y - thisPoint.y) / style.scale) + } else if (direction[1] === 'b') { + newStyle.y = Math.round(thatPoint.y / style.scale) + newStyle.height = Math.round((thisPoint.y - thatPoint.y) / style.scale) + } + return newStyle + } + + // 拖拽边上的点 + if (direction.length === 1) { + const newStyle = JSON.parse(JSON.stringify(style)) + const thisPoint = calculateRotatedPointCoordinate(endPoint, startPoint, -style.rotate) + + // 拖拽上下两边 + if (direction === 't' || direction === 'b') { + const thatPoint = calculateRotatedPointCoordinate({ x: startPoint.x, y: thisPoint.y }, startPoint, style.rotate) + const height = Math.sqrt((thatPoint.x - symmetricPoint.x) ** 2 + (thatPoint.y - symmetricPoint.y) ** 2) + if (height > 0) { + const center = { x: thatPoint.x - (thatPoint.x - symmetricPoint.x) / 2, y: thatPoint.y + (symmetricPoint.y - thatPoint.y) / 2 } + newStyle.width = Math.round(style.width / style.scale) + newStyle.height = Math.round(height / style.scale) + newStyle.x = Math.round((center.x - (style.width / 2)) / style.scale) + newStyle.y = Math.round((center.y - (height / 2)) / style.scale) + } + } + + // 拖拽左右两边 + if (direction === 'l' || direction === 'r') { + const thatPoint = calculateRotatedPointCoordinate({ x: thisPoint.x, y: startPoint.y }, startPoint, style.rotate) + const width = Math.sqrt((thatPoint.x - symmetricPoint.x) ** 2 + (thatPoint.y - symmetricPoint.y) ** 2) + if (width > 0) { + const center = { x: thatPoint.x - (thatPoint.x - symmetricPoint.x) / 2, y: thatPoint.y + (symmetricPoint.y - thatPoint.y) / 2 } + newStyle.width = Math.round(width / style.scale) + newStyle.height = Math.round(style.height / style.scale) + newStyle.x = Math.round((center.x - (width / 2)) / style.scale) + newStyle.y = Math.round((center.y - (style.height / 2)) / style.scale) + } + } + return newStyle + } +} + const setAttr = (ev: MouseEvent, dir: Direction | null, com: DatavComponent, scale: number, grid: number) => { const attr = { ...com.attr } const pos = Object.create(null) as Partial + + const style = { + x: Math.round(attr.x * scale), + y: Math.round(attr.y * scale), + width: Math.round(attr.w * scale), + height: Math.round(attr.h * scale), + rotate: attr.deg, + scale: scale, + } + // 组件中心点 + const center = { x: style.x + style.width / 2, y: style.y + style.height / 2 } + // 获取画布位移信息 + const layoutRect = document.querySelector('#canvas-coms').getBoundingClientRect() + // 当前点击坐标 + const startPoint = { x: ev.clientX - layoutRect.left, y: ev.clientY - layoutRect.top } + // 获取对称点的坐标 + const symmetricPoint = { x: center.x - (startPoint.x - center.x), y: center.y - (startPoint.y - center.y) } const move = (e: MouseEvent) => { - if (dir === 't') { - pos.h = Math.round(attr.h + (ev.clientY - e.clientY) / scale) - pos.y = Math.round(attr.y + (e.clientY - ev.clientY) / scale) - } else if (dir === 'rt') { - pos.h = Math.round(attr.h + (ev.clientY - e.clientY) / scale) - pos.w = Math.round(attr.w + (ev.clientX - e.clientX) / scale) - pos.x = Math.round(attr.x + (e.clientX - ev.clientX) / scale) - pos.y = Math.round(attr.y + (e.clientY - ev.clientY) / scale) - } else if (dir === 'r') { - pos.w = Math.round(attr.w + (e.clientX - ev.clientX) / scale) - } else if (dir === 'rb') { - pos.h = Math.round(attr.h + (e.clientY - ev.clientY) / scale) - pos.w = Math.round(attr.w + (e.clientX - ev.clientX) / scale) - } else if (dir === 'b') { - pos.h = Math.round(attr.h + (e.clientY - ev.clientY) / scale) - } else if (dir === 'lb') { - pos.h = Math.round(attr.h + (e.clientY - ev.clientY) / scale) - pos.w = Math.round(attr.w + (ev.clientX - e.clientX) / scale) - pos.x = Math.round(attr.x + (e.clientX - ev.clientX) / scale) - } else if (dir === 'l') { - pos.w = Math.round(attr.w + (ev.clientX - e.clientX) / scale) - pos.x = Math.round(attr.x + (e.clientX - ev.clientX) / scale) - } else if (dir === 'lt') { - pos.h = Math.round(attr.h + (ev.clientY - e.clientY) / scale) - pos.w = Math.round(attr.w + (ev.clientX - e.clientX) / scale) - pos.x = Math.round(attr.x + (e.clientX - ev.clientX) / scale) - pos.y = Math.round(attr.y + (e.clientY - ev.clientY) / scale) + if (dir !== null) { + const endPoint = { x: e.clientX - layoutRect.left, y: e.clientY - layoutRect.top } + const newPosition = calcResizeInfo(dir, style, startPoint, symmetricPoint, endPoint) + pos.x = newPosition.x + pos.y = newPosition.y + pos.w = newPosition.width + pos.h = newPosition.height } else { // grid 是每次移动固定格数 pos.x = attr.x + Math.round((e.clientX - ev.clientX) / scale / grid) * grid diff --git a/src/views/screen/canvas-main/ruler/index.ts b/src/views/screen/canvas-main/ruler/index.ts index c6b21af0..3c0408ec 100644 --- a/src/views/screen/canvas-main/ruler/index.ts +++ b/src/views/screen/canvas-main/ruler/index.ts @@ -109,15 +109,22 @@ class GuideLine { } moving(ev: MouseEvent) { + const { options } = this ev.preventDefault() ev.stopPropagation() const { coor: oldCoor } = this const move = (e: MouseEvent) => { + if (options.direction === 'TB') { + document.body.style.cursor = 'col-resize' + } else { + document.body.style.cursor = 'row-resize' + } this.setLine(e) } const up = () => { + document.body.style.cursor = '' off(document, 'mousemove', move) off(document, 'mouseup', up) diff --git a/src/views/screen/canvas-main/ruler/index.vue b/src/views/screen/canvas-main/ruler/index.vue index e32f881b..ac50280e 100644 --- a/src/views/screen/canvas-main/ruler/index.vue +++ b/src/views/screen/canvas-main/ruler/index.vue @@ -164,7 +164,7 @@ export default defineComponent({ .h-container { left: 20px; - cursor: ew-resize; + cursor: col-resize; transform: translateX(0); .ruler-line { @@ -191,7 +191,7 @@ export default defineComponent({ } .v-container { - cursor: ns-resize; + cursor: row-resize; transform: rotate(90deg) translateX(0); transform-origin: 0 100% 0;