|
@@ -0,0 +1,76 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { useDesign } from '@/hooks/web/useDesign'
|
|
|
+import { propTypes } from '@/utils/propTypes'
|
|
|
+import { CSSProperties, computed } from 'vue'
|
|
|
+
|
|
|
+const { getPrefixCls } = useDesign()
|
|
|
+
|
|
|
+const prefixCls = getPrefixCls('image-cropping')
|
|
|
+
|
|
|
+const bgIcon =
|
|
|
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ imageUrl: propTypes.string,
|
|
|
+ boxWidth: propTypes.oneOfType([propTypes.number, propTypes.string]).def('100%'),
|
|
|
+ boxHeight: propTypes.oneOfType([propTypes.number, propTypes.string]).def('100%'),
|
|
|
+ dragWidth: propTypes.oneOfType([propTypes.number, propTypes.string]).def(200),
|
|
|
+ dragHeight: propTypes.oneOfType([propTypes.number, propTypes.string]).def(200),
|
|
|
+ cropWidth: propTypes.oneOfType([propTypes.number, propTypes.string]).def(200),
|
|
|
+ cropHeight: propTypes.oneOfType([propTypes.number, propTypes.string]).def(200)
|
|
|
+})
|
|
|
+
|
|
|
+const boxStyles = computed((): CSSProperties => {
|
|
|
+ return {
|
|
|
+ width: (typeof props.boxWidth === 'number' ? `${props.boxWidth}px` : props.boxWidth) ?? '100%',
|
|
|
+ height:
|
|
|
+ (typeof props.boxHeight === 'number' ? `${props.boxHeight}px` : props.boxHeight) ?? '100%',
|
|
|
+ position: 'relative',
|
|
|
+ backgroundImage: `url(${bgIcon})`
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const dragStyles = computed((): CSSProperties => {
|
|
|
+ return {
|
|
|
+ width: (typeof props.dragWidth === 'number' ? `${props.dragWidth}px` : props.dragWidth) ?? 200,
|
|
|
+ height:
|
|
|
+ (typeof props.dragHeight === 'number' ? `${props.dragHeight}px` : props.dragHeight) ?? 200,
|
|
|
+ position: 'absolute',
|
|
|
+ top: '50%',
|
|
|
+ left: '50%',
|
|
|
+ transform: 'translate(-50%, -50%)',
|
|
|
+ zIndex: 1,
|
|
|
+ boxShadow: '0 0 0 1px var(--el-color-primary),0 0 0 10000px rgba(0,0,0,.5)',
|
|
|
+ cursor: 'move'
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const cropStyles = computed((): CSSProperties => {
|
|
|
+ return {
|
|
|
+ width: (typeof props.cropWidth === 'number' ? `${props.cropWidth}px` : props.cropWidth) ?? 300,
|
|
|
+ height:
|
|
|
+ (typeof props.cropHeight === 'number' ? `${props.cropHeight}px` : props.cropHeight) ?? 300,
|
|
|
+ position: 'absolute',
|
|
|
+ top: '50%',
|
|
|
+ left: '80px',
|
|
|
+ transform: 'translate(0, -50%)',
|
|
|
+ overflow: 'hidden',
|
|
|
+ borderRadius: '50%',
|
|
|
+ border: '1px solid var(--el-border-color)'
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div :class="prefixCls" class="flex">
|
|
|
+ <div class="flex-1">
|
|
|
+ <div :style="boxStyles">
|
|
|
+ <img :src="imageUrl" class="w-full absolute top-[50%] left-[50%]" alt="" srcset="" />
|
|
|
+ <div :style="dragStyles"> </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="relative w-full">
|
|
|
+ <div :style="cropStyles"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|