feat:更换画布

This commit is contained in:
wangjiahao
2021-03-25 19:16:32 +08:00
parent 470f8cddae
commit 5db39b5855
65 changed files with 8586 additions and 427 deletions

View 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' },
],
},
]

View 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)
}

View 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 = {}
}

View File

@@ -0,0 +1,3 @@
import Vue from 'vue'
// 用于监听、触发事件
export default new Vue()

View 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,
}

View File

@@ -0,0 +1,5 @@
let id = 0
// 主要用于 Vue 的 diff 算法,为每个元素创建一个独一无二的 ID
export default function generateID() {
return id++
}

View 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])
}
}

View 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')
}

View 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
}

View File

@@ -0,0 +1,9 @@
import { Message } from 'element-ui'
export default function toast(message = '', type = 'error', duration = 1500) {
Message({
message,
type,
duration,
})
}

View 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
}

View 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)
}