feat: 支持图片着色(蒙版)

This commit is contained in:
pipipi-pikachu 2022-07-16 21:13:39 +08:00
parent 06edd83960
commit 52e2142434
5 changed files with 145 additions and 1 deletions

View File

@ -211,6 +211,18 @@ export interface ImageElementClip {
shape: string
}
/**
*
*
* color: 蒙版颜色
*
* opacity: 蒙版透明度
*/
export interface ImageColorElementMask {
color: string
opacity: number
}
/**
*
*
@ -242,6 +254,7 @@ export interface PPTImageElement extends PPTBaseElement {
flipH?: boolean
flipV?: boolean
shadow?: PPTElementShadow
colorMask?: ImageColorElementMask
}

View File

@ -41,6 +41,8 @@
</Popover>
</ButtonGroup>
<Divider />
<ElementColorMask />
<Divider />
<ElementFilter />
<Divider />
@ -70,6 +72,7 @@ import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
import ElementFilter from '../common/ElementFilter.vue'
import ElementColorMask from '../common/ElementColorMask.vue'
const shapeClipPathOptions = CLIPPATHS
const ratioClipOptions = [
@ -235,7 +238,7 @@ const resetImage = () => {
slidesStore.removeElementProps({
id: handleElementId.value,
propName: ['clip', 'outline', 'flip', 'shadow', 'filters'],
propName: ['clip', 'outline', 'flip', 'shadow', 'filters', 'colorMask'],
})
addHistorySnapshot()
}

View File

@ -0,0 +1,100 @@
<template>
<div class="element-color-mask">
<div class="row">
<div style="flex: 1;">重新着色蒙版</div>
<div class="switch-wrapper" style="flex: 1;">
<Switch
:checked="hasColorMask"
@change="checked => toggleColorMask(checked as boolean)"
/>
</div>
</div>
<template v-if="hasColorMask">
<div class="row" style="margin-top: 15px;">
<div style="flex: 2;">蒙版颜色</div>
<Popover trigger="click">
<template #content>
<ColorPicker
:modelValue="colorMask.color"
@update:modelValue="value => updateColorMask({ color: value })"
/>
</template>
<ColorButton :color="colorMask.color" style="flex: 3;" />
</Popover>
</div>
<div class="row">
<div style="flex: 2;">不透明度</div>
<Slider
class="opacity-slider"
:max="1"
:min="0"
:step="0.05"
:value="colorMask.opacity"
@change="value => updateColorMask({ opacity: value as number })"
/>
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import { ImageColorElementMask } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ColorButton from './ColorButton.vue'
const defaultColorMask = { color: 'transparent', opacity: 0.3 }
const slidesStore = useSlidesStore()
const { handleElement, handleElementId } = storeToRefs(useMainStore())
const colorMask = ref<ImageColorElementMask>(defaultColorMask)
const hasColorMask = ref(false)
const { addHistorySnapshot } = useHistorySnapshot()
watch(handleElement, () => {
if (!handleElement.value || handleElement.value.type !== 'image') return
if (handleElement.value.colorMask) {
colorMask.value = handleElement.value.colorMask
hasColorMask.value = true
}
else hasColorMask.value = false
}, { deep: true, immediate: true })
const toggleColorMask = (checked: boolean) => {
if (!handleElement.value) return
if (checked) {
slidesStore.updateElement({ id: handleElement.value.id, props: { colorMask: defaultColorMask } })
}
else {
slidesStore.removeElementProps({ id: handleElement.value.id, propName: 'colorMask' })
}
addHistorySnapshot()
}
const updateColorMask = (colorMaskProp: Partial<ImageColorElementMask>) => {
const newColorMask = { ...colorMask.value, ...colorMaskProp }
slidesStore.updateElement({ id: handleElementId.value, props: { colorMask: newColorMask } })
addHistorySnapshot()
}
</script>
<style lang="scss" scoped>
.row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.switch-wrapper {
text-align: right;
}
.opacity-slider {
flex: 3;
}
</style>

View File

@ -34,6 +34,13 @@
}"
alt=""
/>
<div class="color-mask"
v-if="elementInfo.colorMask"
:style="{
backgroundColor: elementInfo.colorMask.color,
opacity: elementInfo.colorMask.opacity,
}"
></div>
</div>
</div>
</div>
@ -95,4 +102,11 @@ const { filter } = useFilter(filters)
position: absolute;
}
}
.color-mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>

View File

@ -52,6 +52,13 @@
@dragstart.prevent
alt=""
/>
<div class="color-mask"
v-if="elementInfo.colorMask"
:style="{
backgroundColor: elementInfo.colorMask.color,
opacity: elementInfo.colorMask.opacity,
}"
></div>
</div>
</div>
</div>
@ -185,4 +192,11 @@ const handleClip = (data: ImageClipedEmitData | null) => {
position: absolute;
}
}
.color-mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>