This commit is contained in:
pipipi-pikachu 2021-01-11 21:30:55 +08:00
parent f100f2cd9e
commit 653bf033a7
3 changed files with 540 additions and 560 deletions

View File

@ -1,24 +1,5 @@
<template> <template>
<div <div class="image-element-operate" :class="{ 'cliping': isCliping }">
class="clip-wrapper"
:style="{
width: elementInfo.width + 'px',
height: elementInfo.height + 'px',
}"
v-if="isCliping"
>
<ImageClipHandler
:src="elementInfo.src"
:clipData="elementInfo.clip"
:width="elementInfo.width"
:height="elementInfo.height"
:top="elementInfo.top"
:left="elementInfo.left"
:clipPath="clipShape.style"
@clip="range => clip(range)"
/>
</div>
<div class="image-element-operate" v-else>
<BorderLine <BorderLine
class="operate-border-line" class="operate-border-line"
v-for="line in borderLines" v-for="line in borderLines"
@ -47,16 +28,14 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType } from 'vue' import { computed, defineComponent, PropType } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { MutationTypes, State } from '@/store' import { State } from '@/store'
import { PPTImageElement } from '@/types/slides' import { PPTImageElement } from '@/types/slides'
import { OperateResizeHandler, ImageClipedEmitData } from '@/types/edit' import { OperateResizeHandler } from '@/types/edit'
import { CLIPPATHS, ClipPathTypes } from '@/configs/imageClip'
import useCommonOperate from '../hooks/useCommonOperate' import useCommonOperate from '../hooks/useCommonOperate'
import RotateHandler from './RotateHandler.vue' import RotateHandler from './RotateHandler.vue'
import ResizeHandler from './ResizeHandler.vue' import ResizeHandler from './ResizeHandler.vue'
import BorderLine from './BorderLine.vue' import BorderLine from './BorderLine.vue'
import ImageClipHandler from './ImageClipHandler.vue'
export default defineComponent({ export default defineComponent({
name: 'image-element-operate', name: 'image-element-operate',
@ -65,7 +44,6 @@ export default defineComponent({
RotateHandler, RotateHandler,
ResizeHandler, ResizeHandler,
BorderLine, BorderLine,
ImageClipHandler,
}, },
props: { props: {
elementInfo: { elementInfo: {
@ -93,52 +71,24 @@ export default defineComponent({
const store = useStore<State>() const store = useStore<State>()
const canvasScale = computed(() => store.state.canvasScale) const canvasScale = computed(() => store.state.canvasScale)
const clipingImageElementId = computed(() => store.state.clipingImageElementId) const clipingImageElementId = computed(() => store.state.clipingImageElementId)
const isCliping = computed(() => clipingImageElementId.value === props.elementInfo.id)
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value) const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value) const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
const { resizeHandlers, borderLines } = useCommonOperate(scaleWidth, scaleHeight) const { resizeHandlers, borderLines } = useCommonOperate(scaleWidth, scaleHeight)
const clipShape = computed(() => {
if(!props.elementInfo || !props.elementInfo.clip) return CLIPPATHS.rect
const shape = props.elementInfo.clip.shape || ClipPathTypes.RECT
return CLIPPATHS[shape]
})
const isCliping = computed(() => clipingImageElementId.value === props.elementInfo.id)
const clip = (data: ImageClipedEmitData) => {
store.commit(MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID, '')
if(!data) return
const { range, position } = data
const originClip = props.elementInfo.clip || {}
const _props = {
clip: { ...originClip, range },
left: props.elementInfo.left + position.left,
top: props.elementInfo.top + position.top,
width: props.elementInfo.width + position.width,
height: props.elementInfo.height + position.height,
}
console.log(_props)
}
return { return {
clipShape, isCliping,
scaleWidth, scaleWidth,
resizeHandlers, resizeHandlers,
borderLines, borderLines,
isCliping,
clip,
} }
}, },
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.clip-wrapper { .image-element-operate.cliping {
position: relative; visibility: hidden;
} }
</style> </style>

View File

@ -1,494 +1,496 @@
<template> <template>
<div <div
class="image-clip-handler" class="image-clip-handler"
:style="clipWrapperPositionStyle" :style="clipWrapperPositionStyle"
v-click-outside="clip" v-click-outside="handleClip"
> >
<img <img
class="bottom-img" class="bottom-img"
:src="src" :src="src"
:draggable="false" :draggable="false"
alt="" alt=""
:style="bottomImgPositionStyle" :style="bottomImgPositionStyle"
/> />
<div <div
class="top-image-content" class="top-image-content"
:style="{ :style="{
...topImgWrapperPositionStyle, ...topImgWrapperPositionStyle,
clipPath, clipPath,
}" }"
> >
<img <img
class="top-img" class="top-img"
:src="src" :src="src"
:draggable="false" :draggable="false"
alt="" alt=""
:style="topImgPositionStyle" :style="topImgPositionStyle"
/> />
</div> </div>
<div <div
class="operate" class="operate"
:style="topImgWrapperPositionStyle" :style="topImgWrapperPositionStyle"
@mousedown.stop="$event => moveClipRange($event)" @mousedown.stop="$event => moveClipRange($event)"
> >
<div <div
:class="['clip-point', point]" :class="['clip-point', point]"
v-for="point in ['t-l', 't-r', 'b-l', 'b-r']" v-for="point in ['t-l', 't-r', 'b-l', 'b-r']"
:key="point" :key="point"
@mousedown.stop="$event => scaleClipRange($event, point)" @mousedown.stop="$event => scaleClipRange($event, point)"
> >
<SvgWrapper width="12" height="12" fill="#fff" stroke="#666"> <SvgWrapper width="12" height="12" fill="#fff" stroke="#666">
<path d="M 12 0 L 0 0 L 0 12 L 3 12 L 3 3 L 12 3 L 12 0 Z"></path> <path d="M 12 0 L 0 0 L 0 12 L 3 12 L 3 3 L 12 3 L 12 0 Z"></path>
</SvgWrapper> </SvgWrapper>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted, PropType, reactive, ref } from 'vue' import { computed, defineComponent, onMounted, onUnmounted, PropType, reactive, ref } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { State } from '@/store' import { State } from '@/store'
import { KEYS } from '@/configs/hotkey' import { KEYS } from '@/configs/hotkey'
import { ImageClipData, ImageClipDataRange, ImageClipedEmitData } from '@/types/edit' import { ImageClipData, ImageClipDataRange, ImageClipedEmitData } from '@/types/edit'
type ScaleClipRangeType = 't-l' | 't-r' | 'b-l' | 'b-r' type ScaleClipRangeType = 't-l' | 't-r' | 'b-l' | 'b-r'
export default defineComponent({ export default defineComponent({
name: 'image-clip-handler', name: 'image-clip-handler',
props: { props: {
src: { src: {
type: String, type: String,
required: true, required: true,
}, },
clipData: { clipData: {
type: Object as PropType<ImageClipData>, type: Object as PropType<ImageClipData>,
}, },
clipPath: { clipPath: {
type: String, type: String,
required: true, required: true,
}, },
width: { width: {
type: Number, type: Number,
required: true, required: true,
}, },
height: { height: {
type: Number, type: Number,
required: true, required: true,
}, },
top: { top: {
type: Number, type: Number,
required: true, required: true,
}, },
left: { left: {
type: Number, type: Number,
required: true, required: true,
}, },
}, },
setup(props, { emit }) { setup(props, { emit }) {
const store = useStore<State>() const store = useStore<State>()
const canvasScale = computed(() => store.state.canvasScale) const canvasScale = computed(() => store.state.canvasScale)
const topImgWrapperPosition = reactive({ const topImgWrapperPosition = reactive({
top: 0, top: 0,
left: 0, left: 0,
width: 0, width: 0,
height: 0, height: 0,
}) })
const clipWrapperPositionStyle = reactive({ const clipWrapperPositionStyle = reactive({
top: '0', top: '0',
left: '0', left: '0',
}) })
const isSettingClipRange = ref(false) const isSettingClipRange = ref(false)
const currentRange = ref<ImageClipDataRange | null>(null) const currentRange = ref<ImageClipDataRange | null>(null)
const getClipDataTransformInfo = () => { const getClipDataTransformInfo = () => {
const [start, end] = props.clipData ? props.clipData.range : [[0, 0], [100, 100]] const [start, end] = props.clipData ? props.clipData.range : [[0, 0], [100, 100]]
const widthScale = (end[0] - start[0]) / 100 const widthScale = (end[0] - start[0]) / 100
const heightScale = (end[1] - start[1]) / 100 const heightScale = (end[1] - start[1]) / 100
const left = start[0] / widthScale const left = start[0] / widthScale
const top = start[1] / heightScale const top = start[1] / heightScale
return { widthScale, heightScale, left, top } return { widthScale, heightScale, left, top }
} }
const imgPosition = computed(() => { const imgPosition = computed(() => {
const { widthScale, heightScale, left, top } = getClipDataTransformInfo() const { widthScale, heightScale, left, top } = getClipDataTransformInfo()
return { return {
left: -left, left: -left,
top: -top, top: -top,
width: 100 / widthScale, width: 100 / widthScale,
height: 100 / heightScale, height: 100 / heightScale,
} }
}) })
const bottomImgPositionStyle = computed(() => { const bottomImgPositionStyle = computed(() => {
return { return {
top: imgPosition.value.top + '%', top: imgPosition.value.top + '%',
left: imgPosition.value.left + '%', left: imgPosition.value.left + '%',
width: imgPosition.value.width + '%', width: imgPosition.value.width + '%',
height: imgPosition.value.height + '%', height: imgPosition.value.height + '%',
} }
}) })
const topImgWrapperPositionStyle = computed(() => { const topImgWrapperPositionStyle = computed(() => {
return { return {
top: topImgWrapperPosition.top + '%', top: topImgWrapperPosition.top + '%',
left: topImgWrapperPosition.left + '%', left: topImgWrapperPosition.left + '%',
width: topImgWrapperPosition.width + '%', width: topImgWrapperPosition.width + '%',
height: topImgWrapperPosition.height + '%', height: topImgWrapperPosition.height + '%',
} }
}) })
const topImgPositionStyle = computed(() => { const topImgPositionStyle = computed(() => {
const bottomWidth = imgPosition.value.width const bottomWidth = imgPosition.value.width
const bottomHeight = imgPosition.value.height const bottomHeight = imgPosition.value.height
const topLeft = topImgWrapperPosition.left const topLeft = topImgWrapperPosition.left
const topTop = topImgWrapperPosition.top const topTop = topImgWrapperPosition.top
const topWidth = topImgWrapperPosition.width const topWidth = topImgWrapperPosition.width
const topHeight = topImgWrapperPosition.height const topHeight = topImgWrapperPosition.height
return { return {
left: -topLeft * (100 / topWidth) + '%', left: -topLeft * (100 / topWidth) + '%',
top: -topTop * (100 / topHeight) + '%', top: -topTop * (100 / topHeight) + '%',
width: bottomWidth / topWidth * 100 + '%', width: bottomWidth / topWidth * 100 + '%',
height: bottomHeight / topHeight * 100 + '%', height: bottomHeight / topHeight * 100 + '%',
} }
}) })
const initClipPosition = () => { const initClipPosition = () => {
const { left, top } = getClipDataTransformInfo() const { left, top } = getClipDataTransformInfo()
topImgWrapperPosition.left = left topImgWrapperPosition.left = left
topImgWrapperPosition.top = top topImgWrapperPosition.top = top
topImgWrapperPosition.width = 100 topImgWrapperPosition.width = 100
topImgWrapperPosition.height = 100 topImgWrapperPosition.height = 100
clipWrapperPositionStyle.top = -top + '%' clipWrapperPositionStyle.top = -top + '%'
clipWrapperPositionStyle.left = -left + '%' clipWrapperPositionStyle.left = -left + '%'
} }
const clip = () => { const handleClip = () => {
if(isSettingClipRange.value || !currentRange.value) { if(isSettingClipRange.value) return
emit('clip', null)
return if(!currentRange.value) {
} emit('clip', null)
return
const { left, top } = getClipDataTransformInfo() }
const position = { const { left, top } = getClipDataTransformInfo()
left: (topImgWrapperPosition.left - left) / 100 * props.width,
top: (topImgWrapperPosition.top - top) / 100 * props.height, const position = {
width: (topImgWrapperPosition.width - 100) / 100 * props.width, left: (topImgWrapperPosition.left - left) / 100 * props.width,
height: (topImgWrapperPosition.height - 100) / 100 * props.height, top: (topImgWrapperPosition.top - top) / 100 * props.height,
} width: (topImgWrapperPosition.width - 100) / 100 * props.width,
height: (topImgWrapperPosition.height - 100) / 100 * props.height,
const clipedEmitData: ImageClipedEmitData = { }
range: currentRange.value,
position, const clipedEmitData: ImageClipedEmitData = {
} range: currentRange.value,
emit('clip', clipedEmitData) position,
} }
emit('clip', clipedEmitData)
const keyboardClip = (e: KeyboardEvent) => { }
const key = e.key.toUpperCase()
if(key === KEYS.ENTER) clip() const keyboardClip = (e: KeyboardEvent) => {
} const key = e.key.toUpperCase()
if(key === KEYS.ENTER) handleClip()
onMounted(() => { }
initClipPosition()
document.addEventListener('keydown', keyboardClip) onMounted(() => {
}) initClipPosition()
onUnmounted(() => { document.addEventListener('keydown', keyboardClip)
document.removeEventListener('keydown', keyboardClip) })
}) onUnmounted(() => {
document.removeEventListener('keydown', keyboardClip)
const getRange = () => { })
const retPosition = {
left: parseInt(topImgPositionStyle.value.left), const getRange = () => {
top: parseInt(topImgPositionStyle.value.top), const retPosition = {
width: parseInt(topImgPositionStyle.value.width), left: parseInt(topImgPositionStyle.value.left),
height: parseInt(topImgPositionStyle.value.height), top: parseInt(topImgPositionStyle.value.top),
} width: parseInt(topImgPositionStyle.value.width),
height: parseInt(topImgPositionStyle.value.height),
const widthScale = 100 / retPosition.width }
const heightScale = 100 / retPosition.height
const widthScale = 100 / retPosition.width
const start: [number, number] = [ const heightScale = 100 / retPosition.height
-retPosition.left * widthScale,
-retPosition.top * heightScale, const start: [number, number] = [
] -retPosition.left * widthScale,
const end: [number, number] = [ -retPosition.top * heightScale,
widthScale * 100 + start[0], ]
heightScale * 100 + start[1], const end: [number, number] = [
] widthScale * 100 + start[0],
heightScale * 100 + start[1],
currentRange.value = [start, end] ]
}
currentRange.value = [start, end]
const moveClipRange = (e: MouseEvent) => { }
isSettingClipRange.value = true
let isMouseDown = true const moveClipRange = (e: MouseEvent) => {
isSettingClipRange.value = true
const startPageX = e.pageX let isMouseDown = true
const startPageY = e.pageY
const bottomPosition = imgPosition.value const startPageX = e.pageX
const originPositopn = { const startPageY = e.pageY
left: topImgWrapperPosition.left, const bottomPosition = imgPosition.value
top: topImgWrapperPosition.top, const originPositopn = {
width: topImgWrapperPosition.width, left: topImgWrapperPosition.left,
height: topImgWrapperPosition.height, top: topImgWrapperPosition.top,
} width: topImgWrapperPosition.width,
height: topImgWrapperPosition.height,
document.onmousemove = e => { }
if(!isMouseDown) return
document.onmousemove = e => {
const currentPageX = e.pageX if(!isMouseDown) return
const currentPageY = e.pageY
const currentPageX = e.pageX
const moveX = (currentPageX - startPageX) / canvasScale.value / props.width * 100 const currentPageY = e.pageY
const moveY = (currentPageY - startPageY) / canvasScale.value / props.height * 100
const moveX = (currentPageX - startPageX) / canvasScale.value / props.width * 100
let targetLeft = originPositopn.left + moveX const moveY = (currentPageY - startPageY) / canvasScale.value / props.height * 100
let targetTop = originPositopn.top + moveY
let targetLeft = originPositopn.left + moveX
// let targetTop = originPositopn.top + moveY
if(targetLeft < 0) targetLeft = 0
else if(targetLeft + originPositopn.width > bottomPosition.width) { //
targetLeft = bottomPosition.width - originPositopn.width if(targetLeft < 0) targetLeft = 0
} else if(targetLeft + originPositopn.width > bottomPosition.width) {
if(targetTop < 0) targetTop = 0 targetLeft = bottomPosition.width - originPositopn.width
else if(targetTop + originPositopn.height > bottomPosition.height) { }
targetTop = bottomPosition.height - originPositopn.height if(targetTop < 0) targetTop = 0
} else if(targetTop + originPositopn.height > bottomPosition.height) {
targetTop = bottomPosition.height - originPositopn.height
topImgWrapperPosition.left = targetLeft }
topImgWrapperPosition.top = targetTop
} topImgWrapperPosition.left = targetLeft
topImgWrapperPosition.top = targetTop
document.onmouseup = () => { }
isMouseDown = false
document.onmousemove = null document.onmouseup = () => {
document.onmouseup = null isMouseDown = false
document.onmousemove = null
getRange() document.onmouseup = null
setTimeout(() => { getRange()
isSettingClipRange.value = false
}, 0) setTimeout(() => {
} isSettingClipRange.value = false
} }, 0)
}
const scaleClipRange = (e: MouseEvent, type: ScaleClipRangeType) => { }
isSettingClipRange.value = true
let isMouseDown = true const scaleClipRange = (e: MouseEvent, type: ScaleClipRangeType) => {
isSettingClipRange.value = true
const minWidth = 32 / props.width * 100 let isMouseDown = true
const minHeight = 32 / props.height * 100
const minWidth = 32 / props.width * 100
const startPageX = e.pageX const minHeight = 32 / props.height * 100
const startPageY = e.pageY
const bottomPosition = imgPosition.value const startPageX = e.pageX
const originPositopn = { const startPageY = e.pageY
left: topImgWrapperPosition.left, const bottomPosition = imgPosition.value
top: topImgWrapperPosition.top, const originPositopn = {
width: topImgWrapperPosition.width, left: topImgWrapperPosition.left,
height: topImgWrapperPosition.height, top: topImgWrapperPosition.top,
} width: topImgWrapperPosition.width,
height: topImgWrapperPosition.height,
document.onmousemove = e => { }
if(!isMouseDown) return
document.onmousemove = e => {
const currentPageX = e.pageX if(!isMouseDown) return
const currentPageY = e.pageY
const currentPageX = e.pageX
let moveX = (currentPageX - startPageX) / canvasScale.value / props.width * 100 const currentPageY = e.pageY
let moveY = (currentPageY - startPageY) / canvasScale.value / props.height * 100
let moveX = (currentPageX - startPageX) / canvasScale.value / props.width * 100
let targetLeft, targetTop, targetWidth, targetHeight let moveY = (currentPageY - startPageY) / canvasScale.value / props.height * 100
// let targetLeft, targetTop, targetWidth, targetHeight
if(type === 't-l') {
if(originPositopn.left + moveX < 0) { //
moveX = -originPositopn.left if(type === 't-l') {
} if(originPositopn.left + moveX < 0) {
if(originPositopn.top + moveY < 0) { moveX = -originPositopn.left
moveY = -originPositopn.top }
} if(originPositopn.top + moveY < 0) {
if(originPositopn.width - moveX < minWidth) { moveY = -originPositopn.top
moveX = originPositopn.width - minWidth }
} if(originPositopn.width - moveX < minWidth) {
if(originPositopn.height - moveY < minHeight) { moveX = originPositopn.width - minWidth
moveY = originPositopn.height - minHeight }
} if(originPositopn.height - moveY < minHeight) {
targetWidth = originPositopn.width - moveX moveY = originPositopn.height - minHeight
targetHeight = originPositopn.height - moveY }
targetLeft = originPositopn.left + moveX targetWidth = originPositopn.width - moveX
targetTop = originPositopn.top + moveY targetHeight = originPositopn.height - moveY
} targetLeft = originPositopn.left + moveX
else if(type === 't-r') { targetTop = originPositopn.top + moveY
if(originPositopn.left + originPositopn.width + moveX > bottomPosition.width) { }
moveX = bottomPosition.width - (originPositopn.left + originPositopn.width) else if(type === 't-r') {
} if(originPositopn.left + originPositopn.width + moveX > bottomPosition.width) {
if(originPositopn.top + moveY < 0) { moveX = bottomPosition.width - (originPositopn.left + originPositopn.width)
moveY = -originPositopn.top }
} if(originPositopn.top + moveY < 0) {
if(originPositopn.width + moveX < minWidth) { moveY = -originPositopn.top
moveX = minWidth - originPositopn.width }
} if(originPositopn.width + moveX < minWidth) {
if(originPositopn.height - moveY < minHeight) { moveX = minWidth - originPositopn.width
moveY = originPositopn.height - minHeight }
} if(originPositopn.height - moveY < minHeight) {
targetWidth = originPositopn.width + moveX moveY = originPositopn.height - minHeight
targetHeight = originPositopn.height - moveY }
targetLeft = originPositopn.left targetWidth = originPositopn.width + moveX
targetTop = originPositopn.top + moveY targetHeight = originPositopn.height - moveY
} targetLeft = originPositopn.left
else if(type === 'b-l') { targetTop = originPositopn.top + moveY
if(originPositopn.left + moveX < 0) { }
moveX = -originPositopn.left else if(type === 'b-l') {
} if(originPositopn.left + moveX < 0) {
if(originPositopn.top + originPositopn.height + moveY > bottomPosition.height) { moveX = -originPositopn.left
moveY = bottomPosition.height - (originPositopn.top + originPositopn.height) }
} if(originPositopn.top + originPositopn.height + moveY > bottomPosition.height) {
if(originPositopn.width - moveX < minWidth) { moveY = bottomPosition.height - (originPositopn.top + originPositopn.height)
moveX = originPositopn.width - minWidth }
} if(originPositopn.width - moveX < minWidth) {
if(originPositopn.height + moveY < minHeight) { moveX = originPositopn.width - minWidth
moveY = minHeight - originPositopn.height }
} if(originPositopn.height + moveY < minHeight) {
targetWidth = originPositopn.width - moveX moveY = minHeight - originPositopn.height
targetHeight = originPositopn.height + moveY }
targetLeft = originPositopn.left + moveX targetWidth = originPositopn.width - moveX
targetTop = originPositopn.top targetHeight = originPositopn.height + moveY
} targetLeft = originPositopn.left + moveX
else { targetTop = originPositopn.top
if(originPositopn.left + originPositopn.width + moveX > bottomPosition.width) { }
moveX = bottomPosition.width - (originPositopn.left + originPositopn.width) else {
} if(originPositopn.left + originPositopn.width + moveX > bottomPosition.width) {
if(originPositopn.top + originPositopn.height + moveY > bottomPosition.height) { moveX = bottomPosition.width - (originPositopn.left + originPositopn.width)
moveY = bottomPosition.height - (originPositopn.top + originPositopn.height) }
} if(originPositopn.top + originPositopn.height + moveY > bottomPosition.height) {
if(originPositopn.width + moveX < minWidth) { moveY = bottomPosition.height - (originPositopn.top + originPositopn.height)
moveX = minWidth - originPositopn.width }
} if(originPositopn.width + moveX < minWidth) {
if(originPositopn.height + moveY < minHeight) { moveX = minWidth - originPositopn.width
moveY = minHeight - originPositopn.height }
} if(originPositopn.height + moveY < minHeight) {
targetWidth = originPositopn.width + moveX moveY = minHeight - originPositopn.height
targetHeight = originPositopn.height + moveY }
targetLeft = originPositopn.left targetWidth = originPositopn.width + moveX
targetTop = originPositopn.top targetHeight = originPositopn.height + moveY
} targetLeft = originPositopn.left
targetTop = originPositopn.top
topImgWrapperPosition.left = targetLeft }
topImgWrapperPosition.top = targetTop
topImgWrapperPosition.width = targetWidth topImgWrapperPosition.left = targetLeft
topImgWrapperPosition.height = targetHeight topImgWrapperPosition.top = targetTop
} topImgWrapperPosition.width = targetWidth
topImgWrapperPosition.height = targetHeight
document.onmouseup = () => { }
isMouseDown = false
document.onmousemove = null document.onmouseup = () => {
document.onmouseup = null isMouseDown = false
document.onmousemove = null
getRange() document.onmouseup = null
setTimeout(() => isSettingClipRange.value = false, 0) getRange()
}
} setTimeout(() => isSettingClipRange.value = false, 0)
}
return { }
clipWrapperPositionStyle,
bottomImgPositionStyle, return {
topImgWrapperPositionStyle, clipWrapperPositionStyle,
topImgPositionStyle, bottomImgPositionStyle,
clip, topImgWrapperPositionStyle,
moveClipRange, topImgPositionStyle,
scaleClipRange, handleClip,
} moveClipRange,
}, scaleClipRange,
}) }
</script> },
})
<style lang="scss" scoped> </script>
.image-clip-handler {
width: 100%; <style lang="scss" scoped>
height: 100%; .image-clip-handler {
position: relative; width: 100%;
height: 100%;
.bottom-img { position: relative;
top: 0;
left: 0; .bottom-img {
width: 100%; top: 0;
height: 100%; left: 0;
opacity: .5; width: 100%;
} height: 100%;
opacity: .5;
img { }
width: 100%;
height: 100%; img {
} width: 100%;
height: 100%;
.top-image-content { }
position: absolute;
overflow: hidden; .top-image-content {
position: absolute;
img { overflow: hidden;
position: absolute;
} img {
} position: absolute;
} }
}
.operate { }
position: absolute;
width: 100%; .operate {
height: 100%; position: absolute;
top: 0; width: 100%;
left: 0; height: 100%;
cursor: move; top: 0;
} left: 0;
cursor: move;
.clip-point { }
position: absolute;
width: 12px; .clip-point {
height: 12px; position: absolute;
left: 0; width: 12px;
top: 0; height: 12px;
transform-origin: 0 0; left: 0;
display: flex; top: 0;
justify-content: center; transform-origin: 0 0;
align-items: center; display: flex;
justify-content: center;
svg { align-items: center;
overflow: visible;
} svg {
overflow: visible;
&.t-l { }
cursor: nwse-resize;
left: 0; &.t-l {
top: 0; cursor: nwse-resize;
} left: 0;
&.t-r { top: 0;
cursor: nesw-resize; }
left: 100%; &.t-r {
top: 0; cursor: nesw-resize;
transform: rotate(90deg); left: 100%;
} top: 0;
&.b-l { transform: rotate(90deg);
cursor: nesw-resize; }
left: 0; &.b-l {
top: 100%; cursor: nesw-resize;
transform: rotate(-90deg); left: 0;
} top: 100%;
&.b-r { transform: rotate(-90deg);
cursor: nwse-resize; }
left: 100%; &.b-r {
top: 100%; cursor: nwse-resize;
transform: rotate(180deg); left: 100%;
} top: 100%;
} transform: rotate(180deg);
}
}
</style> </style>

View File

@ -1,10 +1,7 @@
<template> <template>
<div <div
class="editable-element-image" class="editable-element-image"
:class="{ :class="{ 'lock': elementInfo.lock }"
'lock': elementInfo.lock,
'cliping': clipingImageElementId === elementInfo.id,
}"
:style="{ :style="{
top: elementInfo.top + 'px', top: elementInfo.top + 'px',
left: elementInfo.left + 'px', left: elementInfo.left + 'px',
@ -14,8 +11,20 @@
}" }"
@mousedown="$event => handleSelectElement($event)" @mousedown="$event => handleSelectElement($event)"
> >
<ImageClipHandler
v-if="isCliping"
:src="elementInfo.src"
:clipData="elementInfo.clip"
:width="elementInfo.width"
:height="elementInfo.height"
:top="elementInfo.top"
:left="elementInfo.left"
:clipPath="clipShape.style"
@clip="range => clip(range)"
/>
<div <div
class="element-content" class="element-content"
v-else
v-contextmenu="contextmenus" v-contextmenu="contextmenus"
:style="{ :style="{
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '', filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
@ -64,7 +73,7 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType } from 'vue' import { computed, defineComponent, PropType } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { State } from '@/store' import { MutationTypes, State } from '@/store'
import { PPTImageElement } from '@/types/slides' import { PPTImageElement } from '@/types/slides'
import { ContextmenuItem } from '@/components/Contextmenu/types' import { ContextmenuItem } from '@/components/Contextmenu/types'
import { CLIPPATHS, ClipPathTypes } from '@/configs/imageClip' import { CLIPPATHS, ClipPathTypes } from '@/configs/imageClip'
@ -73,7 +82,8 @@ import useElementShadow from '@/views/components/element/hooks/useElementShadow'
import ImageRectOutline from './ImageRectOutline.vue' import ImageRectOutline from './ImageRectOutline.vue'
import ImageEllipseOutline from './ImageEllipseOutline.vue' import ImageEllipseOutline from './ImageEllipseOutline.vue'
import ImagePolygonOutline from './ImagePolygonOutline.vue' import ImagePolygonOutline from './ImagePolygonOutline.vue'
import ImageClipHandler from './ImageClipHandler.vue'
import { ImageClipedEmitData } from '@/types/edit'
export default defineComponent({ export default defineComponent({
name: 'editable-element-image', name: 'editable-element-image',
@ -81,6 +91,7 @@ export default defineComponent({
ImageRectOutline, ImageRectOutline,
ImageEllipseOutline, ImageEllipseOutline,
ImagePolygonOutline, ImagePolygonOutline,
ImageClipHandler,
}, },
props: { props: {
elementInfo: { elementInfo: {
@ -98,6 +109,7 @@ export default defineComponent({
setup(props) { setup(props) {
const store = useStore<State>() const store = useStore<State>()
const clipingImageElementId = computed(() => store.state.clipingImageElementId) const clipingImageElementId = computed(() => store.state.clipingImageElementId)
const isCliping = computed(() => clipingImageElementId.value === props.elementInfo.id)
const shadow = computed(() => props.elementInfo.shadow) const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow) const { shadowStyle } = useElementShadow(shadow)
@ -157,7 +169,27 @@ export default defineComponent({
return '' return ''
}) })
const clip = (data: ImageClipedEmitData) => {
store.commit(MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID, '')
if(!data) return
const { range, position } = data
const originClip = props.elementInfo.clip || {}
const _props = {
clip: { ...originClip, range },
left: props.elementInfo.left + position.left,
top: props.elementInfo.top + position.top,
width: props.elementInfo.width + position.width,
height: props.elementInfo.height + position.height,
}
store.commit(MutationTypes.UPDATE_ELEMENT, { id: props.elementInfo.id, props: _props })
}
return { return {
isCliping,
clip,
clipingImageElementId, clipingImageElementId,
shadowStyle, shadowStyle,
handleSelectElement, handleSelectElement,
@ -177,10 +209,6 @@ export default defineComponent({
&.lock .element-content { &.lock .element-content {
cursor: default; cursor: default;
} }
&.cliping {
visibility: hidden;
}
} }
.element-content { .element-content {