feat: 添加形状翻转

This commit is contained in:
pipipi-pikachu 2021-02-09 15:30:55 +08:00
parent 5910c3fce3
commit 2838426ca9
10 changed files with 130 additions and 58 deletions

View File

@ -70,6 +70,7 @@ npm run serve
- 边框
- 阴影
- 透明度
- 翻转
### 线条
- 颜色
- 宽度

View File

@ -41,6 +41,10 @@ export interface PPTTextElement {
shadow?: PPTElementShadow;
}
export interface ImageOrShapeFlip {
x?: number;
y?: number;
}
export interface ImageElementFilters {
'blur'?: string;
'brightness'?: string;
@ -68,7 +72,7 @@ export interface PPTImageElement {
range: [[number, number], [number, number]];
shape: 'rect' | 'roundRect' | 'ellipse' | 'triangle' | 'pentagon' | 'rhombus' | 'star';
};
flip?: { x?: number; y?: number };
flip?: ImageOrShapeFlip;
shadow?: PPTElementShadow;
}
@ -94,6 +98,7 @@ export interface PPTShapeElement {
rotate?: number;
outline?: PPTElementOutline;
opacity?: number;
flip?: ImageOrShapeFlip;
shadow?: PPTElementShadow;
}

View File

@ -58,20 +58,8 @@
</template>
<Button class="full-width-btn"><IconColorFilter class="btn-icon" /> 设置滤镜</Button>
</Popover>
<CheckboxButtonGroup class="row">
<CheckboxButton
style="flex: 1;"
:checked="flip.x === 180"
@click="updateImage({ flip: { x: flip.x === 180 ? 0 : 180, y: flip.y } })"
><IconFlipVertically /> 水平翻转</CheckboxButton>
<CheckboxButton
style="flex: 1;"
:checked="flip.y === 180"
@click="updateImage({ flip: { x: flip.x, y: flip.y === 180 ? 0 : 180 } })"
><IconFlipHorizontally /> 垂直翻转</CheckboxButton>
</CheckboxButtonGroup>
<ElementFlip />
<Divider />
<ElementOutline />
<Divider />
@ -96,6 +84,7 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
interface FilterOption {
label: string;
@ -156,6 +145,7 @@ export default defineComponent({
components: {
ElementOutline,
ElementShadow,
ElementFlip,
},
setup() {
const store = useStore()
@ -164,24 +154,11 @@ export default defineComponent({
const clipPanelVisible = ref(false)
const flip = ref({
x: 0,
y: 0,
})
const filterOptions = ref<FilterOption[]>(JSON.parse(JSON.stringify(defaultFilters)))
watch(handleElement, () => {
if (!handleElement.value || handleElement.value.type !== 'image') return
if (handleElement.value.flip) {
flip.value = {
x: handleElement.value.flip.x || 0,
y: handleElement.value.flip.y || 0,
}
}
else flip.value = { x: 0, y: 0 }
const filters = handleElement.value.filters
if (filters) {
filterOptions.value = defaultFilters.map(item => {
@ -194,11 +171,6 @@ export default defineComponent({
const { addHistorySnapshot } = useHistorySnapshot()
const updateImage = (props: Partial<PPTImageElement>) => {
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
addHistorySnapshot()
}
const updateFilter = (filter: FilterOption, value: number) => {
const originFilters = handleElement.value.filters || {}
const filters = { ...originFilters, [filter.key]: `${value}${filter.unit}` }
@ -337,9 +309,7 @@ export default defineComponent({
shapeClipPathOptions,
ratioClipOptions,
filterOptions,
flip,
handleElement,
updateImage,
updateFilter,
clipImage,
presetImageClip,

View File

@ -68,6 +68,7 @@
</div>
</template>
<ElementFlip />
<Divider />
<ElementOutline />
<Divider />
@ -86,6 +87,7 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ElementOpacity from '../common/ElementOpacity.vue'
import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
import ColorButton from '../common/ColorButton.vue'
export default defineComponent({
@ -94,6 +96,7 @@ export default defineComponent({
ElementOpacity,
ElementOutline,
ElementShadow,
ElementFlip,
ColorButton,
},
setup() {

View File

@ -0,0 +1,70 @@
<template>
<div class="element-flip">
<CheckboxButtonGroup class="row">
<CheckboxButton
style="flex: 1;"
:checked="flip.x === 180"
@click="updateFlip({ x: flip.x === 180 ? 0 : 180, y: flip.y })"
><IconFlipVertically /> 水平翻转</CheckboxButton>
<CheckboxButton
style="flex: 1;"
:checked="flip.y === 180"
@click="updateFlip({ x: flip.x, y: flip.y === 180 ? 0 : 180 })"
><IconFlipHorizontally /> 垂直翻转</CheckboxButton>
</CheckboxButtonGroup>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref, watch } from 'vue'
import { MutationTypes, useStore } from '@/store'
import { PPTImageElement, PPTShapeElement } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
export default defineComponent({
name: 'element-flip',
setup() {
const store = useStore()
const handleElement = computed<PPTImageElement | PPTShapeElement>(() => store.getters.handleElement)
const flip = ref({
x: 0,
y: 0,
})
watch(handleElement, () => {
if (!handleElement.value || !['image', 'shape'].includes(handleElement.value.type)) return
if (handleElement.value.flip) {
flip.value = {
x: handleElement.value.flip.x || 0,
y: handleElement.value.flip.y || 0,
}
}
else flip.value = { x: 0, y: 0 }
}, { deep: true, immediate: true })
const { addHistorySnapshot } = useHistorySnapshot()
const updateFlip = (value: number) => {
const props = { flip: value }
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
addHistorySnapshot()
}
return {
flip,
updateFlip,
}
},
})
</script>
<style lang="scss" scoped>
.row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
}
</style>

View File

@ -13,7 +13,7 @@
class="element-content"
:style="{
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
transform: flip,
transform: flipStyle,
}"
>
<ImageRectOutline
@ -66,6 +66,7 @@ import ImageEllipseOutline from './ImageEllipseOutline.vue'
import ImagePolygonOutline from './ImagePolygonOutline.vue'
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
import useElementFlip from '@/views/components/element/hooks/useElementFlip'
export default defineComponent({
name: 'base-element-image',
@ -122,23 +123,17 @@ export default defineComponent({
return filter
})
const flip = computed(() => {
if (!props.elementInfo.flip) return ''
const { x, y } = props.elementInfo.flip
if (x && y) return `rotateX(${x}deg) rotateY(${y}deg)`
else if (x) return `rotateX(${x}deg)`
else if (y) return `rotateY(${y}deg)`
return ''
})
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
const flip = computed(() => props.elementInfo.flip)
const { flipStyle } = useElementFlip(flip)
return {
imgPosition,
clipShape,
filter,
flip,
flipStyle,
shadowStyle,
}
},

View File

@ -28,7 +28,7 @@
v-contextmenu="contextmenus"
:style="{
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
transform: flip,
transform: flipStyle,
}"
>
<ImageRectOutline
@ -77,6 +77,7 @@ import { PPTImageElement } from '@/types/slides'
import { ContextmenuItem } from '@/components/Contextmenu/types'
import { CLIPPATHS, ClipPathTypes } from '@/configs/imageClip'
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
import useElementFlip from '@/views/components/element/hooks/useElementFlip'
import ImageRectOutline from './ImageRectOutline.vue'
import ImageEllipseOutline from './ImageEllipseOutline.vue'
@ -113,6 +114,9 @@ export default defineComponent({
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
const flip = computed(() => props.elementInfo.flip)
const { flipStyle } = useElementFlip(flip)
const handleSelectElement = (e: MouseEvent) => {
if (props.elementInfo.lock) return
e.stopPropagation()
@ -159,15 +163,6 @@ export default defineComponent({
return filter
})
const flip = computed(() => {
if (!props.elementInfo.flip) return ''
const { x, y } = props.elementInfo.flip
if (x && y) return `rotateX(${x}deg) rotateY(${y}deg)`
else if (x) return `rotateX(${x}deg)`
else if (y) return `rotateY(${y}deg)`
return ''
})
const clip = (data: ImageClipedEmitData) => {
store.commit(MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID, '')
@ -195,7 +190,7 @@ export default defineComponent({
clipShape,
imgPosition,
filter,
flip,
flipStyle,
}
},
})

View File

@ -14,6 +14,7 @@
:style="{
opacity: elementInfo.opacity,
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
transform: flipStyle,
}"
>
<SvgWrapper
@ -55,6 +56,7 @@ import { computed, defineComponent, PropType } from 'vue'
import { PPTShapeElement } from '@/types/slides'
import useElementOutline from '@/views/components/element/hooks/useElementOutline'
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
import useElementFlip from '@/views/components/element/hooks/useElementFlip'
import GradientDefs from './GradientDefs.vue'
@ -76,11 +78,15 @@ export default defineComponent({
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
const flip = computed(() => props.elementInfo.flip)
const { flipStyle } = useElementFlip(flip)
return {
shadowStyle,
outlineWidth,
outlineStyle,
outlineColor,
flipStyle,
}
},
})

View File

@ -17,6 +17,7 @@
:style="{
opacity: elementInfo.opacity,
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
transform: flipStyle,
}"
>
<SvgWrapper
@ -59,6 +60,7 @@ import { PPTShapeElement } from '@/types/slides'
import { ContextmenuItem } from '@/components/Contextmenu/types'
import useElementOutline from '@/views/components/element/hooks/useElementOutline'
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
import useElementFlip from '@/views/components/element/hooks/useElementFlip'
import GradientDefs from './GradientDefs.vue'
@ -94,12 +96,16 @@ export default defineComponent({
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
const flip = computed(() => props.elementInfo.flip)
const { flipStyle } = useElementFlip(flip)
return {
handleSelectElement,
shadowStyle,
outlineWidth,
outlineStyle,
outlineColor,
flipStyle,
}
},
})

View File

@ -0,0 +1,21 @@
import { ref, Ref, watchEffect } from 'vue'
import { ImageOrShapeFlip } from '@/types/slides'
export default (flip: Ref<ImageOrShapeFlip | undefined>) => {
const flipStyle = ref('')
watchEffect(() => {
if (flip.value) {
const { x, y } = flip.value
if (x && y) flipStyle.value = `rotateX(${x}deg) rotateY(${y}deg)`
else if (x) flipStyle.value = `rotateX(${x}deg)`
else if (y) flipStyle.value = `rotateY(${y}deg)`
else flipStyle.value = ''
}
else flipStyle.value = ''
})
return {
flipStyle,
}
}