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;
|
||||
disableHotkeys: boolean;
|
||||
showGridLines: boolean;
|
||||
showRuler: boolean;
|
||||
creatingElement: CreatingElement | null;
|
||||
availableFonts: typeof SYS_FONTS;
|
||||
toolbarState: ToolbarStates;
|
||||
@ -41,6 +42,7 @@ export const useMainStore = defineStore('main', {
|
||||
editorAreaFocus: false, // 编辑区域聚焦
|
||||
disableHotkeys: false, // 禁用快捷键
|
||||
showGridLines: false, // 显示网格线
|
||||
showRuler: false, // 显示标尺
|
||||
creatingElement: null, // 正在插入的元素信息,需要通过绘制插入的元素(文字、形状、线条)
|
||||
availableFonts: SYS_FONTS, // 当前环境可用字体
|
||||
toolbarState: ToolbarStates.SLIDE_DESIGN, // 右侧工具栏状态
|
||||
@ -112,6 +114,10 @@ export const useMainStore = defineStore('main', {
|
||||
this.showGridLines = show
|
||||
},
|
||||
|
||||
setRulerState(show: boolean) {
|
||||
this.showRuler = show
|
||||
},
|
||||
|
||||
setCreatingElement(element: CreatingElement | null) {
|
||||
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>
|
||||
|
||||
<Ruler :viewportStyles="viewportStyles" v-if="showRuler" />
|
||||
|
||||
<Modal
|
||||
v-model:visible="linkDialogVisible"
|
||||
:footer="null"
|
||||
@ -121,6 +123,7 @@ import EditableElement from './EditableElement.vue'
|
||||
import MouseSelection from './MouseSelection.vue'
|
||||
import ViewportBackground from './ViewportBackground.vue'
|
||||
import AlignmentLine from './AlignmentLine.vue'
|
||||
import Ruler from './Ruler.vue'
|
||||
import ElementCreateSelection from './ElementCreateSelection.vue'
|
||||
import MultiSelectOperate from './Operate/MultiSelectOperate.vue'
|
||||
import Operate from './Operate/index.vue'
|
||||
@ -133,6 +136,7 @@ export default defineComponent({
|
||||
MouseSelection,
|
||||
ViewportBackground,
|
||||
AlignmentLine,
|
||||
Ruler,
|
||||
ElementCreateSelection,
|
||||
MultiSelectOperate,
|
||||
Operate,
|
||||
@ -146,6 +150,7 @@ export default defineComponent({
|
||||
handleElementId,
|
||||
editorAreaFocus,
|
||||
showGridLines,
|
||||
showRuler,
|
||||
creatingElement,
|
||||
canvasScale,
|
||||
} = storeToRefs(mainStore)
|
||||
@ -228,6 +233,11 @@ export default defineComponent({
|
||||
mainStore.setGridLinesState(!showGridLines.value)
|
||||
}
|
||||
|
||||
// 开关标尺
|
||||
const toggleRuler = () => {
|
||||
mainStore.setRulerState(!showRuler.value)
|
||||
}
|
||||
|
||||
// 在鼠标绘制的范围插入元素
|
||||
const { insertElementFromCreateSelection } = useInsertFromCreateSelection(viewportRef)
|
||||
|
||||
@ -248,6 +258,11 @@ export default defineComponent({
|
||||
subText: showGridLines.value ? '√' : '',
|
||||
handler: toggleGridLines,
|
||||
},
|
||||
{
|
||||
text: '标尺',
|
||||
subText: showRuler.value ? '√' : '',
|
||||
handler: toggleRuler,
|
||||
},
|
||||
{
|
||||
text: '重置当前页',
|
||||
handler: deleteAllElements,
|
||||
@ -279,6 +294,7 @@ export default defineComponent({
|
||||
alignmentLines,
|
||||
linkDialogVisible,
|
||||
spaceKeyState,
|
||||
showRuler,
|
||||
openLinkDialog,
|
||||
handleClickBlankArea,
|
||||
removeEditorAreaFocus,
|
||||
|
@ -20,6 +20,7 @@
|
||||
<MenuItem @click="createSlide()">添加页面</MenuItem>
|
||||
<MenuItem @click="deleteSlide()">删除页面</MenuItem>
|
||||
<MenuItem @click="toggleGridLines()">{{ showGridLines ? '关闭网格线' : '打开网格线' }}</MenuItem>
|
||||
<MenuItem @click="toggleRuler()">{{ toggleRuler ? '关闭标尺' : '打开标尺' }}</MenuItem>
|
||||
<MenuItem @click="resetSlides()">重置幻灯片</MenuItem>
|
||||
</Menu>
|
||||
</template>
|
||||
@ -99,7 +100,7 @@ export default defineComponent({
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore()
|
||||
const { showGridLines } = storeToRefs(mainStore)
|
||||
const { showGridLines, showRuler } = storeToRefs(mainStore)
|
||||
|
||||
const { enterScreening, enterScreeningFromStart } = useScreening()
|
||||
const { createSlide, deleteSlide, resetSlides } = useSlideHandler()
|
||||
@ -110,6 +111,10 @@ export default defineComponent({
|
||||
mainStore.setGridLinesState(!showGridLines.value)
|
||||
}
|
||||
|
||||
const toggleRuler = () => {
|
||||
mainStore.setRulerState(!showRuler.value)
|
||||
}
|
||||
|
||||
const hotkeyDrawerVisible = ref(false)
|
||||
const exportImgDialogVisible = ref(false)
|
||||
|
||||
@ -129,6 +134,7 @@ export default defineComponent({
|
||||
createSlide,
|
||||
deleteSlide,
|
||||
toggleGridLines,
|
||||
toggleRuler,
|
||||
resetSlides,
|
||||
exportJSON,
|
||||
exportPPTX,
|
||||
|
Loading…
x
Reference in New Issue
Block a user