mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
update
This commit is contained in:
parent
071c608fcf
commit
8fa35d4645
@ -4,7 +4,6 @@ export enum MutationTypes {
|
||||
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
||||
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
||||
SET_EDITOR_AREA_SHOW_SCALE = 'setEditorAreaShowScale',
|
||||
SET_CANVAS_SCALE = 'setCanvasScale',
|
||||
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
||||
SET_EDITORAREA_FOCUS = 'setEditorAreaFocus',
|
||||
SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
|
||||
|
@ -13,7 +13,6 @@ export interface State {
|
||||
activeElementIdList: string[];
|
||||
handleElementId: string;
|
||||
editorAreaShowScale: number;
|
||||
canvasScale: number;
|
||||
thumbnailsFocus: boolean;
|
||||
editorAreaFocus: boolean;
|
||||
disableHotkeys: boolean;
|
||||
@ -30,7 +29,6 @@ const state: State = {
|
||||
activeElementIdList: [],
|
||||
handleElementId: '',
|
||||
editorAreaShowScale: 85,
|
||||
canvasScale: 1,
|
||||
thumbnailsFocus: false,
|
||||
editorAreaFocus: false,
|
||||
disableHotkeys: false,
|
||||
|
@ -34,10 +34,6 @@ export const mutations: MutationTree<State> = {
|
||||
state.editorAreaShowScale = scale
|
||||
},
|
||||
|
||||
[MutationTypes.SET_CANVAS_SCALE](state, scale: number) {
|
||||
state.canvasScale = scale
|
||||
},
|
||||
|
||||
[MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus: boolean) {
|
||||
state.thumbnailsFocus = isFocus
|
||||
},
|
||||
|
@ -41,6 +41,10 @@ export default defineComponent({
|
||||
BorderLine,
|
||||
},
|
||||
props: {
|
||||
canvasScale: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
elementList: {
|
||||
type: Array as PropType<PPTElement[]>,
|
||||
required: true,
|
||||
@ -52,7 +56,6 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore<State>()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.elId)))
|
||||
|
||||
@ -63,8 +66,8 @@ export default defineComponent({
|
||||
maxY: 0,
|
||||
})
|
||||
|
||||
const width = computed(() => (range.maxX - range.minX) * canvasScale.value)
|
||||
const height = computed(() => (range.maxY - range.minY) * canvasScale.value)
|
||||
const width = computed(() => (range.maxX - range.minX) * props.canvasScale)
|
||||
const height = computed(() => (range.maxY - range.minY) * props.canvasScale)
|
||||
|
||||
const resizablePoints = computed(() => {
|
||||
return [
|
||||
@ -110,7 +113,6 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
...toRefs(range),
|
||||
canvasScale,
|
||||
borderLines,
|
||||
disableResizablePoint,
|
||||
resizablePoints,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
@ -6,9 +6,12 @@ import { ElementAlignCommand, ElementAlignCommands } from '@/types/edit'
|
||||
import { getElementListRange } from '../utils/elementRange'
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, activeElementList: Ref<PPTElement[]>, activeElementIdList: Ref<string[]>) => {
|
||||
export default (elementList: Ref<PPTElement[]>) => {
|
||||
const store = useStore<State>()
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList: Ref<PPTElement[]> = computed(() => store.getters.activeElementList)
|
||||
|
||||
const alignElementToCanvas = (command: ElementAlignCommand) => {
|
||||
const viewportWidth = VIEWPORT_SIZE
|
||||
const viewportHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, activeElementList: Ref<PPTElement[]>, activeElementIdList: Ref<string[]>) => {
|
||||
export default (elementList: Ref<PPTElement[]>) => {
|
||||
const store = useStore<State>()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList: Ref<PPTElement[]> = computed(() => store.getters.activeElementList)
|
||||
|
||||
// 组合元素(为当前所有激活元素添加一个相同的groupId)
|
||||
const combineElements = () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
@ -6,8 +6,10 @@ import { copyText, readClipboard } from '@/utils/clipboard'
|
||||
import { encrypt, decrypt } from '@/utils/crypto'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export default (deleteElement: () => void, activeElementList: Ref<PPTElement[]>, activeElementIdList: Ref<string[]>) => {
|
||||
export default (deleteElement: () => void) => {
|
||||
const store = useStore<State>()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList: Ref<PPTElement[]> = computed(() => store.getters.activeElementList)
|
||||
|
||||
const copyElement = () => {
|
||||
if(!activeElementIdList.value.length) return
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, activeElementIdList: Ref<string[]>) => {
|
||||
export default (elementList: Ref<PPTElement[]>) => {
|
||||
const store = useStore<State>()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
|
||||
const deleteElement = () => {
|
||||
if(!activeElementIdList.value.length) return
|
||||
|
@ -1,14 +1,17 @@
|
||||
import { ref, onMounted, onUnmounted, Ref } from 'vue'
|
||||
import { onMounted, onUnmounted, Ref } from 'vue'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
|
||||
export default (elementRef: Ref<HTMLElement | null>) => {
|
||||
const imageFile = ref<File | null>(null)
|
||||
|
||||
const handleDrop = (e: DragEvent) => {
|
||||
if(!e.dataTransfer) return
|
||||
const file = e.dataTransfer.items[0]
|
||||
if( file.kind === 'file' && file.type.indexOf('image') !== -1 ) {
|
||||
const _imageFile = file.getAsFile()
|
||||
if(_imageFile) imageFile.value = _imageFile
|
||||
const imageFile = file.getAsFile()
|
||||
if(imageFile) {
|
||||
getImageDataURL(imageFile).then(dataURL => {
|
||||
console.log(dataURL)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +31,4 @@ export default (elementRef: Ref<HTMLElement | null>) => {
|
||||
document.ondragenter = null
|
||||
document.ondragover = null
|
||||
})
|
||||
|
||||
return imageFile
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
import { useStore } from 'vuex'
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, activeElementIdList: Ref<string[]>) => {
|
||||
export default (elementList: Ref<PPTElement[]>) => {
|
||||
const store = useStore<State>()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
|
||||
const lockElement = (handleElement: PPTElement) => {
|
||||
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList.value))
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Ref } from 'vue'
|
||||
import { Ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
@ -9,12 +9,12 @@ import { AlignLine, uniqAlignLines } from '../utils/alignLines'
|
||||
|
||||
export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
activeElementIdList: Ref<string[]>,
|
||||
activeGroupElementId: Ref<string>,
|
||||
canvasScale: Ref<number>,
|
||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||
) => {
|
||||
const store = useStore<State>()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
|
||||
const moveElement = (e: MouseEvent, element: PPTElement) => {
|
||||
if(!activeElementIdList.value.includes(element.elId)) return
|
||||
|
@ -2,7 +2,15 @@ import { Ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
|
||||
import { getAngleFromCoordinate } from '../utils/elementRotate'
|
||||
|
||||
// 给定一个坐标,计算该坐标到(0, 0)点连线的弧度值
|
||||
// 注意,Math.atan2的一般用法是Math.atan2(y, x)返回的是原点(0,0)到(x,y)点的线段与X轴正方向之间的弧度值
|
||||
// 这里将使用时将x与y的传入顺序交换了,为的是获取原点(0,0)到(x,y)点的线段与Y轴正方向之间的弧度值
|
||||
export const getAngleFromCoordinate = (x: number, y: number) => {
|
||||
const radian = Math.atan2(x, y)
|
||||
const angle = 180 / Math.PI * radian
|
||||
return angle
|
||||
}
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>, canvasScale: Ref<number>) => {
|
||||
const store = useStore<State>()
|
||||
|
@ -4,19 +4,93 @@ import { State, MutationTypes } from '@/store'
|
||||
import { ElementTypes, PPTElement, PPTLineElement } from '@/types/slides'
|
||||
import { OPERATE_KEYS, ElementScaleHandler } from '@/types/edit'
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
import { getRotateElementPoints, getOppositePoint } from '../utils/elementRotate'
|
||||
import { AlignLine, uniqAlignLines } from '../utils/alignLines'
|
||||
import { AlignmentLineProps, MultiSelectRange } from '../types/index'
|
||||
|
||||
// 计算元素被旋转一定角度后,八个操作点的新坐标
|
||||
interface RotateElementData {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
export const getRotateElementPoints = (element: RotateElementData, angle: number) => {
|
||||
const { left, top, width, height } = element
|
||||
|
||||
const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2
|
||||
const auxiliaryAngle = Math.atan(height / width) * 180 / Math.PI
|
||||
|
||||
const tlbraRadian = (180 - angle - auxiliaryAngle) * Math.PI / 180
|
||||
const trblaRadian = (auxiliaryAngle - angle) * Math.PI / 180
|
||||
const taRadian = (90 - angle) * Math.PI / 180
|
||||
const raRadian = angle * Math.PI / 180
|
||||
|
||||
const halfWidth = width / 2
|
||||
const halfHeight = height / 2
|
||||
|
||||
const middleLeft = left + halfWidth
|
||||
const middleTop = top + halfHeight
|
||||
|
||||
const leftTopPoint = {
|
||||
left: middleLeft + radius * Math.cos(tlbraRadian),
|
||||
top: middleTop - radius * Math.sin(tlbraRadian),
|
||||
}
|
||||
const topPoint = {
|
||||
left: middleLeft + halfHeight * Math.cos(taRadian),
|
||||
top: middleTop - halfHeight * Math.sin(taRadian),
|
||||
}
|
||||
const rightTopPoint = {
|
||||
left: middleLeft + radius * Math.cos(trblaRadian),
|
||||
top: middleTop - radius * Math.sin(trblaRadian),
|
||||
}
|
||||
const rightPoint = {
|
||||
left: middleLeft + halfWidth * Math.cos(raRadian),
|
||||
top: middleTop + halfWidth * Math.sin(raRadian),
|
||||
}
|
||||
const rightBottomPoint = {
|
||||
left: middleLeft - radius * Math.cos(tlbraRadian),
|
||||
top: middleTop + radius * Math.sin(tlbraRadian),
|
||||
}
|
||||
const bottomPoint = {
|
||||
left: middleLeft - halfHeight * Math.sin(raRadian),
|
||||
top: middleTop + halfHeight * Math.cos(raRadian),
|
||||
}
|
||||
const leftBottomPoint = {
|
||||
left: middleLeft - radius * Math.cos(trblaRadian),
|
||||
top: middleTop + radius * Math.sin(trblaRadian),
|
||||
}
|
||||
const leftPoint = {
|
||||
left: middleLeft - halfWidth * Math.cos(raRadian),
|
||||
top: middleTop - halfWidth * Math.sin(raRadian),
|
||||
}
|
||||
|
||||
return { leftTopPoint, topPoint, rightTopPoint, rightPoint, rightBottomPoint, bottomPoint, leftBottomPoint, leftPoint }
|
||||
}
|
||||
|
||||
// 获取元素某个操作点对角线上另一端的操作点坐标(例如:左上 <-> 右下)
|
||||
export const getOppositePoint = (direction: number, points: ReturnType<typeof getRotateElementPoints>): { left: number; top: number } => {
|
||||
const oppositeMap = {
|
||||
[OPERATE_KEYS.RIGHT_BOTTOM]: points.leftTopPoint,
|
||||
[OPERATE_KEYS.LEFT_BOTTOM]: points.rightTopPoint,
|
||||
[OPERATE_KEYS.LEFT_TOP]: points.rightBottomPoint,
|
||||
[OPERATE_KEYS.RIGHT_TOP]: points.leftBottomPoint,
|
||||
[OPERATE_KEYS.TOP]: points.bottomPoint,
|
||||
[OPERATE_KEYS.BOTTOM]: points.topPoint,
|
||||
[OPERATE_KEYS.LEFT]: points.rightPoint,
|
||||
[OPERATE_KEYS.RIGHT]: points.leftPoint,
|
||||
}
|
||||
return oppositeMap[direction]
|
||||
}
|
||||
|
||||
export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
canvasScale: Ref<number>,
|
||||
activeGroupElementId: Ref<string>,
|
||||
activeElementIdList: Ref<string[]>,
|
||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||
) => {
|
||||
const store = useStore<State>()
|
||||
const ctrlOrShiftKeyActive = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
|
||||
const scaleElement = (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: ElementScaleHandler) => {
|
||||
let isMouseDown = true
|
||||
|
@ -6,14 +6,14 @@ import { PPTElement } from '@/types/slides'
|
||||
|
||||
export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
activeElementIdList: Ref<string[]>,
|
||||
activeGroupElementId: Ref<string>,
|
||||
editorAreaFocus: Ref<boolean>,
|
||||
handleElementId: Ref<string>,
|
||||
moveElement: (e: MouseEvent, element: PPTElement) => void,
|
||||
) => {
|
||||
const store = useStore<State>()
|
||||
const ctrlOrShiftKeyActive = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
|
||||
const selectElement = (e: MouseEvent, element: PPTElement, canMove = true) => {
|
||||
if(!editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||
|
@ -30,6 +30,13 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
|
||||
}
|
||||
}
|
||||
|
||||
const viewportStyles = computed(() => ({
|
||||
width: VIEWPORT_SIZE,
|
||||
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
|
||||
left: viewportLeft.value,
|
||||
top: viewportTop.value,
|
||||
}))
|
||||
|
||||
const resizeObserver = new ResizeObserver(setViewportSize)
|
||||
|
||||
onMounted(() => {
|
||||
@ -41,7 +48,6 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
|
||||
|
||||
return {
|
||||
canvasScale,
|
||||
viewportLeft,
|
||||
viewportTop,
|
||||
viewportStyles,
|
||||
}
|
||||
}
|
@ -40,11 +40,13 @@
|
||||
v-if="activeElementIdList.length > 1"
|
||||
:elementList="elementList"
|
||||
:scaleMultiElement="scaleMultiElement"
|
||||
:canvasScale="canvasScale"
|
||||
/>
|
||||
|
||||
<EditableElement
|
||||
v-for="(element, index) in elementList"
|
||||
:key="element.elId"
|
||||
:canvasScale="canvasScale"
|
||||
:elementInfo="element"
|
||||
:elementIndex="index + 1"
|
||||
:isActive="activeElementIdList.includes(element.elId)"
|
||||
@ -69,17 +71,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch, watchEffect } from 'vue'
|
||||
import { computed, defineComponent, Ref, ref, watch, watchEffect } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State, MutationTypes } from '@/store'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { AlignmentLineProps } from './types/index'
|
||||
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
|
||||
import useDropImage from '@/hooks/useDropImage'
|
||||
import useViewportSize from './hooks/useViewportSize'
|
||||
import useLockElement from './hooks/useLockElement'
|
||||
import useDeleteElement from './hooks/useDeleteElement'
|
||||
@ -92,6 +90,7 @@ import useScaleElement from './hooks/useScaleElement'
|
||||
import useSelectElement from './hooks/useSelectElement'
|
||||
import useMoveElement from './hooks/useMoveElement'
|
||||
import useMouseSelection from './hooks/useMouseSelection'
|
||||
import useDropImageElement from './hooks/useDropImageElement'
|
||||
|
||||
import EditableElement from '@/views/_common/_element/EditableElement.vue'
|
||||
import MouseSelection from './MouseSelection.vue'
|
||||
@ -112,10 +111,9 @@ export default defineComponent({
|
||||
const store = useStore<State>()
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed(() => store.getters.activeElementList)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const ctrlOrShiftKeyActive = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||
|
||||
const viewportRef = ref<HTMLElement | null>(null)
|
||||
const isShowGridLines = ref(false)
|
||||
@ -131,26 +129,24 @@ export default defineComponent({
|
||||
}
|
||||
watchEffect(setLocalElementList)
|
||||
|
||||
const dropImageFile = useDropImage(viewportRef)
|
||||
watch(dropImageFile, () => {
|
||||
if(dropImageFile.value) {
|
||||
getImageDataURL(dropImageFile.value).then(dataURL => {
|
||||
console.log(dataURL)
|
||||
})
|
||||
}
|
||||
})
|
||||
useDropImageElement(viewportRef)
|
||||
|
||||
const canvasRef = ref<HTMLElement | null>(null)
|
||||
const { canvasScale, viewportLeft, viewportTop } = useViewportSize(canvasRef)
|
||||
const viewportStyles = computed(() => ({
|
||||
width: VIEWPORT_SIZE,
|
||||
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
|
||||
left: viewportLeft.value,
|
||||
top: viewportTop.value,
|
||||
}))
|
||||
const { canvasScale, viewportStyles } = useViewportSize(canvasRef)
|
||||
|
||||
const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef, canvasScale)
|
||||
|
||||
const { moveElement } = useMoveElement(elementList, activeGroupElementId, canvasScale, alignmentLines)
|
||||
const { selectElement, selectAllElement } = useSelectElement(elementList, activeGroupElementId, moveElement)
|
||||
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, canvasScale, activeGroupElementId, alignmentLines)
|
||||
const { rotateElement } = useRotateElement(elementList, viewportRef, canvasScale)
|
||||
const { orderElement } = useOrderElement(elementList)
|
||||
const { alignElementToCanvas } = useAlignElementToCanvas(elementList)
|
||||
const { combineElements, uncombineElements } = useCombineElement(elementList)
|
||||
const { deleteElement, deleteAllElements } = useDeleteElement(elementList)
|
||||
const { lockElement, unlockElement } = useLockElement(elementList)
|
||||
const { copyElement, cutElement, pasteElement } = useCopyAndPasteElement(deleteElement)
|
||||
|
||||
const handleClickBlankArea = (e: MouseEvent) => {
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
if(!ctrlOrShiftKeyActive.value) updateMouseSelection(e)
|
||||
@ -161,17 +157,6 @@ export default defineComponent({
|
||||
if(editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
||||
}
|
||||
|
||||
const { moveElement } = useMoveElement(elementList, activeElementIdList, activeGroupElementId, canvasScale, alignmentLines)
|
||||
const { selectElement, selectAllElement } = useSelectElement(elementList, activeElementIdList, activeGroupElementId, editorAreaFocus, handleElementId, moveElement)
|
||||
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, canvasScale, activeGroupElementId, activeElementIdList, alignmentLines)
|
||||
const { rotateElement } = useRotateElement(elementList, viewportRef, canvasScale)
|
||||
const { orderElement } = useOrderElement(elementList)
|
||||
const { alignElementToCanvas } = useAlignElementToCanvas(elementList, activeElementList, activeElementIdList)
|
||||
const { combineElements, uncombineElements } = useCombineElement(elementList, activeElementList, activeElementIdList)
|
||||
const { deleteElement, deleteAllElements } = useDeleteElement(elementList, activeElementIdList)
|
||||
const { lockElement, unlockElement } = useLockElement(elementList, activeElementIdList)
|
||||
const { copyElement, cutElement, pasteElement } = useCopyAndPasteElement(deleteElement, activeElementList, activeElementIdList)
|
||||
|
||||
const contextmenus = (): ContextmenuItem[] => {
|
||||
return [
|
||||
{
|
||||
@ -194,7 +179,6 @@ export default defineComponent({
|
||||
return {
|
||||
elementList,
|
||||
activeElementIdList,
|
||||
activeElementList,
|
||||
handleElementId,
|
||||
activeGroupElementId,
|
||||
canvasRef,
|
||||
|
@ -1,85 +0,0 @@
|
||||
import { OPERATE_KEYS } from '@/types/edit'
|
||||
|
||||
// 给定一个坐标,计算该坐标到(0, 0)点连线的弧度值
|
||||
// 注意,Math.atan2的一般用法是Math.atan2(y, x)返回的是原点(0,0)到(x,y)点的线段与X轴正方向之间的弧度值
|
||||
// 这里将使用时将x与y的传入顺序交换了,为的是获取原点(0,0)到(x,y)点的线段与Y轴正方向之间的弧度值
|
||||
export const getAngleFromCoordinate = (x: number, y: number) => {
|
||||
const radian = Math.atan2(x, y)
|
||||
const angle = 180 / Math.PI * radian
|
||||
return angle
|
||||
}
|
||||
|
||||
// 计算元素被旋转一定角度后,八个操作点的新坐标
|
||||
interface RotateElementData {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
export const getRotateElementPoints = (element: RotateElementData, angle: number) => {
|
||||
const { left, top, width, height } = element
|
||||
|
||||
const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2
|
||||
const auxiliaryAngle = Math.atan(height / width) * 180 / Math.PI
|
||||
|
||||
const tlbraRadian = (180 - angle - auxiliaryAngle) * Math.PI / 180
|
||||
const trblaRadian = (auxiliaryAngle - angle) * Math.PI / 180
|
||||
const taRadian = (90 - angle) * Math.PI / 180
|
||||
const raRadian = angle * Math.PI / 180
|
||||
|
||||
const halfWidth = width / 2
|
||||
const halfHeight = height / 2
|
||||
|
||||
const middleLeft = left + halfWidth
|
||||
const middleTop = top + halfHeight
|
||||
|
||||
const leftTopPoint = {
|
||||
left: middleLeft + radius * Math.cos(tlbraRadian),
|
||||
top: middleTop - radius * Math.sin(tlbraRadian),
|
||||
}
|
||||
const topPoint = {
|
||||
left: middleLeft + halfHeight * Math.cos(taRadian),
|
||||
top: middleTop - halfHeight * Math.sin(taRadian),
|
||||
}
|
||||
const rightTopPoint = {
|
||||
left: middleLeft + radius * Math.cos(trblaRadian),
|
||||
top: middleTop - radius * Math.sin(trblaRadian),
|
||||
}
|
||||
const rightPoint = {
|
||||
left: middleLeft + halfWidth * Math.cos(raRadian),
|
||||
top: middleTop + halfWidth * Math.sin(raRadian),
|
||||
}
|
||||
const rightBottomPoint = {
|
||||
left: middleLeft - radius * Math.cos(tlbraRadian),
|
||||
top: middleTop + radius * Math.sin(tlbraRadian),
|
||||
}
|
||||
const bottomPoint = {
|
||||
left: middleLeft - halfHeight * Math.sin(raRadian),
|
||||
top: middleTop + halfHeight * Math.cos(raRadian),
|
||||
}
|
||||
const leftBottomPoint = {
|
||||
left: middleLeft - radius * Math.cos(trblaRadian),
|
||||
top: middleTop + radius * Math.sin(trblaRadian),
|
||||
}
|
||||
const leftPoint = {
|
||||
left: middleLeft - halfWidth * Math.cos(raRadian),
|
||||
top: middleTop - halfWidth * Math.sin(raRadian),
|
||||
}
|
||||
|
||||
return { leftTopPoint, topPoint, rightTopPoint, rightPoint, rightBottomPoint, bottomPoint, leftBottomPoint, leftPoint }
|
||||
}
|
||||
|
||||
// 获取元素某个操作点对角线上另一端的操作点坐标(例如:左上 <-> 右下)
|
||||
export const getOppositePoint = (direction: number, points: ReturnType<typeof getRotateElementPoints>): { left: number; top: number } => {
|
||||
const oppositeMap = {
|
||||
[OPERATE_KEYS.RIGHT_BOTTOM]: points.leftTopPoint,
|
||||
[OPERATE_KEYS.LEFT_BOTTOM]: points.rightTopPoint,
|
||||
[OPERATE_KEYS.LEFT_TOP]: points.rightBottomPoint,
|
||||
[OPERATE_KEYS.RIGHT_TOP]: points.leftBottomPoint,
|
||||
[OPERATE_KEYS.TOP]: points.bottomPoint,
|
||||
[OPERATE_KEYS.BOTTOM]: points.topPoint,
|
||||
[OPERATE_KEYS.LEFT]: points.rightPoint,
|
||||
[OPERATE_KEYS.RIGHT]: points.leftPoint,
|
||||
}
|
||||
return oppositeMap[direction]
|
||||
}
|
@ -7,8 +7,8 @@
|
||||
>
|
||||
<component
|
||||
:is="currentElementComponent"
|
||||
:elementInfo="elementInfo"
|
||||
:canvasScale="canvasScale"
|
||||
:elementInfo="elementInfo"
|
||||
:isActive="isActive"
|
||||
:isHandleEl="isHandleEl"
|
||||
:isActiveGroupElement="isActiveGroupElement"
|
||||
@ -24,8 +24,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State } from '@/store'
|
||||
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTLineElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
|
||||
@ -43,6 +41,10 @@ import TextElement from './TextElement/index.vue'
|
||||
export default defineComponent({
|
||||
name: 'editable-element',
|
||||
props: {
|
||||
canvasScale: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
elementInfo: {
|
||||
type: Object as PropType<PPTElement>,
|
||||
required: true,
|
||||
@ -121,9 +123,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore<State>()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
'image': ImageElement,
|
||||
@ -209,7 +208,6 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
canvasScale,
|
||||
currentElementComponent,
|
||||
contextmenus,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user