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
845cecd553
commit
8ff1500b53
@ -18,7 +18,6 @@
|
|||||||
"mitt": "^2.1.0",
|
"mitt": "^2.1.0",
|
||||||
"store2": "^2.12.0",
|
"store2": "^2.12.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-router": "^4.0.0-0",
|
|
||||||
"vuedraggable": "^4.0.1",
|
"vuedraggable": "^4.0.1",
|
||||||
"vuex": "^4.0.0-0"
|
"vuex": "^4.0.0-0"
|
||||||
},
|
},
|
||||||
@ -31,7 +30,6 @@
|
|||||||
"@typescript-eslint/parser": "^2.33.0",
|
"@typescript-eslint/parser": "^2.33.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
"@vue/cli-plugin-router": "~4.5.0",
|
|
||||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||||
"@vue/cli-plugin-unit-jest": "~4.5.0",
|
"@vue/cli-plugin-unit-jest": "~4.5.0",
|
||||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-view/>
|
<Editor />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -7,8 +7,13 @@ import { defineComponent, onMounted } from 'vue'
|
|||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { MutationTypes, ActionTypes, State } from '@/store'
|
import { MutationTypes, ActionTypes, State } from '@/store'
|
||||||
|
|
||||||
|
import Editor from './views/Editor/index.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'app',
|
name: 'app',
|
||||||
|
components: {
|
||||||
|
Editor,
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
|
|
||||||
|
23
src/hooks/useScaleCanvas.ts
Normal file
23
src/hooks/useScaleCanvas.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { computed } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { MutationTypes, State } from '@/store'
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const store = useStore<State>()
|
||||||
|
const canvasPercentage = computed(() => store.state.canvasPercentage)
|
||||||
|
|
||||||
|
const scaleCanvas = (command: '+' | '-') => {
|
||||||
|
let percentage = canvasPercentage.value
|
||||||
|
const step = 5
|
||||||
|
const max = 120
|
||||||
|
const min = 60
|
||||||
|
if(command === '+' && percentage <= max) percentage += step
|
||||||
|
if(command === '-' && percentage >= min) percentage -= step
|
||||||
|
|
||||||
|
store.commit(MutationTypes.SET_CANVAS_PERCENTAGE, percentage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
scaleCanvas,
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
|
||||||
import '@/assets/styles/global.scss'
|
import '@/assets/styles/global.scss'
|
||||||
@ -14,5 +13,4 @@ app.component('IconFont', IconFont)
|
|||||||
app.use(contextmenu)
|
app.use(contextmenu)
|
||||||
app.use(clickOutside)
|
app.use(clickOutside)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(router)
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
|
||||||
import Editor from '@/views/Editor/index.vue'
|
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'Editor',
|
|
||||||
component: Editor,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/player',
|
|
||||||
name: 'Player',
|
|
||||||
component: () => import(/* webpackChunkName: "Player" */ '@/views/Player/index.vue'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = createRouter({
|
|
||||||
history: createWebHistory(process.env.BASE_URL),
|
|
||||||
routes,
|
|
||||||
})
|
|
||||||
|
|
||||||
router.beforeEach((to, from) => {
|
|
||||||
if(to.name === 'Player' && from.name !== 'Editor') {
|
|
||||||
return router.push({ path: '/' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default router
|
|
@ -3,10 +3,12 @@ export enum MutationTypes {
|
|||||||
// editor
|
// editor
|
||||||
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
||||||
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
||||||
SET_EDITOR_AREA_SHOW_SCALE = 'setEditorAreaShowScale',
|
SET_CANVAS_PERCENTAGE = 'setCanvasPercentage',
|
||||||
|
SET_CANVAS_SCALE = 'setCanvasScale',
|
||||||
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
||||||
SET_EDITORAREA_FOCUS = 'setEditorAreaFocus',
|
SET_EDITORAREA_FOCUS = 'setEditorAreaFocus',
|
||||||
SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
|
SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
|
||||||
|
SET_GRID_LINES_STATE = 'setGridLinesState',
|
||||||
SET_AVAILABLE_FONTS = 'setAvailableFonts',
|
SET_AVAILABLE_FONTS = 'setAvailableFonts',
|
||||||
|
|
||||||
// slides
|
// slides
|
||||||
|
@ -13,10 +13,12 @@ export { MutationTypes, ActionTypes }
|
|||||||
export interface State {
|
export interface State {
|
||||||
activeElementIdList: string[];
|
activeElementIdList: string[];
|
||||||
handleElementId: string;
|
handleElementId: string;
|
||||||
editorAreaShowScale: number;
|
canvasPercentage: number;
|
||||||
|
canvasScale: number;
|
||||||
thumbnailsFocus: boolean;
|
thumbnailsFocus: boolean;
|
||||||
editorAreaFocus: boolean;
|
editorAreaFocus: boolean;
|
||||||
disableHotkeys: boolean;
|
disableHotkeys: boolean;
|
||||||
|
showGridLines: boolean;
|
||||||
availableFonts: FontName[];
|
availableFonts: FontName[];
|
||||||
slides: Slide[];
|
slides: Slide[];
|
||||||
slideIndex: number;
|
slideIndex: number;
|
||||||
@ -29,10 +31,12 @@ export interface State {
|
|||||||
const state: State = {
|
const state: State = {
|
||||||
activeElementIdList: [],
|
activeElementIdList: [],
|
||||||
handleElementId: '',
|
handleElementId: '',
|
||||||
editorAreaShowScale: 90,
|
canvasPercentage: 90,
|
||||||
|
canvasScale: 1,
|
||||||
thumbnailsFocus: false,
|
thumbnailsFocus: false,
|
||||||
editorAreaFocus: false,
|
editorAreaFocus: false,
|
||||||
disableHotkeys: false,
|
disableHotkeys: false,
|
||||||
|
showGridLines: false,
|
||||||
availableFonts: [],
|
availableFonts: [],
|
||||||
slides: slides,
|
slides: slides,
|
||||||
slideIndex: 0,
|
slideIndex: 0,
|
||||||
|
@ -5,11 +5,6 @@ import { Slide, PPTElement } from '@/types/slides'
|
|||||||
import { FONT_NAMES } from '@/configs/fontName'
|
import { FONT_NAMES } from '@/configs/fontName'
|
||||||
import { isSupportFontFamily } from '@/utils/fontFamily'
|
import { isSupportFontFamily } from '@/utils/fontFamily'
|
||||||
|
|
||||||
interface AddSlideData {
|
|
||||||
index?: number;
|
|
||||||
slide: Slide | Slide[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UpdateElementData {
|
interface UpdateElementData {
|
||||||
elId: string | string[];
|
elId: string | string[];
|
||||||
props: Partial<PPTElement>;
|
props: Partial<PPTElement>;
|
||||||
@ -30,8 +25,12 @@ export const mutations: MutationTree<State> = {
|
|||||||
state.handleElementId = handleElementId
|
state.handleElementId = handleElementId
|
||||||
},
|
},
|
||||||
|
|
||||||
[MutationTypes.SET_EDITOR_AREA_SHOW_SCALE](state, scale: number) {
|
[MutationTypes.SET_CANVAS_PERCENTAGE](state, percentage: number) {
|
||||||
state.editorAreaShowScale = scale
|
state.canvasPercentage = percentage
|
||||||
|
},
|
||||||
|
|
||||||
|
[MutationTypes.SET_CANVAS_SCALE](state, scale: number) {
|
||||||
|
state.canvasScale = scale
|
||||||
},
|
},
|
||||||
|
|
||||||
[MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus: boolean) {
|
[MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus: boolean) {
|
||||||
@ -46,6 +45,10 @@ export const mutations: MutationTree<State> = {
|
|||||||
state.disableHotkeys = disable
|
state.disableHotkeys = disable
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[MutationTypes.SET_GRID_LINES_STATE](state, show: boolean) {
|
||||||
|
state.showGridLines = show
|
||||||
|
},
|
||||||
|
|
||||||
[MutationTypes.SET_AVAILABLE_FONTS](state) {
|
[MutationTypes.SET_AVAILABLE_FONTS](state) {
|
||||||
state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en))
|
state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en))
|
||||||
},
|
},
|
||||||
|
@ -39,10 +39,6 @@ export default defineComponent({
|
|||||||
BorderLine,
|
BorderLine,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
canvasScale: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
elementList: {
|
elementList: {
|
||||||
type: Array as PropType<PPTElement[]>,
|
type: Array as PropType<PPTElement[]>,
|
||||||
required: true,
|
required: true,
|
||||||
@ -55,6 +51,7 @@ export default defineComponent({
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.elId)))
|
const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.elId)))
|
||||||
|
|
||||||
const range = reactive({
|
const range = reactive({
|
||||||
@ -64,8 +61,8 @@ export default defineComponent({
|
|||||||
maxY: 0,
|
maxY: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const width = computed(() => (range.maxX - range.minX) * props.canvasScale)
|
const width = computed(() => (range.maxX - range.minX) * canvasScale.value)
|
||||||
const height = computed(() => (range.maxY - range.minY) * props.canvasScale)
|
const height = computed(() => (range.maxY - range.minY) * canvasScale.value)
|
||||||
|
|
||||||
const resizablePoints = computed(() => {
|
const resizablePoints = computed(() => {
|
||||||
return [
|
return [
|
||||||
|
@ -3,36 +3,34 @@
|
|||||||
class="slide-background"
|
class="slide-background"
|
||||||
:style="backgroundStyle"
|
:style="backgroundStyle"
|
||||||
>
|
>
|
||||||
<template v-if="isShowGridLines">
|
<template v-if="showGridLines">
|
||||||
<GridLines />
|
<GridLines />
|
||||||
<GridLines :gridSize="100" gridColor="rgba(100, 100, 100, 0.3)" />
|
<GridLines :gridSize="100" gridColor="rgba(100, 100, 100, 0.3)" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue'
|
import { Ref, computed, defineComponent } from 'vue'
|
||||||
import GridLines from './GridLines'
|
import { useStore } from 'vuex'
|
||||||
|
import { State } from '@/store'
|
||||||
|
import { Slide } from '@/types/slides'
|
||||||
|
import GridLines from './GridLines.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'slide-background',
|
name: 'slide-background',
|
||||||
components: {
|
components: {
|
||||||
GridLines,
|
GridLines,
|
||||||
},
|
},
|
||||||
props: {
|
setup() {
|
||||||
background: {
|
const store = useStore<State>()
|
||||||
type: Array,
|
const showGridLines = computed(() => store.state.showGridLines)
|
||||||
},
|
const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
|
||||||
isShowGridLines: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const backgroundStyle = computed(() => {
|
|
||||||
if(!props.background) return { backgroundColor: '#fff' }
|
|
||||||
|
|
||||||
const [type, value] = props.background
|
const backgroundStyle = computed(() => {
|
||||||
|
if(!currentSlide.value.background) return { backgroundColor: '#fff' }
|
||||||
|
|
||||||
|
const [type, value] = currentSlide.value.background
|
||||||
if(type === 'solid') return { backgroundColor: value }
|
if(type === 'solid') return { backgroundColor: value }
|
||||||
else if(type === 'image') return { backgroundImage: `url(${value}` }
|
else if(type === 'image') return { backgroundImage: `url(${value}` }
|
||||||
|
|
||||||
@ -40,6 +38,7 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
showGridLines,
|
||||||
backgroundStyle,
|
backgroundStyle,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,11 +9,11 @@ import { getRectRotatedRange, AlignLine, uniqAlignLines } from '@/utils/element'
|
|||||||
export default (
|
export default (
|
||||||
elementList: Ref<PPTElement[]>,
|
elementList: Ref<PPTElement[]>,
|
||||||
activeGroupElementId: Ref<string>,
|
activeGroupElementId: Ref<string>,
|
||||||
canvasScale: Ref<number>,
|
|
||||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||||
) => {
|
) => {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
|
||||||
const dragElement = (e: MouseEvent, element: PPTElement) => {
|
const dragElement = (e: MouseEvent, element: PPTElement) => {
|
||||||
if(!activeElementIdList.value.includes(element.elId)) return
|
if(!activeElementIdList.value.includes(element.elId)) return
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Ref, reactive } from 'vue'
|
import { Ref, reactive, computed } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { State, MutationTypes } from '@/store'
|
import { State, MutationTypes } from '@/store'
|
||||||
import { PPTElement } from '@/types/slides'
|
import { PPTElement } from '@/types/slides'
|
||||||
import { getElementRange } from '@/utils/element'
|
import { getElementRange } from '@/utils/element'
|
||||||
|
|
||||||
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>, canvasScale: Ref<number>) => {
|
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>) => {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
|
||||||
const mouseSelectionState = reactive({
|
const mouseSelectionState = reactive({
|
||||||
isShow: false,
|
isShow: false,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Ref } from 'vue'
|
import { Ref, computed } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { State, MutationTypes } from '@/store'
|
import { State, MutationTypes } from '@/store'
|
||||||
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
|
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
|
||||||
@ -12,8 +12,9 @@ export const getAngleFromCoordinate = (x: number, y: number) => {
|
|||||||
return angle
|
return angle
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>, canvasScale: Ref<number>) => {
|
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>) => {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
|
||||||
const rotateElement = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => {
|
const rotateElement = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => {
|
||||||
let isMouseDown = true
|
let isMouseDown = true
|
||||||
|
@ -83,13 +83,13 @@ export const getOppositePoint = (direction: number, points: ReturnType<typeof ge
|
|||||||
|
|
||||||
export default (
|
export default (
|
||||||
elementList: Ref<PPTElement[]>,
|
elementList: Ref<PPTElement[]>,
|
||||||
canvasScale: Ref<number>,
|
|
||||||
activeGroupElementId: Ref<string>,
|
activeGroupElementId: Ref<string>,
|
||||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||||
) => {
|
) => {
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
|
||||||
const scaleElement = (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: ElementScaleHandler) => {
|
const scaleElement = (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: ElementScaleHandler) => {
|
||||||
let isMouseDown = true
|
let isMouseDown = true
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { ref, computed, onMounted, onUnmounted, Ref } from 'vue'
|
import { ref, computed, onMounted, onUnmounted, Ref, watch } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { State } from '@/store'
|
import { State, MutationTypes } from '@/store'
|
||||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||||
|
|
||||||
export default (canvasRef: Ref<HTMLElement | null>) => {
|
export default (canvasRef: Ref<HTMLElement | null>) => {
|
||||||
const canvasScale = ref(1)
|
|
||||||
const viewportLeft = ref(0)
|
const viewportLeft = ref(0)
|
||||||
const viewportTop = ref(0)
|
const viewportTop = ref(0)
|
||||||
|
|
||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
const editorAreaShowScale = computed(() => store.state.editorAreaShowScale)
|
const canvasPercentage = computed(() => store.state.canvasPercentage)
|
||||||
|
|
||||||
const setViewportSize = () => {
|
const setViewportSize = () => {
|
||||||
if(!canvasRef.value) return
|
if(!canvasRef.value) return
|
||||||
@ -17,19 +16,21 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
|
|||||||
const canvasHeight = canvasRef.value.clientHeight
|
const canvasHeight = canvasRef.value.clientHeight
|
||||||
|
|
||||||
if(canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
|
if(canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
|
||||||
const viewportActualWidth = canvasWidth * (editorAreaShowScale.value / 100)
|
const viewportActualWidth = canvasWidth * (canvasPercentage.value / 100)
|
||||||
canvasScale.value = viewportActualWidth / VIEWPORT_SIZE
|
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualWidth / VIEWPORT_SIZE)
|
||||||
viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
|
viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
|
||||||
viewportTop.value = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
|
viewportTop.value = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const viewportActualHeight = canvasHeight * (editorAreaShowScale.value / 100)
|
const viewportActualHeight = canvasHeight * (canvasPercentage.value / 100)
|
||||||
canvasScale.value = viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO)
|
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO))
|
||||||
viewportLeft.value = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
|
viewportLeft.value = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
|
||||||
viewportTop.value = (canvasHeight - viewportActualHeight) / 2
|
viewportTop.value = (canvasHeight - viewportActualHeight) / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(canvasPercentage, setViewportSize)
|
||||||
|
|
||||||
const viewportStyles = computed(() => ({
|
const viewportStyles = computed(() => ({
|
||||||
width: VIEWPORT_SIZE,
|
width: VIEWPORT_SIZE,
|
||||||
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
|
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
|
||||||
@ -47,7 +48,6 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canvasScale,
|
|
||||||
viewportStyles,
|
viewportStyles,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
<div
|
<div
|
||||||
class="canvas"
|
class="canvas"
|
||||||
ref="canvasRef"
|
ref="canvasRef"
|
||||||
|
@mousewheel="$event => mousewheelScaleCanvas($event)"
|
||||||
@mousedown="$event => handleClickBlankArea($event)"
|
@mousedown="$event => handleClickBlankArea($event)"
|
||||||
v-contextmenu="contextmenus"
|
v-contextmenu="contextmenus"
|
||||||
v-click-outside="removeEditorAreaFocus"
|
v-click-outside="removeEditorAreaFocus"
|
||||||
@ -26,11 +27,6 @@
|
|||||||
:quadrant="mouseSelectionState.quadrant"
|
:quadrant="mouseSelectionState.quadrant"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SlideBackground
|
|
||||||
:background="currentSlide?.background"
|
|
||||||
:isShowGridLines="isShowGridLines"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AlignmentLine
|
<AlignmentLine
|
||||||
v-for="(line, index) in alignmentLines" :key="index"
|
v-for="(line, index) in alignmentLines" :key="index"
|
||||||
:type="line.type" :axis="line.axis" :length="line.length"
|
:type="line.type" :axis="line.axis" :length="line.length"
|
||||||
@ -40,13 +36,13 @@
|
|||||||
v-if="activeElementIdList.length > 1"
|
v-if="activeElementIdList.length > 1"
|
||||||
:elementList="elementList"
|
:elementList="elementList"
|
||||||
:scaleMultiElement="scaleMultiElement"
|
:scaleMultiElement="scaleMultiElement"
|
||||||
:canvasScale="canvasScale"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SlideBackground />
|
||||||
|
|
||||||
<EditableElement
|
<EditableElement
|
||||||
v-for="(element, index) in elementList"
|
v-for="(element, index) in elementList"
|
||||||
:key="element.elId"
|
:key="element.elId"
|
||||||
:canvasScale="canvasScale"
|
|
||||||
:elementInfo="element"
|
:elementInfo="element"
|
||||||
:elementIndex="index + 1"
|
:elementIndex="index + 1"
|
||||||
:isActive="activeElementIdList.includes(element.elId)"
|
:isActive="activeElementIdList.includes(element.elId)"
|
||||||
@ -64,6 +60,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, Ref, ref, watch, watchEffect } from 'vue'
|
import { computed, defineComponent, Ref, ref, watch, watchEffect } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
|
import throttle from 'lodash/throttle'
|
||||||
import { State, MutationTypes } from '@/store'
|
import { State, MutationTypes } from '@/store'
|
||||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||||
import { PPTElement, Slide } from '@/types/slides'
|
import { PPTElement, Slide } from '@/types/slides'
|
||||||
@ -80,6 +77,7 @@ import useDragElement from './hooks/useDragElement'
|
|||||||
import useDeleteElement from '@/hooks/useDeleteElement'
|
import useDeleteElement from '@/hooks/useDeleteElement'
|
||||||
import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
|
import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
|
||||||
import useSelectAllElement from '@/hooks/useSelectAllElement'
|
import useSelectAllElement from '@/hooks/useSelectAllElement'
|
||||||
|
import useScaleCanvas from '@/hooks/useScaleCanvas'
|
||||||
|
|
||||||
import EditableElement from '@/views/_common/_element/EditableElement.vue'
|
import EditableElement from '@/views/_common/_element/EditableElement.vue'
|
||||||
import MouseSelection from './MouseSelection.vue'
|
import MouseSelection from './MouseSelection.vue'
|
||||||
@ -102,6 +100,7 @@ export default defineComponent({
|
|||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
const handleElementId = computed(() => store.state.handleElementId)
|
const handleElementId = computed(() => store.state.handleElementId)
|
||||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||||
|
const ctrlKeyState = computed(() => store.state.ctrlKeyState)
|
||||||
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
|
||||||
|
|
||||||
const viewportRef = ref<HTMLElement | null>(null)
|
const viewportRef = ref<HTMLElement | null>(null)
|
||||||
@ -121,14 +120,15 @@ export default defineComponent({
|
|||||||
useDropImageElement(viewportRef)
|
useDropImageElement(viewportRef)
|
||||||
|
|
||||||
const canvasRef = ref<HTMLElement | null>(null)
|
const canvasRef = ref<HTMLElement | null>(null)
|
||||||
const { canvasScale, viewportStyles } = useViewportSize(canvasRef)
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
const { viewportStyles } = useViewportSize(canvasRef)
|
||||||
|
|
||||||
const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef, canvasScale)
|
const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef)
|
||||||
|
|
||||||
const { dragElement } = useDragElement(elementList, activeGroupElementId, canvasScale, alignmentLines)
|
const { dragElement } = useDragElement(elementList, activeGroupElementId, alignmentLines)
|
||||||
const { selectElement } = useSelectElement(elementList, activeGroupElementId, dragElement)
|
const { selectElement } = useSelectElement(elementList, activeGroupElementId, dragElement)
|
||||||
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, canvasScale, activeGroupElementId, alignmentLines)
|
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, activeGroupElementId, alignmentLines)
|
||||||
const { rotateElement } = useRotateElement(elementList, viewportRef, canvasScale)
|
const { rotateElement } = useRotateElement(elementList, viewportRef)
|
||||||
|
|
||||||
const { selectAllElement } = useSelectAllElement()
|
const { selectAllElement } = useSelectAllElement()
|
||||||
const { deleteAllElements } = useDeleteElement()
|
const { deleteAllElements } = useDeleteElement()
|
||||||
@ -144,6 +144,17 @@ export default defineComponent({
|
|||||||
if(editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
if(editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { scaleCanvas } = useScaleCanvas()
|
||||||
|
const throttleScaleCanvas = throttle(scaleCanvas, 100, { leading: true, trailing: false })
|
||||||
|
|
||||||
|
const mousewheelScaleCanvas = (e: WheelEvent) => {
|
||||||
|
if(!ctrlKeyState.value) return
|
||||||
|
|
||||||
|
e.preventDefault()
|
||||||
|
if(e.deltaY > 0) throttleScaleCanvas('-')
|
||||||
|
else if(e.deltaY < 0) throttleScaleCanvas('+')
|
||||||
|
}
|
||||||
|
|
||||||
const contextmenus = (): ContextmenuItem[] => {
|
const contextmenus = (): ContextmenuItem[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -182,6 +193,7 @@ export default defineComponent({
|
|||||||
rotateElement,
|
rotateElement,
|
||||||
scaleElement,
|
scaleElement,
|
||||||
scaleMultiElement,
|
scaleMultiElement,
|
||||||
|
mousewheelScaleCanvas,
|
||||||
contextmenus,
|
contextmenus,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -15,19 +15,41 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right-handler">
|
<div class="right-handler">
|
||||||
<IconFont class="handler-item viewport-size" type="icon-minus" />
|
<IconFont class="handler-item viewport-size" type="icon-minus" @click="scaleCanvas('-')" />
|
||||||
<span class="text">100%</span>
|
<span class="text">{{canvasScalePercentage}}</span>
|
||||||
<IconFont class="handler-item viewport-size" type="icon-plus" />
|
<IconFont class="handler-item viewport-size" type="icon-plus" @click="scaleCanvas('+')" />
|
||||||
<IconFont class="handler-item viewport-size" type="icon-number" />
|
<IconFont class="handler-item viewport-size" type="icon-number" @click="toggleGridLines()" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent, computed } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { MutationTypes, State } from '@/store'
|
||||||
|
import useScaleCanvas from '@/hooks/useScaleCanvas'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'canvas-tool',
|
name: 'canvas-tool',
|
||||||
|
setup() {
|
||||||
|
const store = useStore<State>()
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
const showGridLines = computed(() => store.state.showGridLines)
|
||||||
|
|
||||||
|
const canvasScalePercentage = computed(() => parseInt(canvasScale.value * 100 + '') + '%')
|
||||||
|
|
||||||
|
const { scaleCanvas } = useScaleCanvas()
|
||||||
|
|
||||||
|
const toggleGridLines = () => {
|
||||||
|
store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
scaleCanvas,
|
||||||
|
canvasScalePercentage,
|
||||||
|
toggleGridLines,
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -40,6 +62,7 @@ export default defineComponent({
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.left-handler {
|
.left-handler {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -59,6 +82,11 @@ export default defineComponent({
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
width: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.viewport-size {
|
.viewport-size {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
v-click-outside="() => setThumbnailsFocus(false)"
|
v-click-outside="() => setThumbnailsFocus(false)"
|
||||||
>
|
>
|
||||||
<div class="add-slide">
|
<div class="add-slide">
|
||||||
<span>+ 添加幻灯片</span>
|
<span @click="createSlide()">+ 添加幻灯片</span>
|
||||||
</div>
|
</div>
|
||||||
<draggable
|
<draggable
|
||||||
class="thumbnail-list"
|
class="thumbnail-list"
|
||||||
@ -130,6 +130,7 @@ export default defineComponent({
|
|||||||
setThumbnailsFocus,
|
setThumbnailsFocus,
|
||||||
slides,
|
slides,
|
||||||
slideIndex,
|
slideIndex,
|
||||||
|
createSlide,
|
||||||
changSlideIndex,
|
changSlideIndex,
|
||||||
contextmenus,
|
contextmenus,
|
||||||
fillDigit,
|
fillDigit,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, PropType } from 'vue'
|
import { computed, defineComponent, PropType } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { State } from '@/store'
|
||||||
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTLineElement } from '@/types/slides'
|
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTLineElement } from '@/types/slides'
|
||||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||||
|
|
||||||
@ -42,10 +44,6 @@ import TextElement from './TextElement/index.vue'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'editable-element',
|
name: 'editable-element',
|
||||||
props: {
|
props: {
|
||||||
canvasScale: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
elementInfo: {
|
elementInfo: {
|
||||||
type: Object as PropType<PPTElement>,
|
type: Object as PropType<PPTElement>,
|
||||||
required: true,
|
required: true,
|
||||||
@ -88,6 +86,9 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const store = useStore<State>()
|
||||||
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
|
|
||||||
const currentElementComponent = computed(() => {
|
const currentElementComponent = computed(() => {
|
||||||
const elementTypeMap = {
|
const elementTypeMap = {
|
||||||
'image': ImageElement,
|
'image': ImageElement,
|
||||||
@ -180,6 +181,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
canvasScale,
|
||||||
currentElementComponent,
|
currentElementComponent,
|
||||||
contextmenus,
|
contextmenus,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user