mirror of
https://github.com/dataease/dataease.git
synced 2026-05-21 04:08:10 +08:00
feat:更换画布
This commit is contained in:
94
frontend/src/utils/animationClassData.js
Normal file
94
frontend/src/utils/animationClassData.js
Normal file
@@ -0,0 +1,94 @@
|
||||
export default [
|
||||
{
|
||||
label: '进入',
|
||||
children: [
|
||||
{ label: '渐显', value: 'fadeIn' },
|
||||
{ label: '向右进入', value: 'fadeInLeft' },
|
||||
{ label: '向左进入', value: 'fadeInRight' },
|
||||
{ label: '向上进入', value: 'fadeInUp' },
|
||||
{ label: '向下进入', value: 'fadeInDown' },
|
||||
{ label: '向右长距进入', value: 'fadeInLeftBig' },
|
||||
{ label: '向左长距进入', value: 'fadeInRightBig' },
|
||||
{ label: '向上长距进入', value: 'fadeInUpBig' },
|
||||
{ label: '向下长距进入', value: 'fadeInDownBig' },
|
||||
{ label: '旋转进入', value: 'rotateIn' },
|
||||
{ label: '左顺时针旋转', value: 'rotateInDownLeft' },
|
||||
{ label: '右逆时针旋转', value: 'rotateInDownRight' },
|
||||
{ label: '左逆时针旋转', value: 'rotateInUpLeft' },
|
||||
{ label: '右逆时针旋转', value: 'rotateInUpRight' },
|
||||
{ label: '弹入', value: 'bounceIn' },
|
||||
{ label: '向右弹入', value: 'bounceInLeft' },
|
||||
{ label: '向左弹入', value: 'bounceInRight' },
|
||||
{ label: '向上弹入', value: 'bounceInUp' },
|
||||
{ label: '向下弹入', value: 'bounceInDown' },
|
||||
{ label: '光速从右进入', value: 'lightSpeedInRight' },
|
||||
{ label: '光速从左进入', value: 'lightSpeedInLeft' },
|
||||
{ label: '光速从右退出', value: 'lightSpeedOutRight' },
|
||||
{ label: '光速从左退出', value: 'lightSpeedOutLeft' },
|
||||
{ label: 'Y轴旋转', value: 'flip' },
|
||||
{ label: '中心X轴旋转', value: 'flipInX' },
|
||||
{ label: '中心Y轴旋转', value: 'flipInY' },
|
||||
{ label: '左长半径旋转', value: 'rollIn' },
|
||||
{ label: '由小变大进入', value: 'zoomIn' },
|
||||
{ label: '左变大进入', value: 'zoomInLeft' },
|
||||
{ label: '右变大进入', value: 'zoomInRight' },
|
||||
{ label: '向上变大进入', value: 'zoomInUp' },
|
||||
{ label: '向下变大进入', value: 'zoomInDown' },
|
||||
{ label: '向右滑动展开', value: 'slideInLeft' },
|
||||
{ label: '向左滑动展开', value: 'slideInRight' },
|
||||
{ label: '向上滑动展开', value: 'slideInUp' },
|
||||
{ label: '向下滑动展开', value: 'slideInDown' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '强调',
|
||||
children: [
|
||||
{ label: '弹跳', value: 'bounce' },
|
||||
{ label: '闪烁', value: 'flash' },
|
||||
{ label: '放大缩小', value: 'pulse' },
|
||||
{ label: '放大缩小弹簧', value: 'rubberBand' },
|
||||
{ label: '左右晃动', value: 'headShake' },
|
||||
{ label: '左右扇形摇摆', value: 'swing' },
|
||||
{ label: '放大晃动缩小', value: 'tada' },
|
||||
{ label: '扇形摇摆', value: 'wobble' },
|
||||
{ label: '左右上下晃动', value: 'jello' },
|
||||
{ label: 'Y轴旋转', value: 'flip' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '退出',
|
||||
children: [
|
||||
{ label: '渐隐', value: 'fadeOut' },
|
||||
{ label: '向左退出', value: 'fadeOutLeft' },
|
||||
{ label: '向右退出', value: 'fadeOutRight' },
|
||||
{ label: '向上退出', value: 'fadeOutUp' },
|
||||
{ label: '向下退出', value: 'fadeOutDown' },
|
||||
{ label: '向左长距退出', value: 'fadeOutLeftBig' },
|
||||
{ label: '向右长距退出', value: 'fadeOutRightBig' },
|
||||
{ label: '向上长距退出', value: 'fadeOutUpBig' },
|
||||
{ label: '向下长距退出', value: 'fadeOutDownBig' },
|
||||
{ label: '旋转退出', value: 'rotateOut' },
|
||||
{ label: '左顺时针旋转', value: 'rotateOutDownLeft' },
|
||||
{ label: '右逆时针旋转', value: 'rotateOutDownRight' },
|
||||
{ label: '左逆时针旋转', value: 'rotateOutUpLeft' },
|
||||
{ label: '右逆时针旋转', value: 'rotateOutUpRight' },
|
||||
{ label: '弹出', value: 'bounceOut' },
|
||||
{ label: '向左弹出', value: 'bounceOutLeft' },
|
||||
{ label: '向右弹出', value: 'bounceOutRight' },
|
||||
{ label: '向上弹出', value: 'bounceOutUp' },
|
||||
{ label: '向下弹出', value: 'bounceOutDown' },
|
||||
{ label: '中心X轴旋转', value: 'flipOutX' },
|
||||
{ label: '中心Y轴旋转', value: 'flipOutY' },
|
||||
{ label: '左长半径旋转', value: 'rollOut' },
|
||||
{ label: '由小变大退出', value: 'zoomOut' },
|
||||
{ label: '左变大退出', value: 'zoomOutLeft' },
|
||||
{ label: '右变大退出', value: 'zoomOutRight' },
|
||||
{ label: '向上变大退出', value: 'zoomOutUp' },
|
||||
{ label: '向下变大退出', value: 'zoomOutDown' },
|
||||
{ label: '向左滑动收起', value: 'slideOutLeft' },
|
||||
{ label: '向右滑动收起', value: 'slideOutRight' },
|
||||
{ label: '向上滑动收起', value: 'slideOutUp' },
|
||||
{ label: '向下滑动收起', value: 'slideOutDown' },
|
||||
],
|
||||
},
|
||||
]
|
||||
273
frontend/src/utils/calculateComponentPositonAndSize.js
Normal file
273
frontend/src/utils/calculateComponentPositonAndSize.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/* eslint-disable no-lonely-if */
|
||||
import { calculateRotatedPointCoordinate, getCenterPoint } from './translate'
|
||||
|
||||
const funcs = {
|
||||
lt: calculateLeftTop,
|
||||
t: calculateTop,
|
||||
rt: calculateRightTop,
|
||||
r: calculateRight,
|
||||
rb: calculateRightBottom,
|
||||
b: calculateBottom,
|
||||
lb: calculateLeftBottom,
|
||||
l: calculateLeft,
|
||||
}
|
||||
|
||||
function calculateLeftTop(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint } = pointInfo
|
||||
let newCenterPoint = getCenterPoint(curPositon, symmetricPoint)
|
||||
let newTopLeftPoint = calculateRotatedPointCoordinate(curPositon, newCenterPoint, -style.rotate)
|
||||
let newBottomRightPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
let newWidth = newBottomRightPoint.x - newTopLeftPoint.x
|
||||
let newHeight = newBottomRightPoint.y - newTopLeftPoint.y
|
||||
|
||||
if (needLockProportion) {
|
||||
if (newWidth / newHeight > proportion) {
|
||||
newTopLeftPoint.x += Math.abs(newWidth - newHeight * proportion)
|
||||
newWidth = newHeight * proportion
|
||||
} else {
|
||||
newTopLeftPoint.y += Math.abs(newHeight - newWidth / proportion)
|
||||
newHeight = newWidth / proportion
|
||||
}
|
||||
|
||||
// 由于现在求的未旋转前的坐标是以没按比例缩减宽高前的坐标来计算的
|
||||
// 所以缩减宽高后,需要按照原来的中心点旋转回去,获得缩减宽高并旋转后对应的坐标
|
||||
// 然后以这个坐标和对称点获得新的中心点,并重新计算未旋转前的坐标
|
||||
const rotatedTopLeftPoint = calculateRotatedPointCoordinate(newTopLeftPoint, newCenterPoint, style.rotate)
|
||||
newCenterPoint = getCenterPoint(rotatedTopLeftPoint, symmetricPoint)
|
||||
newTopLeftPoint = calculateRotatedPointCoordinate(rotatedTopLeftPoint, newCenterPoint, -style.rotate)
|
||||
newBottomRightPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
newWidth = newBottomRightPoint.x - newTopLeftPoint.x
|
||||
newHeight = newBottomRightPoint.y - newTopLeftPoint.y
|
||||
}
|
||||
|
||||
if (newWidth > 0 && newHeight > 0) {
|
||||
style.width = Math.round(newWidth)
|
||||
style.height = Math.round(newHeight)
|
||||
style.left = Math.round(newTopLeftPoint.x)
|
||||
style.top = Math.round(newTopLeftPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
function calculateRightTop(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint } = pointInfo
|
||||
let newCenterPoint = getCenterPoint(curPositon, symmetricPoint)
|
||||
let newTopRightPoint = calculateRotatedPointCoordinate(curPositon, newCenterPoint, -style.rotate)
|
||||
let newBottomLeftPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
let newWidth = newTopRightPoint.x - newBottomLeftPoint.x
|
||||
let newHeight = newBottomLeftPoint.y - newTopRightPoint.y
|
||||
|
||||
if (needLockProportion) {
|
||||
if (newWidth / newHeight > proportion) {
|
||||
newTopRightPoint.x -= Math.abs(newWidth - newHeight * proportion)
|
||||
newWidth = newHeight * proportion
|
||||
} else {
|
||||
newTopRightPoint.y += Math.abs(newHeight - newWidth / proportion)
|
||||
newHeight = newWidth / proportion
|
||||
}
|
||||
|
||||
const rotatedTopRightPoint = calculateRotatedPointCoordinate(newTopRightPoint, newCenterPoint, style.rotate)
|
||||
newCenterPoint = getCenterPoint(rotatedTopRightPoint, symmetricPoint)
|
||||
newTopRightPoint = calculateRotatedPointCoordinate(rotatedTopRightPoint, newCenterPoint, -style.rotate)
|
||||
newBottomLeftPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
newWidth = newTopRightPoint.x - newBottomLeftPoint.x
|
||||
newHeight = newBottomLeftPoint.y - newTopRightPoint.y
|
||||
}
|
||||
|
||||
if (newWidth > 0 && newHeight > 0) {
|
||||
style.width = Math.round(newWidth)
|
||||
style.height = Math.round(newHeight)
|
||||
style.left = Math.round(newBottomLeftPoint.x)
|
||||
style.top = Math.round(newTopRightPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
function calculateRightBottom(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint } = pointInfo
|
||||
let newCenterPoint = getCenterPoint(curPositon, symmetricPoint)
|
||||
let newTopLeftPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
let newBottomRightPoint = calculateRotatedPointCoordinate(curPositon, newCenterPoint, -style.rotate)
|
||||
|
||||
let newWidth = newBottomRightPoint.x - newTopLeftPoint.x
|
||||
let newHeight = newBottomRightPoint.y - newTopLeftPoint.y
|
||||
|
||||
if (needLockProportion) {
|
||||
if (newWidth / newHeight > proportion) {
|
||||
newBottomRightPoint.x -= Math.abs(newWidth - newHeight * proportion)
|
||||
newWidth = newHeight * proportion
|
||||
} else {
|
||||
newBottomRightPoint.y -= Math.abs(newHeight - newWidth / proportion)
|
||||
newHeight = newWidth / proportion
|
||||
}
|
||||
|
||||
const rotatedBottomRightPoint = calculateRotatedPointCoordinate(newBottomRightPoint, newCenterPoint, style.rotate)
|
||||
newCenterPoint = getCenterPoint(rotatedBottomRightPoint, symmetricPoint)
|
||||
newTopLeftPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
newBottomRightPoint = calculateRotatedPointCoordinate(rotatedBottomRightPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
newWidth = newBottomRightPoint.x - newTopLeftPoint.x
|
||||
newHeight = newBottomRightPoint.y - newTopLeftPoint.y
|
||||
}
|
||||
|
||||
if (newWidth > 0 && newHeight > 0) {
|
||||
style.width = Math.round(newWidth)
|
||||
style.height = Math.round(newHeight)
|
||||
style.left = Math.round(newTopLeftPoint.x)
|
||||
style.top = Math.round(newTopLeftPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
function calculateLeftBottom(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint } = pointInfo
|
||||
let newCenterPoint = getCenterPoint(curPositon, symmetricPoint)
|
||||
let newTopRightPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
let newBottomLeftPoint = calculateRotatedPointCoordinate(curPositon, newCenterPoint, -style.rotate)
|
||||
|
||||
let newWidth = newTopRightPoint.x - newBottomLeftPoint.x
|
||||
let newHeight = newBottomLeftPoint.y - newTopRightPoint.y
|
||||
|
||||
if (needLockProportion) {
|
||||
if (newWidth / newHeight > proportion) {
|
||||
newBottomLeftPoint.x += Math.abs(newWidth - newHeight * proportion)
|
||||
newWidth = newHeight * proportion
|
||||
} else {
|
||||
newBottomLeftPoint.y -= Math.abs(newHeight - newWidth / proportion)
|
||||
newHeight = newWidth / proportion
|
||||
}
|
||||
|
||||
const rotatedBottomLeftPoint = calculateRotatedPointCoordinate(newBottomLeftPoint, newCenterPoint, style.rotate)
|
||||
newCenterPoint = getCenterPoint(rotatedBottomLeftPoint, symmetricPoint)
|
||||
newTopRightPoint = calculateRotatedPointCoordinate(symmetricPoint, newCenterPoint, -style.rotate)
|
||||
newBottomLeftPoint = calculateRotatedPointCoordinate(rotatedBottomLeftPoint, newCenterPoint, -style.rotate)
|
||||
|
||||
newWidth = newTopRightPoint.x - newBottomLeftPoint.x
|
||||
newHeight = newBottomLeftPoint.y - newTopRightPoint.y
|
||||
}
|
||||
|
||||
if (newWidth > 0 && newHeight > 0) {
|
||||
style.width = Math.round(newWidth)
|
||||
style.height = Math.round(newHeight)
|
||||
style.left = Math.round(newBottomLeftPoint.x)
|
||||
style.top = Math.round(newTopRightPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTop(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint, curPoint } = pointInfo
|
||||
let rotatedcurPositon = calculateRotatedPointCoordinate(curPositon, curPoint, -style.rotate)
|
||||
let rotatedTopMiddlePoint = calculateRotatedPointCoordinate({
|
||||
x: curPoint.x,
|
||||
y: rotatedcurPositon.y,
|
||||
}, curPoint, style.rotate)
|
||||
|
||||
// 勾股定理
|
||||
let newHeight = Math.sqrt((rotatedTopMiddlePoint.x - symmetricPoint.x) ** 2 + (rotatedTopMiddlePoint.y - symmetricPoint.y) ** 2)
|
||||
|
||||
if (newHeight > 0) {
|
||||
const newCenter = {
|
||||
x: rotatedTopMiddlePoint.x - (rotatedTopMiddlePoint.x - symmetricPoint.x) / 2,
|
||||
y: rotatedTopMiddlePoint.y + (symmetricPoint.y - rotatedTopMiddlePoint.y) / 2,
|
||||
}
|
||||
|
||||
let width = style.width
|
||||
// 因为调整的是高度 所以只需根据锁定的比例调整宽度即可
|
||||
if (needLockProportion) {
|
||||
width = newHeight * proportion
|
||||
}
|
||||
|
||||
style.width = width
|
||||
style.height = Math.round(newHeight)
|
||||
style.top = Math.round(newCenter.y - (newHeight / 2))
|
||||
style.left = Math.round(newCenter.x - (style.width / 2))
|
||||
}
|
||||
}
|
||||
|
||||
function calculateRight(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint, curPoint } = pointInfo
|
||||
const rotatedcurPositon = calculateRotatedPointCoordinate(curPositon, curPoint, -style.rotate)
|
||||
const rotatedRightMiddlePoint = calculateRotatedPointCoordinate({
|
||||
x: rotatedcurPositon.x,
|
||||
y: curPoint.y,
|
||||
}, curPoint, style.rotate)
|
||||
|
||||
let newWidth = Math.sqrt((rotatedRightMiddlePoint.x - symmetricPoint.x) ** 2 + (rotatedRightMiddlePoint.y - symmetricPoint.y) ** 2)
|
||||
if (newWidth > 0) {
|
||||
const newCenter = {
|
||||
x: rotatedRightMiddlePoint.x - (rotatedRightMiddlePoint.x - symmetricPoint.x) / 2,
|
||||
y: rotatedRightMiddlePoint.y + (symmetricPoint.y - rotatedRightMiddlePoint.y) / 2,
|
||||
}
|
||||
|
||||
let height = style.height
|
||||
// 因为调整的是宽度 所以只需根据锁定的比例调整高度即可
|
||||
if (needLockProportion) {
|
||||
height = newWidth / proportion
|
||||
}
|
||||
|
||||
style.height = height
|
||||
style.width = Math.round(newWidth)
|
||||
style.top = Math.round(newCenter.y - (style.height / 2))
|
||||
style.left = Math.round(newCenter.x - (newWidth / 2))
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBottom(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint, curPoint } = pointInfo
|
||||
const rotatedcurPositon = calculateRotatedPointCoordinate(curPositon, curPoint, -style.rotate)
|
||||
const rotatedBottomMiddlePoint = calculateRotatedPointCoordinate({
|
||||
x: curPoint.x,
|
||||
y: rotatedcurPositon.y,
|
||||
}, curPoint, style.rotate)
|
||||
|
||||
const newHeight = Math.sqrt((rotatedBottomMiddlePoint.x - symmetricPoint.x) ** 2 + (rotatedBottomMiddlePoint.y - symmetricPoint.y) ** 2)
|
||||
if (newHeight > 0) {
|
||||
const newCenter = {
|
||||
x: rotatedBottomMiddlePoint.x - (rotatedBottomMiddlePoint.x - symmetricPoint.x) / 2,
|
||||
y: rotatedBottomMiddlePoint.y + (symmetricPoint.y - rotatedBottomMiddlePoint.y) / 2,
|
||||
}
|
||||
|
||||
let width = style.width
|
||||
// 因为调整的是高度 所以只需根据锁定的比例调整宽度即可
|
||||
if (needLockProportion) {
|
||||
width = newHeight * proportion
|
||||
}
|
||||
|
||||
style.width = width
|
||||
style.height = Math.round(newHeight)
|
||||
style.top = Math.round(newCenter.y - (newHeight / 2))
|
||||
style.left = Math.round(newCenter.x - (style.width / 2))
|
||||
}
|
||||
}
|
||||
|
||||
function calculateLeft(style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
const { symmetricPoint, curPoint } = pointInfo
|
||||
const rotatedcurPositon = calculateRotatedPointCoordinate(curPositon, curPoint, -style.rotate)
|
||||
const rotatedLeftMiddlePoint = calculateRotatedPointCoordinate({
|
||||
x: rotatedcurPositon.x,
|
||||
y: curPoint.y,
|
||||
}, curPoint, style.rotate)
|
||||
|
||||
const newWidth = Math.sqrt((rotatedLeftMiddlePoint.x - symmetricPoint.x) ** 2 + (rotatedLeftMiddlePoint.y - symmetricPoint.y) ** 2)
|
||||
if (newWidth > 0) {
|
||||
const newCenter = {
|
||||
x: rotatedLeftMiddlePoint.x - (rotatedLeftMiddlePoint.x - symmetricPoint.x) / 2,
|
||||
y: rotatedLeftMiddlePoint.y + (symmetricPoint.y - rotatedLeftMiddlePoint.y) / 2,
|
||||
}
|
||||
|
||||
let height = style.height
|
||||
if (needLockProportion) {
|
||||
height = newWidth / proportion
|
||||
}
|
||||
|
||||
style.height = height
|
||||
style.width = Math.round(newWidth)
|
||||
style.top = Math.round(newCenter.y - (style.height / 2))
|
||||
style.left = Math.round(newCenter.x - (newWidth / 2))
|
||||
}
|
||||
}
|
||||
|
||||
export default function calculateComponentPositonAndSize(name, style, curPositon, proportion, needLockProportion, pointInfo) {
|
||||
funcs[name](style, curPositon, proportion, needLockProportion, pointInfo)
|
||||
}
|
||||
20
frontend/src/utils/decomposeComponent.js
Normal file
20
frontend/src/utils/decomposeComponent.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { $ } from './utils'
|
||||
import { mod360 } from './translate'
|
||||
|
||||
// 将组合中的各个子组件拆分出来,并计算它们新的 style
|
||||
export default function decomposeComponent(component, editorRect, parentStyle) {
|
||||
const componentRect = $(`#component${component.id}`).getBoundingClientRect()
|
||||
// 获取元素的中心点坐标
|
||||
const center = {
|
||||
x: componentRect.left - editorRect.left + componentRect.width / 2,
|
||||
y: componentRect.top - editorRect.top + componentRect.height / 2,
|
||||
}
|
||||
|
||||
component.style.rotate = mod360(component.style.rotate + parentStyle.rotate)
|
||||
component.style.width = parseFloat(component.groupStyle.width) / 100 * parentStyle.width
|
||||
component.style.height = parseFloat(component.groupStyle.height) / 100 * parentStyle.height
|
||||
// 计算出元素新的 top left 坐标
|
||||
component.style.left = center.x - component.style.width / 2
|
||||
component.style.top = center.y - component.style.height / 2
|
||||
component.groupStyle = {}
|
||||
}
|
||||
3
frontend/src/utils/eventBus.js
Normal file
3
frontend/src/utils/eventBus.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Vue from 'vue'
|
||||
// 用于监听、触发事件
|
||||
export default new Vue()
|
||||
39
frontend/src/utils/events.js
Normal file
39
frontend/src/utils/events.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// 编辑器自定义事件
|
||||
const events = {
|
||||
redirect(url) {
|
||||
if (url) {
|
||||
window.location.href = url
|
||||
}
|
||||
},
|
||||
|
||||
alert(msg) {
|
||||
if (msg) {
|
||||
alert(msg)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mixins = {
|
||||
methods: events,
|
||||
}
|
||||
|
||||
const eventList = [
|
||||
{
|
||||
key: 'redirect',
|
||||
label: '跳转事件',
|
||||
event: events.redirect,
|
||||
param: '',
|
||||
},
|
||||
{
|
||||
key: 'alert',
|
||||
label: 'alert 事件',
|
||||
event: events.alert,
|
||||
param: '',
|
||||
},
|
||||
]
|
||||
|
||||
export {
|
||||
mixins,
|
||||
events,
|
||||
eventList,
|
||||
}
|
||||
5
frontend/src/utils/generateID.js
Normal file
5
frontend/src/utils/generateID.js
Normal file
@@ -0,0 +1,5 @@
|
||||
let id = 0
|
||||
// 主要用于 Vue 的 diff 算法,为每个元素创建一个独一无二的 ID
|
||||
export default function generateID() {
|
||||
return id++
|
||||
}
|
||||
18
frontend/src/utils/runAnimation.js
Normal file
18
frontend/src/utils/runAnimation.js
Normal file
@@ -0,0 +1,18 @@
|
||||
export default async function runAnimation($el, animations = []) {
|
||||
const play = (animation) => new Promise(resolve => {
|
||||
$el.classList.add(animation.value, 'animated')
|
||||
const removeAnimation = () => {
|
||||
$el.removeEventListener('animationend', removeAnimation)
|
||||
$el.removeEventListener('animationcancel', removeAnimation)
|
||||
$el.classList.remove(animation.value, 'animated')
|
||||
resolve()
|
||||
}
|
||||
|
||||
$el.addEventListener('animationend', removeAnimation)
|
||||
$el.addEventListener('animationcancel', removeAnimation)
|
||||
})
|
||||
|
||||
for (let i = 0, len = animations.length; i < len; i++) {
|
||||
await play(animations[i])
|
||||
}
|
||||
}
|
||||
143
frontend/src/utils/shortcutKey.js
Normal file
143
frontend/src/utils/shortcutKey.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import store from '@/store'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
|
||||
const ctrlKey = 17,
|
||||
vKey = 86, // 粘贴
|
||||
cKey = 67, // 复制
|
||||
xKey = 88, // 剪切
|
||||
|
||||
yKey = 89, // 重做
|
||||
zKey = 90, // 撤销
|
||||
|
||||
gKey = 71, // 组合
|
||||
bKey = 66, // 拆分
|
||||
|
||||
lKey = 76, // 锁定
|
||||
uKey = 85, // 解锁
|
||||
|
||||
sKey = 83, // 保存
|
||||
pKey = 80, // 预览
|
||||
dKey = 68, // 删除
|
||||
deleteKey = 46, // 删除
|
||||
eKey = 69 // 清空画布
|
||||
|
||||
export const keycodes = [66, 67, 68, 69, 71, 76, 80, 83, 85, 86, 88, 89, 90]
|
||||
|
||||
// 与组件状态无关的操作
|
||||
const basemap = {
|
||||
[vKey]: paste,
|
||||
[yKey]: redo,
|
||||
[zKey]: undo,
|
||||
[sKey]: save,
|
||||
[pKey]: preview,
|
||||
[eKey]: clearCanvas,
|
||||
}
|
||||
|
||||
// 组件锁定状态下可以执行的操作
|
||||
const lockMap = {
|
||||
...basemap,
|
||||
[uKey]: unlock,
|
||||
}
|
||||
|
||||
// 组件未锁定状态下可以执行的操作
|
||||
const unlockMap = {
|
||||
...basemap,
|
||||
[cKey]: copy,
|
||||
[xKey]: cut,
|
||||
[gKey]: compose,
|
||||
[bKey]: decompose,
|
||||
[dKey]: deleteComponent,
|
||||
[deleteKey]: deleteComponent,
|
||||
[lKey]: lock,
|
||||
}
|
||||
|
||||
let isCtrlDown = false
|
||||
// 全局监听按键操作并执行相应命令
|
||||
export function listenGlobalKeyDown() {
|
||||
window.onkeydown = (e) => {
|
||||
const { curComponent } = store.state
|
||||
if (e.keyCode == ctrlKey) {
|
||||
isCtrlDown = true
|
||||
} else if (e.keyCode == deleteKey && curComponent) {
|
||||
store.commit('deleteComponent')
|
||||
store.commit('recordSnapshot')
|
||||
} else if (isCtrlDown) {
|
||||
if (!curComponent || !curComponent.isLock) {
|
||||
e.preventDefault()
|
||||
unlockMap[e.keyCode] && unlockMap[e.keyCode]()
|
||||
} else if (curComponent && curComponent.isLock) {
|
||||
e.preventDefault()
|
||||
lockMap[e.keyCode] && lockMap[e.keyCode]()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.onkeyup = (e) => {
|
||||
if (e.keyCode == ctrlKey) {
|
||||
isCtrlDown = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copy() {
|
||||
store.commit('copy')
|
||||
}
|
||||
|
||||
function paste() {
|
||||
store.commit('paste')
|
||||
store.commit('recordSnapshot')
|
||||
}
|
||||
|
||||
function cut() {
|
||||
store.commit('cut')
|
||||
}
|
||||
|
||||
function redo() {
|
||||
store.commit('redo')
|
||||
}
|
||||
|
||||
function undo() {
|
||||
store.commit('undo')
|
||||
}
|
||||
|
||||
function compose() {
|
||||
if (store.state.areaData.components.length) {
|
||||
store.commit('compose')
|
||||
store.commit('recordSnapshot')
|
||||
}
|
||||
}
|
||||
|
||||
function decompose() {
|
||||
const curComponent = store.state.curComponent
|
||||
if (curComponent && !curComponent.isLock && curComponent.component == 'Group') {
|
||||
store.commit('decompose')
|
||||
store.commit('recordSnapshot')
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
eventBus.$emit('save')
|
||||
}
|
||||
|
||||
function preview() {
|
||||
eventBus.$emit('preview')
|
||||
}
|
||||
|
||||
function deleteComponent() {
|
||||
if (store.state.curComponent) {
|
||||
store.commit('deleteComponent')
|
||||
store.commit('recordSnapshot')
|
||||
}
|
||||
}
|
||||
|
||||
function clearCanvas() {
|
||||
eventBus.$emit('clearCanvas')
|
||||
}
|
||||
|
||||
function lock() {
|
||||
store.commit('lock')
|
||||
}
|
||||
|
||||
function unlock() {
|
||||
store.commit('unlock')
|
||||
}
|
||||
55
frontend/src/utils/style.js
Normal file
55
frontend/src/utils/style.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { sin, cos } from '@/utils/translate'
|
||||
|
||||
export function getStyle(style, filter = []) {
|
||||
const needUnit = [
|
||||
'fontSize',
|
||||
'width',
|
||||
'height',
|
||||
'top',
|
||||
'left',
|
||||
'borderWidth',
|
||||
'letterSpacing',
|
||||
'borderRadius',
|
||||
]
|
||||
|
||||
const result = {}
|
||||
Object.keys(style).forEach(key => {
|
||||
if (!filter.includes(key)) {
|
||||
if (key != 'rotate') {
|
||||
result[key] = style[key]
|
||||
|
||||
if (needUnit.includes(key)) {
|
||||
result[key] += 'px'
|
||||
}
|
||||
} else {
|
||||
result.transform = key + '(' + style[key] + 'deg)'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 获取一个组件旋转 rotate 后的样式
|
||||
export function getComponentRotatedStyle(style) {
|
||||
style = { ...style }
|
||||
if (style.rotate != 0) {
|
||||
const newWidth = style.width * cos(style.rotate) + style.height * sin(style.rotate)
|
||||
const diffX = (style.width - newWidth) / 2 // 旋转后范围变小是正值,变大是负值
|
||||
style.left += diffX
|
||||
style.right = style.left + newWidth
|
||||
|
||||
const newHeight = style.height * cos(style.rotate) + style.width * sin(style.rotate)
|
||||
const diffY = (newHeight - style.height) / 2 // 始终是正
|
||||
style.top -= diffY
|
||||
style.bottom = style.top + newHeight
|
||||
|
||||
style.width = newWidth
|
||||
style.height = newHeight
|
||||
} else {
|
||||
style.bottom = style.top + style.height
|
||||
style.right = style.left + style.width
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
9
frontend/src/utils/toast.js
Normal file
9
frontend/src/utils/toast.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
export default function toast(message = '', type = 'error', duration = 1500) {
|
||||
Message({
|
||||
message,
|
||||
type,
|
||||
duration,
|
||||
})
|
||||
}
|
||||
127
frontend/src/utils/translate.js
Normal file
127
frontend/src/utils/translate.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import store from '@/store'
|
||||
|
||||
// 角度转弧度
|
||||
// Math.PI = 180 度
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取旋转后的点坐标(八个点之一)
|
||||
* @param {Object} style 样式
|
||||
* @param {Object} center 组件中心点
|
||||
* @param {String} name 点名称
|
||||
* @return {Object} 旋转后的点坐标
|
||||
*/
|
||||
export function getRotatedPointCoordinate(style, center, name) {
|
||||
let point // point 是未旋转前的坐标
|
||||
switch (name) {
|
||||
case 't':
|
||||
point = {
|
||||
x: style.left + (style.width / 2),
|
||||
y: style.top,
|
||||
}
|
||||
|
||||
break
|
||||
case 'b':
|
||||
point = {
|
||||
x: style.left + (style.width / 2),
|
||||
y: style.top + style.height,
|
||||
}
|
||||
|
||||
break
|
||||
case 'l':
|
||||
point = {
|
||||
x: style.left,
|
||||
y: style.top + style.height / 2,
|
||||
}
|
||||
|
||||
break
|
||||
case 'r':
|
||||
point = {
|
||||
x: style.left + style.width,
|
||||
y: style.top + style.height / 2,
|
||||
}
|
||||
|
||||
break
|
||||
case 'lt':
|
||||
point = {
|
||||
x: style.left,
|
||||
y: style.top,
|
||||
}
|
||||
|
||||
break
|
||||
case 'rt':
|
||||
point = {
|
||||
x: style.left + style.width,
|
||||
y: style.top,
|
||||
}
|
||||
|
||||
break
|
||||
case 'lb':
|
||||
point = {
|
||||
x: style.left,
|
||||
y: style.top + style.height,
|
||||
}
|
||||
|
||||
break
|
||||
default: // rb
|
||||
point = {
|
||||
x: style.left + style.width,
|
||||
y: style.top+ style.height,
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return calculateRotatedPointCoordinate(point, center, style.rotate)
|
||||
}
|
||||
|
||||
// 求两点之间的中点坐标
|
||||
export function getCenterPoint(p1, p2) {
|
||||
return {
|
||||
x: p1.x + ((p2.x - p1.x) / 2),
|
||||
y: p1.y + ((p2.y - p1.y) / 2),
|
||||
}
|
||||
}
|
||||
|
||||
export function sin(rotate) {
|
||||
return Math.abs(Math.sin(angleToRadian(rotate)))
|
||||
}
|
||||
|
||||
export function cos(rotate) {
|
||||
return Math.abs(Math.cos(angleToRadian(rotate)))
|
||||
}
|
||||
|
||||
export function mod360(deg) {
|
||||
return (deg + 360) % 360
|
||||
}
|
||||
|
||||
export function changeStyleWithScale(value) {
|
||||
return value * parseInt(store.state.canvasStyleData.scale) / 100
|
||||
}
|
||||
26
frontend/src/utils/utils.js
Normal file
26
frontend/src/utils/utils.js
Normal file
@@ -0,0 +1,26 @@
|
||||
export function deepCopy(target) {
|
||||
if (typeof target == 'object') {
|
||||
const result = Array.isArray(target)? [] : {}
|
||||
for (const key in target) {
|
||||
if (typeof target[key] == 'object') {
|
||||
result[key] = deepCopy(target[key])
|
||||
} else {
|
||||
result[key] = target[key]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
export function swap(arr, i, j) {
|
||||
const temp = arr[i]
|
||||
arr[i] = arr[j]
|
||||
arr[j] = temp
|
||||
}
|
||||
|
||||
export function $(selector) {
|
||||
return document.querySelector(selector)
|
||||
}
|
||||
Reference in New Issue
Block a user