feat: 添加页面尺寸修改功能

This commit is contained in:
pipipi-pikachu 2021-03-27 16:43:15 +08:00
parent 5fd09ffc7b
commit 326c13c63e
16 changed files with 7361 additions and 5092 deletions

12329
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
"dependencies": {
"@icon-park/vue-next": "^1.2.6",
"animate.css": "^4.1.1",
"ant-design-vue": "^2.1.0",
"ant-design-vue": "^2.0.0",
"chartist": "^0.11.4",
"clipboard": "^2.0.6",
"core-js": "^3.6.5",
@ -30,7 +30,7 @@
"prosemirror-state": "^1.3.3",
"prosemirror-view": "^1.18.2",
"tinycolor2": "^1.4.2",
"vue": "^3.0.7",
"vue": "^3.0.0",
"vuedraggable": "^4.0.1",
"vuex": "^4.0.0"
},
@ -59,7 +59,7 @@
"@vue/cli-plugin-unit-jest": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.7",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-typescript": "^5.0.2",
"@vue/test-utils": "^2.0.0-0",
"babel-plugin-import": "^1.13.3",

View File

@ -1,2 +1 @@
export const VIEWPORT_SIZE = 1000
export const VIEWPORT_ASPECT_RATIO = 0.5625
export const VIEWPORT_SIZE = 1000

View File

