This commit is contained in:
pipipi-pikachu 2020-12-19 18:29:33 +08:00
parent 585ecf008f
commit 9c63766314
3 changed files with 301 additions and 6 deletions

View File

@ -40,7 +40,7 @@ module.exports = {
'no-with': 'error',
'max-depth': ['error', 5],
'consistent-this': ['error', 'self'],
'max-lines': ['error', 1200],
'max-lines': ['error', 1500],
'no-multi-str': 'error',
'space-infix-ops': 'error',
'space-before-blocks': ['error', 'always'],

View File

@ -83,7 +83,7 @@ import { getImageDataURL } from '@/utils/image'
import { copyText, readClipboard } from '@/utils/clipboard'
import { encrypt, decrypt } from '@/utils/crypto'
import { getElementRange } from './utils/elementRange'
import { getElementRange, getRectRotatedRange } from './utils/elementRange'
import { getAngleFromCoordinate, getRotateElementPoints, getOppositePoint } from './utils/elementRotate'
import { lockElement as _lockElement, unlockElement as _unlockElement } from './utils/elementLock'
import { combineElements as _combineElements, uncombineElements as _uncombineElements } from './utils/elementCombine'
@ -280,7 +280,294 @@ export default defineComponent({
}
const moveElement = (e: MouseEvent, element: PPTElement) => {
console.log(e, element)
if(!activeElementIdList.value.includes(element.elId)) return
let isMouseDown = true
//
const edgeWidth = VIEWPORT_SIZE
const edgeHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
const originElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList.value))
const originActiveElementList = originElementList.filter(el => activeElementIdList.value.includes(el.elId))
const sorptionRange = 3
const elOriginLeft = element.left
const elOriginTop = element.top
const elOriginWidth = element.width
const elOriginHeight = ('height' in element && element.height) ? element.height : 0
const elOriginRotate = ('rotate' in element && element.rotate) ? element.rotate : 0
const startPageX = e.pageX
const startPageY = e.pageY
let isMisoperation: boolean | null = null
const isActiveGroupElement = element.elId === activeGroupElementId.value
// 线
//
let horizontalLines: AlignLine[] = []
let verticalLines: AlignLine[] = []
// 线
for(const el of elementList.value) {
if(el.type === ElementTypes.LINE) continue
if(isActiveGroupElement && el.elId === element.elId) continue
if(!isActiveGroupElement && activeElementIdList.value.includes(el.elId)) continue
let left, top, width, height
if('rotate' in el && el.rotate) {
const { xRange, yRange } = getRectRotatedRange({
left: el.left,
top: el.top,
width: el.width,
height: el.height,
rotate: el.rotate,
})
left = xRange[0]
top = yRange[0]
width = xRange[1] - xRange[0]
height = yRange[1] - yRange[0]
}
else {
left = el.left
top = el.top
width = el.width
height = el.height
}
const right = left + width
const bottom = top + height
const centerX = top + height / 2
const centerY = left + width / 2
const topLine: AlignLine = { value: top, range: [left, right] }
const bottomLine: AlignLine = { value: bottom, range: [left, right] }
const horizontalCenterLine: AlignLine = { value: centerX, range: [left, right] }
const leftLine: AlignLine = { value: left, range: [top, bottom] }
const rightLine: AlignLine = { value: right, range: [top, bottom] }
const verticalCenterLine: AlignLine = { value: centerY, range: [top, bottom] }
horizontalLines.push(topLine, bottomLine, horizontalCenterLine)
verticalLines.push(leftLine, rightLine, verticalCenterLine)
}
//
const edgeTopLine: AlignLine = { value: 0, range: [0, edgeWidth] }
const edgeBottomLine: AlignLine = { value: edgeHeight, range: [0, edgeWidth] }
const edgeHorizontalCenterLine: AlignLine = { value: edgeHeight / 2, range: [0, edgeWidth] }
const edgeLeftLine: AlignLine = { value: 0, range: [0, edgeHeight] }
const edgeRightLine: AlignLine = { value: edgeWidth, range: [0, edgeHeight] }
const edgeVerticalCenterLine: AlignLine = { value: edgeWidth / 2, range: [0, edgeHeight] }
horizontalLines.push(edgeTopLine, edgeBottomLine, edgeHorizontalCenterLine)
verticalLines.push(edgeLeftLine, edgeRightLine, edgeVerticalCenterLine)
// 线
horizontalLines = uniqAlignLines(horizontalLines)
verticalLines = uniqAlignLines(verticalLines)
document.onmousemove = e => {
const currentPageX = e.pageX
const currentPageY = e.pageY
//
// nulltrue
// false
if(isMisoperation !== false) {
isMisoperation = Math.abs(startPageX - currentPageX) < sorptionRange &&
Math.abs(startPageY - currentPageY) < sorptionRange
}
if( !isMouseDown || isMisoperation ) return
//
const moveX = (currentPageX - startPageX) / canvasScale.value
const moveY = (currentPageY - startPageY) / canvasScale.value
//
let targetLeft = elOriginLeft + moveX
let targetTop = elOriginTop + moveY
//
// 线
//
let targetMinX: number, targetMaxX: number, targetMinY: number, targetMaxY: number
if(activeElementIdList.value.length === 1 || isActiveGroupElement) {
if(elOriginRotate) {
const { xRange, yRange } = getRectRotatedRange({
left: targetLeft,
top: targetTop,
width: elOriginWidth,
height: elOriginHeight,
rotate: elOriginRotate,
})
targetMinX = xRange[0]
targetMaxX = xRange[1]
targetMinY = yRange[0]
targetMaxY = yRange[1]
}
else if(element.type === 'line') {
targetMinX = targetLeft
targetMaxX = targetLeft + Math.max(element.start[0], element.end[0])
targetMinY = targetTop
targetMaxY = targetTop + Math.max(element.start[1], element.end[1])
}
else {
targetMinX = targetLeft
targetMaxX = targetLeft + elOriginWidth
targetMinY = targetTop
targetMaxY = targetTop + elOriginHeight
}
}
else {
const leftValues = []
const topValues = []
const rightValues = []
const bottomValues = []
for(let i = 0; i < originActiveElementList.length; i++) {
const element = originActiveElementList[i]
const left = element.left + moveX
const top = element.top + moveY
const width = element.width
const height = ('height' in element && element.height) ? element.height : 0
const rotate = ('rotate' in element && element.rotate) ? element.rotate : 0
if('rotate' in element && element.rotate) {
const { xRange, yRange } = getRectRotatedRange({ left, top, width, height, rotate })
leftValues.push(xRange[0])
topValues.push(yRange[0])
rightValues.push(xRange[1])
bottomValues.push(yRange[1])
}
else if(element.type === 'line') {
leftValues.push(left)
topValues.push(top)
rightValues.push(left + Math.max(element.start[0], element.end[0]))
bottomValues.push(top + Math.max(element.start[1], element.end[1]))
}
else {
leftValues.push(left)
topValues.push(top)
rightValues.push(left + width)
bottomValues.push(top + height)
}
}
targetMinX = Math.min(...leftValues)
targetMaxX = Math.max(...rightValues)
targetMinY = Math.min(...topValues)
targetMaxY = Math.max(...bottomValues)
}
const targetCenterX = targetMinX + (targetMaxX - targetMinX) / 2
const targetCenterY = targetMinY + (targetMaxY - targetMinY) / 2
// 线
const _alignmentLines: AlignmentLineProps[] = []
let isVerticalAdsorbed = false
let isHorizontalAdsorbed = false
for(let i = 0; i < horizontalLines.length; i++) {
const { value, range } = horizontalLines[i]
const min = Math.min(...range, targetMinX, targetMaxX)
const max = Math.max(...range, targetMinX, targetMaxX)
if(Math.abs(targetMinY - value) < sorptionRange) {
if(!isHorizontalAdsorbed) {
targetTop = targetTop - (targetMinY - value)
isHorizontalAdsorbed = true
}
_alignmentLines.push({type: 'horizontal', axis: {x: min - 20, y: value}, length: max - min + 40})
}
if(Math.abs(targetMaxY - value) < sorptionRange) {
if(!isHorizontalAdsorbed) {
targetTop = targetTop - (targetMaxY - value)
isHorizontalAdsorbed = true
}
_alignmentLines.push({type: 'horizontal', axis: {x: min - 20, y: value}, length: max - min + 40})
}
if(Math.abs(targetCenterY - value) < sorptionRange) {
if(!isHorizontalAdsorbed) {
targetTop = targetTop - (targetCenterY - value)
isHorizontalAdsorbed = true
}
_alignmentLines.push({type: 'horizontal', axis: {x: min - 20, y: value}, length: max - min + 40})
}
}
for(let i = 0; i < verticalLines.length; i++) {
const { value, range } = verticalLines[i]
const min = Math.min(...range, targetMinY, targetMaxY)
const max = Math.max(...range, targetMinY, targetMaxY)
if(Math.abs(targetMinX - value) < sorptionRange) {
if(!isVerticalAdsorbed) {
targetLeft = targetLeft - (targetMinX - value)
isVerticalAdsorbed = true
}
_alignmentLines.push({type: 'vertical', axis: {x: value, y: min - 20}, length: max - min + 40})
}
if(Math.abs(targetMaxX - value) < sorptionRange) {
if(!isVerticalAdsorbed) {
targetLeft = targetLeft - (targetMaxX - value)
isVerticalAdsorbed = true
}
_alignmentLines.push({type: 'vertical', axis: {x: value, y: min - 20}, length: max - min + 40})
}
if(Math.abs(targetCenterX - value) < sorptionRange) {
if(!isVerticalAdsorbed) {
targetLeft = targetLeft - (targetCenterX - value)
isVerticalAdsorbed = true
}
_alignmentLines.push({type: 'vertical', axis: {x: value, y: min - 20}, length: max - min + 40})
}
}
alignmentLines.value = _alignmentLines
//
if(activeElementIdList.value.length === 1 || isActiveGroupElement) {
elementList.value = elementList.value.map(el => {
return el.elId === element.elId ? { ...el, left: targetLeft, top: targetTop } : el
})
}
//
//
else {
const handleElement = elementList.value.find(el => el.elId === element.elId)
if(!handleElement) return
elementList.value = elementList.value.map(el => {
const newEl = el
activeElementIdList.value.includes(el.elId) ? { ...el, left: targetLeft, top: targetTop } : el
if(activeElementIdList.value.includes(el.elId)) {
if(el.elId === element.elId) {
newEl.left = targetLeft
newEl.top = targetTop
}
else {
newEl.left = newEl.left + (targetLeft - handleElement.left)
newEl.top = newEl.top + (targetTop - handleElement.top)
}
}
return newEl
})
}
}
document.onmouseup = e => {
isMouseDown = false
document.onmousemove = null
document.onmouseup = null
alignmentLines.value = []
const currentPageX = e.pageX
const currentPageY = e.pageY
//
if(startPageX === currentPageX && startPageY === currentPageY) return
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
}
}
const selectElement = (e: MouseEvent, element: PPTElement, canMove = true) => {

View File

@ -1,7 +1,14 @@
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
import { PPTElement } from '@/types/slides'
// 获取矩形旋转后在画布中的位置范围
export const getRectRotatedRange = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => {
interface RotatedElementData {
left: number;
top: number;
width: number;
height: number;
rotate: number;
}
export const getRectRotatedRange = (element: RotatedElementData) => {
const { left, top, width, height, rotate = 0 } = element
const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2
@ -46,7 +53,8 @@ export const getElementRange = (element: PPTElement) => {
maxY = element.top + Math.max(element.start[1], element.end[1])
}
else if('rotate' in element && element.rotate) {
const { xRange, yRange } = getRectRotatedRange(element)
const { left, top, width, height, rotate } = element
const { xRange, yRange } = getRectRotatedRange({ left, top, width, height, rotate })
minX = xRange[0]
maxX = xRange[1]
minY = yRange[0]