基本完成图片属性面板

This commit is contained in:
pipipi-pikachu 2021-01-12 10:24:21 +08:00
parent 40d234b0fc
commit eb33459d52
5 changed files with 109 additions and 62 deletions

View File

@ -13,6 +13,10 @@
}
.ant-btn {
font-size: 13px !important;
&.no-padding {
padding: 0;
}
}
.ant-radio-group {
font-size: 13px !important;

View File

@ -22,7 +22,7 @@ export enum MutationTypes {
UPDATE_SLIDE_INDEX = 'updateSlideIndex',
ADD_ELEMENT = 'addElement',
UPDATE_ELEMENT = 'updateElement',
REMOVE_ELEMENT_PROP = 'removeElementProp',
REMOVE_ELEMENT_PROPS = 'removeElementProps',
// snapshot
SET_SNAPSHOT_CURSOR = 'setSnapshotCursor',

View File

@ -1,4 +1,5 @@
import { MutationTree } from 'vuex'
import omit from 'lodash/omit'
import { MutationTypes } from './constants'
import { State } from './index'
import { Slide, PPTElement } from '@/types/slides'
@ -8,7 +9,7 @@ import { isSupportFontFamily } from '@/utils/fontFamily'
interface RemoveElementPropData {
id: string;
propName: string;
propName: string | string[];
}
interface UpdateElementData {
@ -120,14 +121,14 @@ export const mutations: MutationTree<State> = {
state.slides[slideIndex].elements = (elements as PPTElement[])
},
[MutationTypes.REMOVE_ELEMENT_PROP](state, data: RemoveElementPropData) {
[MutationTypes.REMOVE_ELEMENT_PROPS](state, data: RemoveElementPropData) {
const { id, propName } = data
const propsNames = typeof propName === 'string' ? [propName] : propName
const slideIndex = state.slideIndex
const slide = state.slides[slideIndex]
const elements = slide.elements.map(el => {
if(el.id === id) delete el[propName]
return el
return el.id === id ? omit(el, propsNames) : el
})
state.slides[slideIndex].elements = (elements as PPTElement[])
},

View File

@ -5,38 +5,39 @@
:style="{ backgroundImage: `url(${handleElement.src})` }"
></div>
<Popover trigger="click" v-model:visible="clipPanelVisible">
<template #content>
<div class="clip">
<Button class="full-width-btn" @click="clipImage()">裁剪</Button>
<div class="title">按形状裁剪</div>
<div class="shape-clip">
<div
class="shape-clip-item"
v-for="(item, index) in shapeClipPathOptions"
:key="index"
@click="presetImageClip(index)"
>
<div class="shape" :style="{ clipPath: item.style }"></div>
<ButtonGroup class="row">
<Button style="flex: 5;" @click="clipImage()">裁剪图片</Button>
<Popover trigger="click" v-model:visible="clipPanelVisible">
<template #content>
<div class="clip">
<div class="title">按形状裁剪</div>
<div class="shape-clip">
<div
class="shape-clip-item"
v-for="(item, index) in shapeClipPathOptions"
:key="index"
@click="presetImageClip(index)"
>
<div class="shape" :style="{ clipPath: item.style }"></div>
</div>
</div>
</div>
<template v-for="type in ratioClipOptions" :key="type.label">
<div class="title" v-if="type.label">{{type.label}}</div>
<ButtonGroup class="row">
<Button
style="flex: 1;"
v-for="item in type.children"
:key="item.key"
@click="presetImageClip('rect', item.ratio)"
>{{item.key}}</Button>
</ButtonGroup>
</template>
</div>
</template>
<Button class="full-width-btn">裁剪图片</Button>
</Popover>
<template v-for="type in ratioClipOptions" :key="type.label">
<div class="title" v-if="type.label">{{type.label}}</div>
<ButtonGroup class="row">
<Button
style="flex: 1;"
v-for="item in type.children"
:key="item.key"
@click="presetImageClip('rect', item.ratio)"
>{{item.key}}</Button>
</ButtonGroup>
</template>
</div>
</template>
<Button class="no-padding" style="flex: 1;"><IconFont type="icon-down" /></Button>
</Popover>
</ButtonGroup>
<Popover trigger="click">
<template #content>
@ -83,8 +84,10 @@
<ElementShadow />
<Divider />
<Button class="full-width-btn">替换图片</Button>
<Button class="full-width-btn">重置样式</Button>
<FileInput @change="files => replaceImage(files)">
<Button class="full-width-btn">替换图片</Button>
</FileInput>
<Button class="full-width-btn" @click="resetImage()">重置样式</Button>
</div>
</template>
@ -94,6 +97,7 @@ import { useStore } from 'vuex'
import { MutationTypes, State } from '@/store'
import { PPTImageElement } from '@/types/slides'
import { CLIPPATHS } from '@/configs/imageClip'
import { getImageDataURL } from '@/utils/image'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ElementOutline from '../common/ElementOutline.vue'
@ -213,7 +217,7 @@ export default defineComponent({
clipPanelVisible.value = false
}
const presetImageClip = (shape: string, ratio = 0) => {
const getImageElementDataBeforeClip = () => {
//
const imgWidth = handleElement.value.width
const imgHeight = handleElement.value.height
@ -226,27 +230,27 @@ export default defineComponent({
const originHeight = imgHeight / ((originClipRange[1][1] - originClipRange[0][1]) / 100)
const originLeft = imgLeft - originWidth * (originClipRange[0][0] / 100)
const originTop = imgTop - originHeight * (originClipRange[0][1] / 100)
//
if(shape === 'none') {
store.commit(MutationTypes.UPDATE_ELEMENT, {
id: handleElement.value.id,
props: {
left: originLeft,
top: originTop,
width: originWidth,
height: originHeight,
},
})
store.commit(MutationTypes.REMOVE_ELEMENT_PROP, {
id: handleElement.value.id,
propName: 'clip',
})
clipPanelVisible.value = false
}
return {
originClipRange,
originWidth,
originHeight,
originLeft,
originTop,
}
}
const presetImageClip = (shape: string, ratio = 0) => {
const {
originClipRange,
originWidth,
originHeight,
originLeft,
originTop,
} = getImageElementDataBeforeClip()
//
else if(ratio) {
if(ratio) {
const imageRatio = originHeight / originWidth
const min = 0
@ -271,9 +275,7 @@ export default defineComponent({
height: originHeight * (range[1][1] - range[0][1]) / 100,
},
})
clipImage()
}
//
else {
store.commit(MutationTypes.UPDATE_ELEMENT, {
@ -282,8 +284,46 @@ export default defineComponent({
clip: { ...handleElement.value.clip, shape, range: originClipRange }
},
})
clipImage()
}
clipImage()
addHistorySnapshot()
}
const replaceImage = (files: File[]) => {
const imageFile = files[0]
if(!imageFile) return
getImageDataURL(imageFile).then(dataURL => {
const props = { src: dataURL }
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
})
addHistorySnapshot()
}
const resetImage = () => {
if(handleElement.value.clip) {
const {
originWidth,
originHeight,
originLeft,
originTop,
} = getImageElementDataBeforeClip()
store.commit(MutationTypes.UPDATE_ELEMENT, {
id: handleElement.value.id,
props: {
left: originLeft,
top: originTop,
width: originWidth,
height: originHeight,
},
})
}
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, {
id: handleElement.value.id,
propName: ['clip', 'outline', 'flip', 'shadow', 'filter'],
})
addHistorySnapshot()
}
return {
@ -297,6 +337,8 @@ export default defineComponent({
updateFilter,
clipImage,
presetImageClip,
replaceImage,
resetImage,
}
},
})

View File

@ -10,7 +10,7 @@
<div class="row">
<div style="flex: 2;">水平阴影</div>
<Slider
:min="1"
:min="0"
:max="10"
:step="1"
:value="shadow.h"
@ -21,7 +21,7 @@
<div class="row">
<div style="flex: 2;">垂直阴影</div>
<Slider
:min="1"
:min="0"
:max="10"
:step="1"
:value="shadow.v"