@ -3,13 +3,14 @@ import { MutationTypes, useStore } from '@/store'
import { PPTElement, Slide } from '@/types/slides'
import { ElementAlignCommand, ElementAlignCommands } from '@/types/edit'
import { getElementListRange } from '@/utils/element'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import useHistorySnapshot from './useHistorySnapshot'
export default () => {
const store = useStore()
const activeElementIdList = computed(() => store.state.activeElementIdList)
const viewportRatio = computed(() => store.state.viewportRatio)
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
@ -21,7 +22,7 @@ export default () => {
*/
const alignElementToCanvas = (command: ElementAlignCommand) => {
const viewportWidth = VIEWPORT_SIZE
const viewportHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
const viewportHeight = VIEWPORT_SIZE * viewportRatio.value
const { minX, maxX, minY, maxY } = getElementListRange(activeElementList.value)
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))

View File

@ -2,7 +2,7 @@ import { computed } from 'vue'
import { MutationTypes, useStore } from '@/store'
import { createRandomCode } from '@/utils/common'
import { getImageSize } from '@/utils/image'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import { PPTLineElement, ChartType, PPTElement, TableCell } from '@/types/slides'
import { ShapePoolItem } from '@/configs/shapes'
import { LinePoolItem } from '@/configs/lines'
@ -26,6 +26,7 @@ export default () => {
const store = useStore()
const themeColor = computed(() => store.state.theme.themeColor)
const fontColor = computed(() => store.state.theme.fontColor)
const viewportRatio = computed(() => store.state.viewportRatio)
const { addHistorySnapshot } = useHistorySnapshot()
@ -44,12 +45,12 @@ export default () => {
getImageSize(src).then(({ width, height }) => {
const scale = height / width
if (scale < VIEWPORT_ASPECT_RATIO && width > VIEWPORT_SIZE) {
if (scale < viewportRatio.value && width > VIEWPORT_SIZE) {
width = VIEWPORT_SIZE
height = width * scale
}
else if (height > VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO) {
height = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
else if (height > VIEWPORT_SIZE * viewportRatio.value) {
height = VIEWPORT_SIZE * viewportRatio.value
width = height / scale
}
@ -60,7 +61,7 @@ export default () => {
width,
height,
left: (VIEWPORT_SIZE - width) / 2,
top: (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO - height) / 2,
top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,
fixedRatio: true,
})
})
@ -115,7 +116,7 @@ export default () => {
colWidths,
data,
left: (VIEWPORT_SIZE - width) / 2,
top: (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO - height) / 2,
top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,
outline: {
width: 2,
style: 'solid',

View File

@ -16,6 +16,7 @@ export const enum MutationTypes {
// slides
SET_THEME = 'setTheme',
SET_VIEWPORT_RATIO = 'setViewportRatio',
SET_SLIDES = 'setSlides',
ADD_SLIDE = 'addSlide',
UPDATE_SLIDE = 'updateSlide',

View File

@ -78,6 +78,10 @@ export const mutations: MutationTree<State> = {
state.theme = { ...state.theme, ...themeProps }
},
[MutationTypes.SET_VIEWPORT_RATIO](state, viewportRatio: number) {
state.viewportRatio = viewportRatio
},
[MutationTypes.SET_SLIDES](state, slides: Slide[]) {
state.slides = slides
},

View File

@ -17,6 +17,7 @@ export interface State {
availableFonts: typeof SYS_FONTS;
toolbarState: ToolbarState;
theme: SlideTheme;
viewportRatio: number;
slides: Slide[];
slideIndex: number;
selectedSlidesIndex: number[];
@ -46,6 +47,7 @@ export const state: State = {
fontName: '微软雅黑',
backgroundColor: '#fff',
},
viewportRatio: 0.5625,
slides: slides,
slideIndex: 0,
selectedSlidesIndex: [],

View File

@ -18,7 +18,7 @@
import { defineComponent, computed } from 'vue'
import tinycolor from 'tinycolor2'
import { useStore } from '@/store'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import { SlideBackground } from '@/types/slides'
export default defineComponent({
@ -26,6 +26,7 @@ export default defineComponent({
setup() {
const store = useStore()
const canvasScale = computed(() => store.state.canvasScale)
const viewportRatio = computed(() => store.state.viewportRatio)
const background = computed<SlideBackground | undefined>(() => store.getters.currentSlide?.background)
// 线
@ -47,7 +48,7 @@ export default defineComponent({
//
const getPath = () => {
const maxX = VIEWPORT_SIZE
const maxY = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
const maxY = VIEWPORT_SIZE * viewportRatio.value
let path = ''
for (let i = 0; i <= Math.floor(maxY / gridSize); i++) {
@ -63,7 +64,7 @@ export default defineComponent({
canvasScale,
gridColor,
width: VIEWPORT_SIZE,
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
height: VIEWPORT_SIZE * viewportRatio.value,
path: getPath(),
}
},

View File

@ -2,7 +2,7 @@ import { Ref, computed } from 'vue'
import { MutationTypes, useStore } from '@/store'
import { PPTElement } from '@/types/slides'
import { AlignmentLineProps } from '@/types/edit'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import { getRectRotatedRange, AlignLine, uniqAlignLines } from '@/utils/element'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
@ -14,6 +14,7 @@ export default (
const store = useStore()
const activeElementIdList = computed(() => store.state.activeElementIdList)
const canvasScale = computed(() => store.state.canvasScale)
const viewportRatio = computed(() => store.state.viewportRatio)
const { addHistorySnapshot } = useHistorySnapshot()
@ -22,7 +23,7 @@ export default (
let isMouseDown = true
const edgeWidth = VIEWPORT_SIZE
const edgeHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
const edgeHeight = VIEWPORT_SIZE * viewportRatio.value
const sorptionRange = 5

View File

@ -3,7 +3,7 @@ import { MutationTypes, useStore } from '@/store'
import { PPTElement, PPTImageElement, PPTLineElement, PPTShapeElement } from '@/types/slides'
import { OperateResizeHandlers, AlignmentLineProps, MultiSelectRange } from '@/types/edit'
import emitter, { EmitterEvents } from '@/utils/emitter'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import { MIN_SIZE } from '@/configs/element'
import { AlignLine, uniqAlignLines } from '@/utils/element'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
@ -99,8 +99,9 @@ export default (
) => {
const store = useStore()
const activeElementIdList = computed(() => store.state.activeElementIdList)
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
const canvasScale = computed(() => store.state.canvasScale)
const viewportRatio = computed(() => store.state.viewportRatio)
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
const { addHistorySnapshot } = useHistorySnapshot()
@ -149,7 +150,7 @@ export default (
// 其中线条和被旋转过的元素不参与吸附对齐
else {
const edgeWidth = VIEWPORT_SIZE
const edgeHeight = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
const edgeHeight = VIEWPORT_SIZE * viewportRatio.value
const isActiveGroupElement = element.id === activeGroupElementId.value
for (const el of elementList.value) {

View File

@ -1,6 +1,6 @@
import { ref, computed, onMounted, onUnmounted, Ref, watch } from 'vue'
import { MutationTypes, useStore } from '@/store'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
export default (canvasRef: Ref<HTMLElement | undefined>) => {
const viewportLeft = ref(0)
@ -8,6 +8,7 @@ export default (canvasRef: Ref<HTMLElement | undefined>) => {
const store = useStore()
const canvasPercentage = computed(() => store.state.canvasPercentage)
const viewportRatio = computed(() => store.state.viewportRatio)
// 计算画布可视区域的位置
const setViewportPosition = () => {
@ -15,27 +16,27 @@ export default (canvasRef: Ref<HTMLElement | undefined>) => {
const canvasWidth = canvasRef.value.clientWidth
const canvasHeight = canvasRef.value.clientHeight
if (canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
if (canvasHeight / canvasWidth > viewportRatio.value) {
const viewportActualWidth = canvasWidth * (canvasPercentage.value / 100)
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualWidth / VIEWPORT_SIZE)
viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
viewportTop.value = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
viewportTop.value = (canvasHeight - viewportActualWidth * viewportRatio.value) / 2
}
else {
const viewportActualHeight = canvasHeight * (canvasPercentage.value / 100)
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO))
viewportLeft.value = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualHeight / (VIEWPORT_SIZE * viewportRatio.value))
viewportLeft.value = (canvasWidth - viewportActualHeight / viewportRatio.value) / 2
viewportTop.value = (canvasHeight - viewportActualHeight) / 2
}
}
// 可视区域缩放时,更新可视区域的位置
watch(canvasPercentage, setViewportPosition)
// 可视区域缩放或比例变化时,更新可视区域的位置
watch([canvasPercentage, viewportRatio], setViewportPosition)
// 画布可视区域位置和大小的样式
const viewportStyles = computed(() => ({
width: VIEWPORT_SIZE,
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
height: VIEWPORT_SIZE * viewportRatio.value,
left: viewportLeft.value,
top: viewportTop.value,
}))

View File

@ -176,6 +176,17 @@
</div>
<div class="row"><Button style="flex: 1;" @click="applyThemeAllSlide()">应用主题到全部</Button></div>
<Divider />
<div class="row">
<div style="flex: 2;">画布尺寸</div>
<Select style="flex: 3;" :value="viewportRatio" @change="value => updateViewportRatio(value)">
<SelectOption :value="0.5625">宽屏 16 : 9</SelectOption>
<SelectOption :value="0.625">宽屏 16 10</SelectOption>
<SelectOption :value="0.75">标准 4 3</SelectOption>
</Select>
</div>
</div>
</template>
@ -202,8 +213,9 @@ export default defineComponent({
const store = useStore()
const slides = computed(() => store.state.slides)
const theme = computed(() => store.state.theme)
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
const availableFonts = computed(() => store.state.availableFonts)
const viewportRatio = computed(() => store.state.viewportRatio)
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
const background = computed(() => {
if (!currentSlide.value.background) {
@ -313,6 +325,11 @@ export default defineComponent({
addHistorySnapshot()
}
//
const updateViewportRatio = (value: number) => {
store.commit(MutationTypes.SET_VIEWPORT_RATIO, value)
}
return {
availableFonts,
background,
@ -325,6 +342,8 @@ export default defineComponent({
webFonts,
updateTheme,
applyThemeAllSlide,
viewportRatio,
updateViewportRatio,
}
},
})

View File

@ -3,7 +3,7 @@
class="screen-slide"
:style="{
width: VIEWPORT_SIZE + 'px',
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + 'px',
height: VIEWPORT_SIZE * viewportRatio + 'px',
transform: `scale(${scale})`,
}"
>
@ -21,8 +21,9 @@
<script lang="ts">
import { computed, PropType, defineComponent } from 'vue'
import { useStore } from '@/store'
import { Slide } from '@/types/slides'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
import ScreenElement from './ScreenElement.vue'
@ -47,13 +48,16 @@ export default defineComponent({
},
},
setup(props) {
const store = useStore()
const viewportRatio = computed(() => store.state.viewportRatio)
const background = computed(() => props.slide.background)
const { backgroundStyle } = useSlideBackgroundStyle(background)
return {
backgroundStyle,
VIEWPORT_SIZE,
VIEWPORT_ASPECT_RATIO,
viewportRatio,
}
},
})

View File

@ -60,7 +60,7 @@ import { computed, defineComponent, onMounted, onUnmounted, provide, ref } from
import throttle from 'lodash/throttle'
import { MutationTypes, useStore } from '@/store'
import { Slide } from '@/types/slides'
import { VIEWPORT_ASPECT_RATIO, VIEWPORT_SIZE } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import { KEYS } from '@/configs/hotkey'
import { ContextmenuItem } from '@/components/Contextmenu/types'
import { isFullscreen } from '@/utils/fullscreen'
@ -81,6 +81,7 @@ export default defineComponent({
const store = useStore()
const slides = computed(() => store.state.slides)
const slideIndex = computed(() => store.state.slideIndex)
const viewportRatio = computed(() => store.state.viewportRatio)
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
const slideWidth = ref(0)
@ -98,16 +99,16 @@ export default defineComponent({
const winHeight = document.body.clientHeight
let width, height
if (winHeight / winWidth === VIEWPORT_ASPECT_RATIO) {
if (winHeight / winWidth === viewportRatio.value) {
width = winWidth
height = winHeight
}
else if (winHeight / winWidth > VIEWPORT_ASPECT_RATIO) {
else if (winHeight / winWidth > viewportRatio.value) {
width = winWidth
height = winWidth * VIEWPORT_ASPECT_RATIO
height = winWidth * viewportRatio.value
}
else {
width = winHeight / VIEWPORT_ASPECT_RATIO
width = winHeight / viewportRatio.value
height = winHeight
}
slideWidth.value = width

View File

@ -2,14 +2,14 @@
<div class="thumbnail-slide"
:style="{
width: size + 'px',
height: size * VIEWPORT_ASPECT_RATIO + 'px',
height: size * viewportRatio + 'px',
}"
>
<div
class="elements"
:style="{
width: VIEWPORT_SIZE + 'px',
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + 'px',
height: VIEWPORT_SIZE * viewportRatio + 'px',
transform: `scale(${scale})`,
}"
>
@ -26,8 +26,9 @@
<script lang="ts">
import { computed, PropType, defineComponent } from 'vue'
import { useStore } from '@/store'
import { Slide } from '@/types/slides'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
import ThumbnailElement from './ThumbnailElement.vue'
@ -48,6 +49,9 @@ export default defineComponent({
},
},
setup(props) {
const store = useStore()
const viewportRatio = computed(() => store.state.viewportRatio)
const background = computed(() => props.slide.background)
const { backgroundStyle } = useSlideBackgroundStyle(background)
@ -57,7 +61,7 @@ export default defineComponent({
scale,
backgroundStyle,
VIEWPORT_SIZE,
VIEWPORT_ASPECT_RATIO,
viewportRatio,
}
},
})