mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 添加画布标尺
This commit is contained in:
parent
e450a944a9
commit
297aa6cca2
@ -18,6 +18,7 @@ export interface MainState {
|
|||||||
editorAreaFocus: boolean;
|
editorAreaFocus: boolean;
|
||||||
disableHotkeys: boolean;
|
disableHotkeys: boolean;
|
||||||
showGridLines: boolean;
|
showGridLines: boolean;
|
||||||
|
showRuler: boolean;
|
||||||
creatingElement: CreatingElement | null;
|
creatingElement: CreatingElement | null;
|
||||||
availableFonts: typeof SYS_FONTS;
|
availableFonts: typeof SYS_FONTS;
|
||||||
toolbarState: ToolbarStates;
|
toolbarState: ToolbarStates;
|
||||||
@ -41,6 +42,7 @@ export const useMainStore = defineStore('main', {
|
|||||||
editorAreaFocus: false, // 编辑区域聚焦
|
editorAreaFocus: false, // 编辑区域聚焦
|
||||||
disableHotkeys: false, // 禁用快捷键
|
disableHotkeys: false, // 禁用快捷键
|
||||||
showGridLines: false, // 显示网格线
|
showGridLines: false, // 显示网格线
|
||||||
|
showRuler: false, // 显示标尺
|
||||||
creatingElement: null, // 正在插入的元素信息,需要通过绘制插入的元素(文字、形状、线条)
|
creatingElement: null, // 正在插入的元素信息,需要通过绘制插入的元素(文字、形状、线条)
|
||||||
availableFonts: SYS_FONTS, // 当前环境可用字体
|
availableFonts: SYS_FONTS, // 当前环境可用字体
|
||||||
toolbarState: ToolbarStates.SLIDE_DESIGN, // 右侧工具栏状态
|
toolbarState: ToolbarStates.SLIDE_DESIGN, // 右侧工具栏状态
|
||||||
@ -112,6 +114,10 @@ export const useMainStore = defineStore('main', {
|
|||||||
this.showGridLines = show
|
this.showGridLines = show
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setRulerState(show: boolean) {
|
||||||
|
this.showRuler = show
|
||||||
|
},
|
||||||
|
|
||||||
setCreatingElement(element: CreatingElement | null) {
|
setCreatingElement(element: CreatingElement | null) {
|
||||||
this.creatingElement = element
|
this.creatingElement = element
|
||||||
},
|
},
|
||||||
|
142
src/views/Editor/Canvas/Ruler.vue
Normal file
142
src/views/Editor/Canvas/Ruler.vue
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ruler">
|
||||||
|
<div
|
||||||
|
class="h"
|
||||||
|
:style="{
|
||||||
|
width: viewportStyles.width * canvasScale + 'px',
|
||||||
|
left: viewportStyles.left + 'px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="ruler-mark-100" v-for="mark in 10" :key="`mark-100-${mark}`">{{mark * 100}}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="v"
|
||||||
|
:style="{
|
||||||
|
height: viewportStyles.height * canvasScale + 'px',
|
||||||
|
top: viewportStyles.top + 'px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ruler-mark-100"
|
||||||
|
v-for="mark in 10"
|
||||||
|
:key="mark"
|
||||||
|
:style="{ height: markSize + 'px' }"
|
||||||
|
>{{mark * 100}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, PropType } from 'vue'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useMainStore } from '@/store'
|
||||||
|
|
||||||
|
interface ViewportStyles {
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
viewportStyles: {
|
||||||
|
type: Object as PropType<ViewportStyles>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const { canvasScale } = storeToRefs(useMainStore())
|
||||||
|
|
||||||
|
const markSize = computed(() => {
|
||||||
|
return props.viewportStyles.width * canvasScale.value / 10
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
canvasScale,
|
||||||
|
markSize,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.ruler {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.h {
|
||||||
|
position: absolute;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid $borderColor;
|
||||||
|
height: 20px;
|
||||||
|
top: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.ruler-mark-100 {
|
||||||
|
height: 100%;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: right;
|
||||||
|
flex: 1;
|
||||||
|
padding-right: 5px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:not(:last-child)::after {
|
||||||
|
content: '';
|
||||||
|
width: .1px;
|
||||||
|
height: 12px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
width: .1px;
|
||||||
|
height: 8px;
|
||||||
|
position: absolute;
|
||||||
|
right: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.v {
|
||||||
|
position: absolute;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid $borderColor;
|
||||||
|
width: 20px;
|
||||||
|
left: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.ruler-mark-100 {
|
||||||
|
width: 100%;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: right;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
position: relative;
|
||||||
|
writing-mode: vertical-rl;
|
||||||
|
|
||||||
|
&:not(:last-child)::after {
|
||||||
|
content: '';
|
||||||
|
height: .1px;
|
||||||
|
width: 12px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: .1px;
|
||||||
|
width: 8px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 50%;
|
||||||
|
right: 0;
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -76,6 +76,8 @@
|
|||||||
|
|
||||||
<div class="drag-mask" v-if="spaceKeyState"></div>
|
<div class="drag-mask" v-if="spaceKeyState"></div>
|
||||||
|
|
||||||
|
<Ruler :viewportStyles="viewportStyles" v-if="showRuler" />
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
v-model:visible="linkDialogVisible"
|
v-model:visible="linkDialogVisible"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
@ -121,6 +123,7 @@ import EditableElement from './EditableElement.vue'
|
|||||||
import MouseSelection from './MouseSelection.vue'
|
import MouseSelection from './MouseSelection.vue'
|
||||||
import ViewportBackground from './ViewportBackground.vue'
|
import ViewportBackground from './ViewportBackground.vue'
|
||||||
import AlignmentLine from './AlignmentLine.vue'
|
import AlignmentLine from './AlignmentLine.vue'
|
||||||
|
import Ruler from './Ruler.vue'
|
||||||
import ElementCreateSelection from './ElementCreateSelection.vue'
|
import ElementCreateSelection from './ElementCreateSelection.vue'
|
||||||
import MultiSelectOperate from './Operate/MultiSelectOperate.vue'
|
import MultiSelectOperate from './Operate/MultiSelectOperate.vue'
|
||||||
import Operate from './Operate/index.vue'
|
import Operate from './Operate/index.vue'
|
||||||
@ -133,6 +136,7 @@ export default defineComponent({
|
|||||||
MouseSelection,
|
MouseSelection,
|
||||||
ViewportBackground,
|
ViewportBackground,
|
||||||
AlignmentLine,
|
AlignmentLine,
|
||||||
|
Ruler,
|
||||||
ElementCreateSelection,
|
ElementCreateSelection,
|
||||||
MultiSelectOperate,
|
MultiSelectOperate,
|
||||||
Operate,
|
Operate,
|
||||||
@ -146,6 +150,7 @@ export default defineComponent({
|
|||||||
handleElementId,
|
handleElementId,
|
||||||
editorAreaFocus,
|
editorAreaFocus,
|
||||||
showGridLines,
|
showGridLines,
|
||||||
|
showRuler,
|
||||||
creatingElement,
|
creatingElement,
|
||||||
canvasScale,
|
canvasScale,
|
||||||
} = storeToRefs(mainStore)
|
} = storeToRefs(mainStore)
|
||||||
@ -228,6 +233,11 @@ export default defineComponent({
|
|||||||
mainStore.setGridLinesState(!showGridLines.value)
|
mainStore.setGridLinesState(!showGridLines.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开关标尺
|
||||||
|
const toggleRuler = () => {
|
||||||
|
mainStore.setRulerState(!showRuler.value)
|
||||||
|
}
|
||||||
|
|
||||||
// 在鼠标绘制的范围插入元素
|
// 在鼠标绘制的范围插入元素
|
||||||
const { insertElementFromCreateSelection } = useInsertFromCreateSelection(viewportRef)
|
const { insertElementFromCreateSelection } = useInsertFromCreateSelection(viewportRef)
|
||||||
|
|
||||||
@ -248,6 +258,11 @@ export default defineComponent({
|
|||||||
subText: showGridLines.value ? '√' : '',
|
subText: showGridLines.value ? '√' : '',
|
||||||
handler: toggleGridLines,
|
handler: toggleGridLines,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: '标尺',
|
||||||
|
subText: showRuler.value ? '√' : '',
|
||||||
|
handler: toggleRuler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: '重置当前页',
|
text: '重置当前页',
|
||||||
handler: deleteAllElements,
|
handler: deleteAllElements,
|
||||||
@ -279,6 +294,7 @@ export default defineComponent({
|
|||||||
alignmentLines,
|
alignmentLines,
|
||||||
linkDialogVisible,
|
linkDialogVisible,
|
||||||
spaceKeyState,
|
spaceKeyState,
|
||||||
|
showRuler,
|
||||||
openLinkDialog,
|
openLinkDialog,
|
||||||
handleClickBlankArea,
|
handleClickBlankArea,
|
||||||
removeEditorAreaFocus,
|
removeEditorAreaFocus,
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
<MenuItem @click="createSlide()">添加页面</MenuItem>
|
<MenuItem @click="createSlide()">添加页面</MenuItem>
|
||||||
<MenuItem @click="deleteSlide()">删除页面</MenuItem>
|
<MenuItem @click="deleteSlide()">删除页面</MenuItem>
|
||||||
<MenuItem @click="toggleGridLines()">{{ showGridLines ? '关闭网格线' : '打开网格线' }}</MenuItem>
|
<MenuItem @click="toggleGridLines()">{{ showGridLines ? '关闭网格线' : '打开网格线' }}</MenuItem>
|
||||||
|
<MenuItem @click="toggleRuler()">{{ toggleRuler ? '关闭标尺' : '打开标尺' }}</MenuItem>
|
||||||
<MenuItem @click="resetSlides()">重置幻灯片</MenuItem>
|
<MenuItem @click="resetSlides()">重置幻灯片</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</template>
|
</template>
|
||||||
@ -99,7 +100,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { showGridLines } = storeToRefs(mainStore)
|
const { showGridLines, showRuler } = storeToRefs(mainStore)
|
||||||
|
|
||||||
const { enterScreening, enterScreeningFromStart } = useScreening()
|
const { enterScreening, enterScreeningFromStart } = useScreening()
|
||||||
const { createSlide, deleteSlide, resetSlides } = useSlideHandler()
|
const { createSlide, deleteSlide, resetSlides } = useSlideHandler()
|
||||||
@ -110,6 +111,10 @@ export default defineComponent({
|
|||||||
mainStore.setGridLinesState(!showGridLines.value)
|
mainStore.setGridLinesState(!showGridLines.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleRuler = () => {
|
||||||
|
mainStore.setRulerState(!showRuler.value)
|
||||||
|
}
|
||||||
|
|
||||||
const hotkeyDrawerVisible = ref(false)
|
const hotkeyDrawerVisible = ref(false)
|
||||||
const exportImgDialogVisible = ref(false)
|
const exportImgDialogVisible = ref(false)
|
||||||
|
|
||||||
@ -129,6 +134,7 @@ export default defineComponent({
|
|||||||
createSlide,
|
createSlide,
|
||||||
deleteSlide,
|
deleteSlide,
|
||||||
toggleGridLines,
|
toggleGridLines,
|
||||||
|
toggleRuler,
|
||||||
resetSlides,
|
resetSlides,
|
||||||
exportJSON,
|
exportJSON,
|
||||||
exportPPTX,
|
exportPPTX,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user