深度画布bug
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# VITE_APP_URL = http://192.168.31.82:8771
|
# VITE_APP_URL = http://192.168.31.82:8771
|
||||||
VITE_APP_URL = http://18.167.251.121:10015
|
VITE_APP_URL = http://18.167.251.121:10015
|
||||||
# VITE_APP_URL = http://192.168.31.118:8080
|
# VITE_APP_URL = http://192.168.31.118:8080
|
||||||
VITE_APP_URL = http://192.168.31.82:8755
|
# VITE_APP_URL = http://192.168.31.82:8755
|
||||||
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
|
|||||||
@@ -103,3 +103,12 @@ body,
|
|||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
.mosaic-bg {
|
||||||
|
--mosaic-bg-size: 1rem;
|
||||||
|
--mosaic-bg-color1: #efefef;
|
||||||
|
--mosaic-bg-color2: #fff;
|
||||||
|
background-image: repeating-conic-gradient(var(--mosaic-bg-color1) 0% 25%, var(--mosaic-bg-color2) 0% 50%);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,3 +117,13 @@ body,
|
|||||||
background: rgba(0, 0, 0, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mosaic-bg{
|
||||||
|
--mosaic-bg-size: 1rem;
|
||||||
|
--mosaic-bg-color1: #efefef;
|
||||||
|
--mosaic-bg-color2: #fff;
|
||||||
|
background-image: repeating-conic-gradient(var(--mosaic-bg-color1) 0% 25%, var(--mosaic-bg-color2) 0% 50%);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<brush-control-panel v-if="show" :currentTool="currentTool2" style="top: 14rem" />
|
<brush-control-panel v-if="show" :currentTool="currentTool" style="top: 14rem" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -40,7 +40,6 @@
|
|||||||
[OperationType.AISELECT_DRAW]: OperationType.ERASER,
|
[OperationType.AISELECT_DRAW]: OperationType.ERASER,
|
||||||
[OperationType.AISELECT_ERASER]: OperationType.ERASER
|
[OperationType.AISELECT_ERASER]: OperationType.ERASER
|
||||||
}
|
}
|
||||||
const currentTool2 = computed(() => tool2[props.currentTool] || props.currentTool)
|
|
||||||
const show = computed(() => stateManager.aiSelectboxToolManager.tools.includes(props.currentTool))
|
const show = computed(() => stateManager.aiSelectboxToolManager.tools.includes(props.currentTool))
|
||||||
const list = ref([
|
const list = ref([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, inject, computed, watch } from 'vue'
|
import { ref, inject, computed, watch, nextTick } from 'vue'
|
||||||
import depthSlider from './tools/depth-slider.vue'
|
import depthSlider from './tools/depth-slider.vue'
|
||||||
import { OperationType } from '../tools/layerHelper'
|
import { OperationType } from '../tools/layerHelper'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -40,20 +40,27 @@
|
|||||||
})
|
})
|
||||||
const stateManager = inject('stateManager') as any
|
const stateManager = inject('stateManager') as any
|
||||||
const brushState = computed(() => stateManager.brushManager.brushStore.state)
|
const brushState = computed(() => stateManager.brushManager.brushStore.state)
|
||||||
const showTools = [OperationType.DRAW, OperationType.ERASER]
|
const showTools = [
|
||||||
|
OperationType.DRAW,
|
||||||
|
OperationType.ERASER,
|
||||||
|
OperationType.AISELECT_DRAW,
|
||||||
|
OperationType.AISELECT_ERASER
|
||||||
|
]
|
||||||
const show = computed(() => showTools.includes(props.currentTool))
|
const show = computed(() => showTools.includes(props.currentTool))
|
||||||
const brushSize = ref(40)
|
const brushSize = ref(40)
|
||||||
const brushOpacity = ref(100)
|
const brushOpacity = ref(100)
|
||||||
const brushColor = ref('#000000')
|
const brushColor = ref('#000000')
|
||||||
const updateBrushState = () => {
|
const updateBrushState = async () => {
|
||||||
brushSize.value = brushState.value.size
|
await nextTick()
|
||||||
brushOpacity.value = brushState.value.opacity
|
brushSize.value = stateManager.brushManager.brushStore.state.size
|
||||||
brushColor.value = brushState.value.color
|
brushOpacity.value = stateManager.brushManager.brushStore.state.opacity
|
||||||
|
brushColor.value = stateManager.brushManager.brushStore.state.color
|
||||||
}
|
}
|
||||||
updateBrushState()
|
updateBrushState()
|
||||||
watch(() => brushState.value.size, updateBrushState)
|
watch(() => brushState.value.size, updateBrushState)
|
||||||
watch(() => brushState.value.opacity, updateBrushState)
|
watch(() => brushState.value.opacity, updateBrushState)
|
||||||
watch(() => brushState.value.color, updateBrushState)
|
watch(() => brushState.value.color, updateBrushState)
|
||||||
|
watch(() => props.currentTool, updateBrushState)
|
||||||
|
|
||||||
const onInputSize = (value: number) => {
|
const onInputSize = (value: number) => {
|
||||||
stateManager.brushManager.setBrushSize(value)
|
stateManager.brushManager.setBrushSize(value)
|
||||||
|
|||||||
@@ -68,12 +68,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="select">
|
||||||
|
<div class="title">{{ $t('DepthCanvas.blendMode') }}</div>
|
||||||
|
<div class="content">
|
||||||
|
<depth-select
|
||||||
|
v-model="data.globalCompositeOperation"
|
||||||
|
:list="layerCompositeOptions"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
|
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
|
||||||
import DepthInput from '../tools/depth-input.vue'
|
import DepthInput from '../tools/depth-input.vue'
|
||||||
|
import DepthSelect from '../tools/depth-select.vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
const objectManager = inject('objectManager') as any
|
const objectManager = inject('objectManager') as any
|
||||||
const stateManager = inject('stateManager') as any
|
const stateManager = inject('stateManager') as any
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -90,7 +103,8 @@
|
|||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
scaleX: 1,
|
scaleX: 1,
|
||||||
scaleY: 1
|
scaleY: 1,
|
||||||
|
globalCompositeOperation: 'source-over'
|
||||||
})
|
})
|
||||||
const updateData = async () => {
|
const updateData = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
@@ -100,6 +114,7 @@
|
|||||||
data.height = Math.round(props.object.height)
|
data.height = Math.round(props.object.height)
|
||||||
data.scaleX = Math.round(props.object.scaleX * 100)
|
data.scaleX = Math.round(props.object.scaleX * 100)
|
||||||
data.scaleY = Math.round(props.object.scaleY * 100)
|
data.scaleY = Math.round(props.object.scaleY * 100)
|
||||||
|
data.globalCompositeOperation = props.object.globalCompositeOperation
|
||||||
}
|
}
|
||||||
updateData()
|
updateData()
|
||||||
watch(() => props.object, updateData)
|
watch(() => props.object, updateData)
|
||||||
@@ -121,6 +136,94 @@
|
|||||||
stateManager.event.remove('canvas:undo', updateData)
|
stateManager.event.remove('canvas:undo', updateData)
|
||||||
stateManager.event.remove('canvas:redo', updateData)
|
stateManager.event.remove('canvas:redo', updateData)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const layerCompositeOptions = ref([
|
||||||
|
{
|
||||||
|
value: 'source-over',
|
||||||
|
label: t('DepthCanvas.compositeNormal'),
|
||||||
|
tip: t('DepthCanvas.compositeNormalTip')
|
||||||
|
}, // 正常
|
||||||
|
{
|
||||||
|
value: 'darken',
|
||||||
|
label: t('DepthCanvas.compositeDarken'),
|
||||||
|
tip: t('DepthCanvas.compositeDarkenTip')
|
||||||
|
}, // 变暗
|
||||||
|
{
|
||||||
|
value: 'multiply',
|
||||||
|
label: t('DepthCanvas.compositeMultiply'),
|
||||||
|
tip: t('DepthCanvas.compositeMultiplyTip')
|
||||||
|
}, // 正片叠底
|
||||||
|
{
|
||||||
|
value: 'color-burn',
|
||||||
|
label: t('DepthCanvas.compositeColorBurn'),
|
||||||
|
tip: t('DepthCanvas.compositeColorBurnTip')
|
||||||
|
}, // 颜色加深
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'lighten',
|
||||||
|
label: t('DepthCanvas.compositeLighten'),
|
||||||
|
tip: t('DepthCanvas.compositeLightenTip')
|
||||||
|
}, // 颜色减淡
|
||||||
|
{
|
||||||
|
value: 'screen',
|
||||||
|
label: t('DepthCanvas.compositeScreen'),
|
||||||
|
tip: t('DepthCanvas.compositeScreenTip')
|
||||||
|
}, // 滤色
|
||||||
|
{
|
||||||
|
value: 'color-dodge',
|
||||||
|
label: t('DepthCanvas.compositeColorDodge'),
|
||||||
|
tip: t('DepthCanvas.compositeColorDodgeTip')
|
||||||
|
}, // 颜色减淡
|
||||||
|
{
|
||||||
|
value: 'lighter',
|
||||||
|
label: t('DepthCanvas.compositeLighter'),
|
||||||
|
tip: t('DepthCanvas.compositeLighterTip')
|
||||||
|
}, // 颜色减淡
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'overlay',
|
||||||
|
label: t('DepthCanvas.compositeOverlay'),
|
||||||
|
tip: t('DepthCanvas.compositeOverlayTip')
|
||||||
|
}, // 叠加
|
||||||
|
{
|
||||||
|
value: 'soft-light',
|
||||||
|
label: t('DepthCanvas.compositeSoftLight'),
|
||||||
|
tip: t('DepthCanvas.compositeSoftLightTip')
|
||||||
|
}, // 柔光
|
||||||
|
{
|
||||||
|
value: 'hard-light',
|
||||||
|
label: t('DepthCanvas.compositeHardLight'),
|
||||||
|
tip: t('DepthCanvas.compositeHardLightTip')
|
||||||
|
}, // 强光
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'difference',
|
||||||
|
label: t('DepthCanvas.compositeDifference'),
|
||||||
|
tip: t('DepthCanvas.compositeDifferenceTip')
|
||||||
|
}, // 差值
|
||||||
|
{
|
||||||
|
value: 'exclusion',
|
||||||
|
label: t('DepthCanvas.compositeExclusion'),
|
||||||
|
tip: t('DepthCanvas.compositeExclusionTip')
|
||||||
|
}, // 排除
|
||||||
|
|
||||||
|
{ value: 'hue', label: t('DepthCanvas.compositeHue'), tip: t('DepthCanvas.compositeHueTip') }, // 色相
|
||||||
|
{
|
||||||
|
value: 'saturation',
|
||||||
|
label: t('DepthCanvas.compositeSaturation'),
|
||||||
|
tip: t('DepthCanvas.compositeSaturationTip')
|
||||||
|
}, // 饱和度
|
||||||
|
{
|
||||||
|
value: 'color',
|
||||||
|
label: t('DepthCanvas.compositeColor'),
|
||||||
|
tip: t('DepthCanvas.compositeColorTip')
|
||||||
|
}, // 颜色
|
||||||
|
{
|
||||||
|
value: 'luminosity',
|
||||||
|
label: t('DepthCanvas.compositeLuminosity'),
|
||||||
|
tip: t('DepthCanvas.compositeLuminosityTip')
|
||||||
|
} // 亮度
|
||||||
|
])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -137,9 +240,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
--depth-input-height: 2.4rem;
|
--depth-input-height: 2.4rem;
|
||||||
--depth-input-bg-color: rgba(249, 249, 250, 1);
|
// --depth-input-bg-color: rgba(249, 249, 250, 1);
|
||||||
--depth-input-border-color: rgba(230, 230, 231, 1);
|
// --depth-input-border-color: rgba(230, 230, 231, 1);
|
||||||
--depth-input-decorate-color: rgba(69, 71, 84, 0.1);
|
// --depth-input-decorate-color: rgba(69, 71, 84, 0.1);
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="fill-repeat h">
|
<div class="fill-repeat h">
|
||||||
<div>
|
<div>
|
||||||
<div class="title">{{ $t('DepthCanvas.image') }}</div>
|
<div class="title">{{ $t('DepthCanvas.image') }}</div>
|
||||||
<div class="content">
|
<div class="content mosaic-bg">
|
||||||
<img :src="object.info.fill.source" alt="" />
|
<img :src="object.info.fill.source" alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -138,9 +138,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
--depth-input-height: 2.4rem;
|
--depth-input-height: 2.4rem;
|
||||||
--depth-input-bg-color: rgba(249, 249, 250, 1);
|
// --depth-input-bg-color: rgba(249, 249, 250, 1);
|
||||||
--depth-input-border-color: rgba(230, 230, 231, 1);
|
// --depth-input-border-color: rgba(230, 230, 231, 1);
|
||||||
--depth-input-decorate-color: rgba(69, 71, 84, 0.1);
|
// --depth-input-decorate-color: rgba(69, 71, 84, 0.1);
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="layer-item">
|
<div class="layer-item">
|
||||||
<div class="item" @click="onClickLayer">
|
<div class="item" @click="onClickLayer">
|
||||||
<div class="drag"><svg-icon name="dc-drag" size="18" /></div>
|
<div class="drag"><svg-icon name="dc-drag" size="18" /></div>
|
||||||
<div class="thumb">
|
<div class="thumb mosaic-bg">
|
||||||
<img v-if="layer.thumbnail" :src="layer.thumbnail" />
|
<img v-if="layer.thumbnail" :src="layer.thumbnail" />
|
||||||
</div>
|
</div>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
:value="layer.info.name"
|
:value="layer.info.name"
|
||||||
@blur="onChangeName"
|
@blur="onChangeName"
|
||||||
@keyup.enter="onChangeName"
|
@keyup.enter="onChangeName"
|
||||||
|
@keydown.stop
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="icons">
|
<div class="icons">
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(v) => {
|
(v) => {
|
||||||
|
console.log(v)
|
||||||
value.value = v
|
value.value = v
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { fabric } from 'fabric-with-all'
|
import { fabric } from 'fabric-with-all'
|
||||||
import { OperationType } from '../tools/layerHelper'
|
import { OperationType } from '../tools/layerHelper'
|
||||||
import { getObjectAlphaToCanvas, traceImageContour, cloneObjects } from '../tools/canvasMethod'
|
import { getObjectAlphaToCanvas, traceImageContour, clipCanvasTransparent, cloneObjects } from '../tools/canvasMethod'
|
||||||
import { getSegAnythingImage } from '@/api/depth-canvas'
|
import { getSegAnythingImage } from '@/api/depth-canvas'
|
||||||
import { useGlobalStore, useUserInfoStore } from '@/stores'
|
import { useGlobalStore, useUserInfoStore } from '@/stores'
|
||||||
|
|
||||||
@@ -256,28 +256,46 @@ export class AISelectboxToolManager {
|
|||||||
if (!this.demoObject) return
|
if (!this.demoObject) return
|
||||||
const fobject = this.demoObject
|
const fobject = this.demoObject
|
||||||
this.clearDemoObject()
|
this.clearDemoObject()
|
||||||
const tcanvas = await this.createStaticCanvas(fobject)
|
|
||||||
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, { r: 255, g: 0, b: 0, a: 255 });
|
|
||||||
const arr = traceImageContour(canvas);
|
|
||||||
const scaleY = fobject.scaleY
|
const scaleY = fobject.scaleY
|
||||||
const scaleX = fobject.scaleX
|
const scaleX = fobject.scaleX
|
||||||
const top = fobject.top
|
const top = fobject.top
|
||||||
const left = fobject.left
|
const left = fobject.left
|
||||||
let minX = fobject.width;
|
let minX = fobject.width;
|
||||||
let minY = fobject.height;
|
let minY = fobject.height;
|
||||||
const str = arr.map((v) => {
|
const tcanvas = await this.createStaticCanvas(fobject)
|
||||||
if (v.x < minX) minX = v.x;
|
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, { r: 255, g: 255, b: 255, a: 255 });
|
||||||
if (v.y < minY) minY = v.y;
|
|
||||||
return `${v.x} ${v.y}`
|
/** 路径裁剪法 */
|
||||||
}).join(" L ");
|
// const arr = traceImageContour(canvas);
|
||||||
const path = new fabric.Path(`M ${str} z`);
|
// const str = arr.map((v) => {
|
||||||
|
// if (v.x < minX) minX = v.x;
|
||||||
|
// if (v.y < minY) minY = v.y;
|
||||||
|
// return `${v.x} ${v.y}`
|
||||||
|
// }).join(" L ");
|
||||||
|
// const path = new fabric.Path(`M ${str} z`);
|
||||||
|
// path.set({
|
||||||
|
// left: left + minX,
|
||||||
|
// top: top + minY,
|
||||||
|
// scaleX: scaleX,
|
||||||
|
// scaleY: scaleY,
|
||||||
|
// ...this.selectionStyle,
|
||||||
|
// });
|
||||||
|
|
||||||
|
/** 图片裁剪法 */
|
||||||
|
const info = clipCanvasTransparent(canvas)
|
||||||
|
minX = info.minX
|
||||||
|
minY = info.minY
|
||||||
|
const path = new fabric.Image(info.canvas)
|
||||||
path.set({
|
path.set({
|
||||||
left: left + minX,
|
left: left + minX,
|
||||||
top: top + minY,
|
top: top + minY,
|
||||||
scaleX: scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: scaleY,
|
scaleY: scaleY,
|
||||||
...this.selectionStyle,
|
absolutePositioned: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 创建分组层
|
||||||
const group = await this.layerManager.createGroupLayer({
|
const group = await this.layerManager.createGroupLayer({
|
||||||
clipPath: path,
|
clipPath: path,
|
||||||
top: path.top + path.height / 2,
|
top: path.top + path.height / 2,
|
||||||
|
|||||||
@@ -189,16 +189,9 @@ export class CanvasManager {
|
|||||||
const objects = this.getObjects().filter((v: any) => v.type !== "group" && !!v.info?.id);
|
const objects = this.getObjects().filter((v: any) => v.type !== "group" && !!v.info?.id);
|
||||||
for (let i = 0; i < objects.length; i++) {
|
for (let i = 0; i < objects.length; i++) {
|
||||||
let object = objects[i]
|
let object = objects[i]
|
||||||
if (object.clipPath) object.set({ clipPath: null })
|
let path = this.getObjectById(object.info.parentId)?.clipPath
|
||||||
let group = this.getObjectById(object.info.parentId)
|
|
||||||
if (!group) continue
|
|
||||||
let path = group.clipPath
|
|
||||||
if (!path) continue
|
if (!path) continue
|
||||||
let clipPath = await cloneObjects([path]).then((v) => v[0])
|
object.set({ clipPath: path })
|
||||||
clipPath.set({
|
|
||||||
absolutePositioned: true,
|
|
||||||
})
|
|
||||||
object.set({ clipPath })
|
|
||||||
}
|
}
|
||||||
this.renderAll()
|
this.renderAll()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,30 @@ export class LayerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setActiveFirstLayer() {
|
setActiveFirstLayer() {
|
||||||
this.setActiveID(this.layers.value[0]?.info?.id || "")
|
const layer = this.layers.value[0]
|
||||||
|
const id = layer.type === "group" ? layer.children[0]?.info?.id : layer.info?.id
|
||||||
|
this.setActiveID(id || "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新图层列表
|
||||||
|
async updateLayers(isSort = false) {
|
||||||
|
const objects = this.canvasManager.getObjects().map(v => v.toObject()).filter(v => !!v.info?.id).reverse()
|
||||||
|
objects.forEach(v => {
|
||||||
|
if (v.type === "group") {
|
||||||
|
if (!v.children) v.children = []
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parentId = v.info?.parentId
|
||||||
|
if (!parentId) return
|
||||||
|
objects.forEach((obj: any) => {
|
||||||
|
if (obj.info?.id !== parentId) return
|
||||||
|
if (!obj.children) obj.children = []
|
||||||
|
obj.children.push(v)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const layers = objects.filter(v => !v.info?.parentId)
|
||||||
|
this.layers.value = layers
|
||||||
|
if (isSort) await this.sortLayers()
|
||||||
}
|
}
|
||||||
|
|
||||||
getActiveLayer() {
|
getActiveLayer() {
|
||||||
@@ -168,26 +191,6 @@ export class LayerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新图层列表
|
|
||||||
async updateLayers(isSort = false) {
|
|
||||||
const objects = this.canvasManager.getObjects().map(v => v.toObject()).filter(v => !!v.info?.id).reverse()
|
|
||||||
objects.forEach(v => {
|
|
||||||
if (v.type === "group") {
|
|
||||||
if (!v.children) v.children = []
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const parentId = v.info?.parentId
|
|
||||||
if (!parentId) return
|
|
||||||
objects.forEach((obj: any) => {
|
|
||||||
if (obj.info?.id !== parentId) return
|
|
||||||
if (!obj.children) obj.children = []
|
|
||||||
obj.children.push(v)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const layers = objects.filter(v => !v.info?.parentId)
|
|
||||||
this.layers.value = layers
|
|
||||||
if (isSort) await this.sortLayers()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 设置图层位置-不设置默认居中 */
|
/** 设置图层位置-不设置默认居中 */
|
||||||
setLayerPosition(object, options?: any) {
|
setLayerPosition(object, options?: any) {
|
||||||
@@ -455,7 +458,7 @@ export class LayerManager {
|
|||||||
const objects = this.canvasManager.getObjects()
|
const objects = this.canvasManager.getObjects()
|
||||||
objects.forEach((item: any) => {
|
objects.forEach((item: any) => {
|
||||||
item.set({
|
item.set({
|
||||||
erasable: (item.info.id === this.activeID.value && item.type !== "group")
|
erasable: (item?.info?.id === this.activeID.value && item.type !== "group")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ export class ToolManager {
|
|||||||
setTool(value: string) {
|
setTool(value: string) {
|
||||||
const tool = this.tools.find((t) => t.name === value)
|
const tool = this.tools.find((t) => t.name === value)
|
||||||
if (!tool) return console.warn(`工具${tool}不存在`)
|
if (!tool) return console.warn(`工具${tool}不存在`)
|
||||||
|
this.brushManager?.handleToolChange(tool.name)
|
||||||
const oldTool = this.currentTool.value
|
const oldTool = this.currentTool.value
|
||||||
this.currentTool.value = tool.name
|
this.currentTool.value = tool.name
|
||||||
this.canvasManager.canvas.defaultCursor = tool.cursor
|
this.canvasManager.canvas.defaultCursor = tool.cursor
|
||||||
@@ -124,7 +125,6 @@ export class ToolManager {
|
|||||||
this.canvasManager.canvas.isDrawingMode = !!tool.isDrawingMode;// 绘制模式
|
this.canvasManager.canvas.isDrawingMode = !!tool.isDrawingMode;// 绘制模式
|
||||||
if (!tool.isDrawingMode) this._disableBrushIndicator()// 非绘制模式,禁用笔刷指示器
|
if (!tool.isDrawingMode) this._disableBrushIndicator()// 非绘制模式,禁用笔刷指示器
|
||||||
|
|
||||||
|
|
||||||
if (tool.setup) tool.setup()
|
if (tool.setup) tool.setup()
|
||||||
|
|
||||||
this.stateManager?.aiSelectboxToolManager?.handleToolChange?.(oldTool, tool.name)
|
this.stateManager?.aiSelectboxToolManager?.handleToolChange?.(oldTool, tool.name)
|
||||||
@@ -160,16 +160,13 @@ export class ToolManager {
|
|||||||
const brushStore = this.brushManager?.brushStore
|
const brushStore = this.brushManager?.brushStore
|
||||||
if (brushStore) {
|
if (brushStore) {
|
||||||
// 同步基本属性
|
// 同步基本属性
|
||||||
// this.brushManager.setBrushSize(brushStore.state.size);
|
this.brushManager.setBrushSize(brushStore.state.size);
|
||||||
// this.brushManager.setBrushColor(brushStore.state.color);
|
this.brushManager.setBrushColor(brushStore.state.color);
|
||||||
// this.brushManager.setBrushOpacity(brushStore.state.opacity);
|
this.brushManager.setBrushOpacity(brushStore.state.opacity);
|
||||||
|
|
||||||
// 同步笔刷类型 - 修复方法名,使用正确的setBrushType方法
|
// 同步笔刷类型 - 修复方法名,使用正确的setBrushType方法
|
||||||
this.brushManager.setBrushType("pencil");
|
this.brushManager.setBrushType("pencil");
|
||||||
}
|
}
|
||||||
this.brushManager.setBrushSize(5);
|
|
||||||
this.brushManager.setBrushColor("#000");
|
|
||||||
this.brushManager.setBrushOpacity(1);
|
|
||||||
|
|
||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
@@ -185,11 +182,12 @@ export class ToolManager {
|
|||||||
if (!this.canvasManager.canvas) return;
|
if (!this.canvasManager.canvas) return;
|
||||||
|
|
||||||
// 确保有笔刷管理器
|
// 确保有笔刷管理器
|
||||||
if (this.brushManager) {
|
const brushStore = this.brushManager?.brushStore
|
||||||
|
if (brushStore) {
|
||||||
this.brushManager.createEraser();
|
this.brushManager.createEraser();
|
||||||
|
this.brushManager.setBrushSize(brushStore.state.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.brushManager.setBrushSize(5);
|
|
||||||
this.stateManager.layerManager.setActiveObjectErasable()
|
this.stateManager.layerManager.setActiveObjectErasable()
|
||||||
// 启用笔刷指示器
|
// 启用笔刷指示器
|
||||||
this._enableBrushIndicator();
|
this._enableBrushIndicator();
|
||||||
@@ -206,10 +204,16 @@ export class ToolManager {
|
|||||||
console.warn("画笔正在更新中,请稍候...");
|
console.warn("画笔正在更新中,请稍候...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.brushManager.setBrushSize(5);
|
const brushStore = this.brushManager?.brushStore
|
||||||
this.brushManager.setBrushColor("rgb(255, 0, 0)");
|
if (brushStore) {
|
||||||
this.brushManager.setBrushOpacity(0.5);
|
// 同步基本属性
|
||||||
this.brushManager.setBrushType("pencil");
|
this.brushManager.setBrushSize(brushStore.state.size);
|
||||||
|
this.brushManager.setBrushColor(brushStore.state.color);
|
||||||
|
this.brushManager.setBrushOpacity(brushStore.state.opacity);
|
||||||
|
|
||||||
|
// 同步笔刷类型 - 修复方法名,使用正确的setBrushType方法
|
||||||
|
this.brushManager.setBrushType("pencil");
|
||||||
|
}
|
||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
}
|
}
|
||||||
@@ -222,9 +226,10 @@ export class ToolManager {
|
|||||||
if (!this.canvasManager.canvas) return;
|
if (!this.canvasManager.canvas) return;
|
||||||
|
|
||||||
// 确保有笔刷管理器
|
// 确保有笔刷管理器
|
||||||
if (this.brushManager) {
|
const brushStore = this.brushManager?.brushStore
|
||||||
|
if (brushStore) {
|
||||||
this.brushManager.createEraser();
|
this.brushManager.createEraser();
|
||||||
this.brushManager.setBrushSize(5);
|
this.brushManager.setBrushSize(brushStore.state.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stateManager.layerManager.setAllObjectsErasable(false)
|
this.stateManager.layerManager.setAllObjectsErasable(false)
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { reactive, readonly } from "vue";
|
|||||||
class texturePresetManager { }
|
class texturePresetManager { }
|
||||||
|
|
||||||
export class BrushState {
|
export class BrushState {
|
||||||
constructor(options) {
|
constructor(options = {}) {
|
||||||
this.state = reactive({
|
this.state = reactive({
|
||||||
// 笔刷基础属性
|
// 笔刷基础属性
|
||||||
size: 5, // 笔刷大小
|
size: options.size || 5, // 笔刷大小
|
||||||
color: "#000000", // 笔刷颜色
|
color: options.color || "#000000", // 笔刷颜色
|
||||||
opacity: 1, // 笔刷透明度
|
opacity: options.opacity || 1, // 笔刷透明度
|
||||||
type: "pencil", // 当前笔刷类型
|
type: options.type || "pencil", // 当前笔刷类型
|
||||||
|
|
||||||
// 阴影相关属性
|
// 阴影相关属性
|
||||||
shadowEnabled: false, // 是否启用阴影
|
shadowEnabled: false, // 是否启用阴影
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { EraserStateManager } from "../EraserStateManager.js";
|
|||||||
import { SprayBrush } from "./types/SprayBrush";
|
import { SprayBrush } from "./types/SprayBrush";
|
||||||
// import { SketchyBrush } from "./types/SketchyBrush";
|
// import { SketchyBrush } from "./types/SketchyBrush";
|
||||||
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
|
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
|
||||||
|
import { OperationType } from '../../tools/layerHelper'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 笔刷管理器
|
* 笔刷管理器
|
||||||
@@ -37,7 +39,17 @@ export class BrushManager {
|
|||||||
*/
|
*/
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.canvas = options.canvas;
|
this.canvas = options.canvas;
|
||||||
this.brushStore = new BrushState();
|
this.brushStoreList = {
|
||||||
|
[OperationType.DRAW]: new BrushState(),
|
||||||
|
[OperationType.ERASER]: new BrushState(),
|
||||||
|
[OperationType.AISELECT_DRAW]: new BrushState({
|
||||||
|
color: "rgb(255, 0, 0)",
|
||||||
|
opacity: 0.5,
|
||||||
|
}),
|
||||||
|
[OperationType.AISELECT_ERASER]: new BrushState(),
|
||||||
|
}
|
||||||
|
this.brushStore = this.brushStoreList[OperationType.DRAW];
|
||||||
|
|
||||||
this.layerManager = options.layerManager; // 添加图层管理器引用
|
this.layerManager = options.layerManager; // 添加图层管理器引用
|
||||||
this.brushIndicator = options.brushIndicator; // 添加笔刷指示器引用
|
this.brushIndicator = options.brushIndicator; // 添加笔刷指示器引用
|
||||||
// this.t = options.t
|
// this.t = options.t
|
||||||
@@ -55,7 +67,15 @@ export class BrushManager {
|
|||||||
this.isErasingActive = false;
|
this.isErasingActive = false;
|
||||||
this.currentErasedObjects = []; // 当前擦除会话中被影响的对象
|
this.currentErasedObjects = []; // 当前擦除会话中被影响的对象
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 切换工具时,更新当前活动笔刷
|
||||||
|
* @param {string} toolName 当前工具名称
|
||||||
|
*/
|
||||||
|
handleToolChange(toolName) {
|
||||||
|
const store = this.brushStoreList[toolName];
|
||||||
|
if (!store) return;
|
||||||
|
this.brushStore = store;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 注册默认笔刷
|
* 注册默认笔刷
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export class KeyEventManager {
|
|||||||
/** 处理键盘事件 */
|
/** 处理键盘事件 */
|
||||||
_handleKeyDown: any
|
_handleKeyDown: any
|
||||||
handleKeyDown(event: any) {
|
handleKeyDown(event: any) {
|
||||||
event.preventDefault()
|
|
||||||
const activeID = this.stateManager.layerManager.activeID.value
|
const activeID = this.stateManager.layerManager.activeID.value
|
||||||
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
||||||
const shift = event.shiftKey ? 'shift-' : "";
|
const shift = event.shiftKey ? 'shift-' : "";
|
||||||
@@ -24,6 +23,7 @@ export class KeyEventManager {
|
|||||||
{ key: "ctrl-s", handler: () => this.onWorkbench() },
|
{ key: "ctrl-s", handler: () => this.onWorkbench() },
|
||||||
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
|
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
|
||||||
]
|
]
|
||||||
|
if (list.some((v) => reg.test(v.key))) event.preventDefault()
|
||||||
list.forEach((v: any) => {
|
list.forEach((v: any) => {
|
||||||
if (reg.test(v.key)) v.handler(event)
|
if (reg.test(v.key)) v.handler(event)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -260,3 +260,40 @@ export function traceImageContour(canvas) {
|
|||||||
|
|
||||||
return contour;
|
return contour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 裁剪画布透明像素 */
|
||||||
|
export function clipCanvasTransparent(canvas) {
|
||||||
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
const width = canvas.width;
|
||||||
|
const height = canvas.height;
|
||||||
|
var minX = width;
|
||||||
|
var minY = height;
|
||||||
|
var maxX = 0;
|
||||||
|
var maxY = 0;
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const index = (y * width + x) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
if (x < minX) minX = x;
|
||||||
|
if (y < minY) minY = y;
|
||||||
|
if (x > maxX) maxX = x;
|
||||||
|
if (y > maxY) maxY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const newCanvas = document.createElement("canvas");
|
||||||
|
newCanvas.width = maxX - minX + 1;
|
||||||
|
newCanvas.height = maxY - minY + 1;
|
||||||
|
const newCtx = newCanvas.getContext("2d");
|
||||||
|
newCtx.drawImage(canvas, minX, minY, maxX - minX + 1, maxY - minY + 1, 0, 0, maxX - minX + 1, maxY - minY + 1);
|
||||||
|
return {
|
||||||
|
minX,
|
||||||
|
minY,
|
||||||
|
maxX,
|
||||||
|
maxY,
|
||||||
|
canvas: newCanvas,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import { fabric } from 'fabric-with-all'
|
import { fabric } from 'fabric-with-all'
|
||||||
import { createStaticCanvas } from './canvasFactory'
|
import { createStaticCanvas } from './canvasFactory'
|
||||||
import { getObjectsBoundingBox, cloneObjects } from './canvasMethod'
|
import { getObjectsBoundingBox, cloneObjects } from './canvasMethod'
|
||||||
/** 导出画布为图片 */
|
/** 导出画布为图片
|
||||||
export async function exportCanvasToImage(canvas) {
|
* @param {fabric.Canvas} canvas - 画布对象
|
||||||
|
* @param {boolean} isDisscar - 是否丢弃选中对象
|
||||||
|
* @returns {Promise<string>} - 图片URL
|
||||||
|
*/
|
||||||
|
export async function exportCanvasToImage(canvas, isDisscar = true) {
|
||||||
|
if (isDisscar) {
|
||||||
|
canvas.discardActiveObject()
|
||||||
|
canvas.renderAll()
|
||||||
|
}
|
||||||
const clonedObjects = await cloneObjects(canvas.getObjects())
|
const clonedObjects = await cloneObjects(canvas.getObjects())
|
||||||
const staticCanvas = createStaticCanvas(document.createElement('canvas'))
|
const staticCanvas = createStaticCanvas(document.createElement('canvas'))
|
||||||
const width = canvas.clipPath.width
|
const width = canvas.clipPath.width
|
||||||
|
|||||||
@@ -254,7 +254,43 @@ export default {
|
|||||||
brush: 'Brush',
|
brush: 'Brush',
|
||||||
erase: 'Erase',
|
erase: 'Erase',
|
||||||
create: 'Create',
|
create: 'Create',
|
||||||
reset: 'Reset'
|
reset: 'Reset',
|
||||||
|
// 混合模式
|
||||||
|
blendMode: 'Blend Mode',
|
||||||
|
compositeNormal: 'Normal',
|
||||||
|
compositeNormalTip: 'Normal: Default, new graphics cover original content',
|
||||||
|
compositeDarken: 'Darken',
|
||||||
|
compositeDarkenTip: 'Darken: Take the darkest color',
|
||||||
|
compositeMultiply: 'Multiply',
|
||||||
|
compositeMultiplyTip: 'Multiply: Darken the image',
|
||||||
|
compositeColorBurn: 'Color Burn',
|
||||||
|
compositeColorBurnTip: 'Color Burn: Increase contrast and darken the bottom color',
|
||||||
|
compositeLighten: 'Lighten',
|
||||||
|
compositeLightenTip: 'Lighten: Take the brightest color',
|
||||||
|
compositeScreen: 'Screen',
|
||||||
|
compositeScreenTip: 'Screen: Lighten the image',
|
||||||
|
compositeColorDodge: 'Color Dodge',
|
||||||
|
compositeColorDodgeTip: 'Color Dodge: Reduce contrast and lighten the bottom color',
|
||||||
|
compositeLighter: 'Color Dodge (Add)',
|
||||||
|
compositeLighterTip: 'Color Dodge (Add): Add the brightness of the overlapping parts',
|
||||||
|
compositeOverlay: 'Overlay',
|
||||||
|
compositeOverlayTip: 'Overlay: Highlight effect',
|
||||||
|
compositeSoftLight: 'Soft Light',
|
||||||
|
compositeSoftLightTip: 'Soft Light: Blend effect',
|
||||||
|
compositeHardLight: 'Hard Light',
|
||||||
|
compositeHardLightTip: 'Hard Light: Highlight effect',
|
||||||
|
compositeDifference: 'Difference',
|
||||||
|
compositeDifferenceTip: 'Difference: Take the color difference between the two images',
|
||||||
|
compositeExclusion: 'Exclusion',
|
||||||
|
compositeExclusionTip: 'Exclusion: Take the absolute value of the color difference between the two images',
|
||||||
|
compositeHue: 'Hue',
|
||||||
|
compositeHueTip: 'Hue: Preserve the original image color and change the hue of the new image',
|
||||||
|
compositeSaturation: 'Saturation',
|
||||||
|
compositeSaturationTip: 'Saturation: Preserve the original image hue and change the saturation of the new image',
|
||||||
|
compositeColor: 'Color',
|
||||||
|
compositeColorTip: 'Color: Preserve the original image saturation and change the color of the new image',
|
||||||
|
compositeLuminosity: 'Luminosity',
|
||||||
|
compositeLuminosityTip: 'Luminosity: Preserve the original image color and change the luminosity of the new image',
|
||||||
},
|
},
|
||||||
clipDialog: {
|
clipDialog: {
|
||||||
title: 'Upload your profile photo',
|
title: 'Upload your profile photo',
|
||||||
|
|||||||
@@ -249,7 +249,43 @@ export default {
|
|||||||
brush: '画笔',
|
brush: '画笔',
|
||||||
erase: '擦除',
|
erase: '擦除',
|
||||||
create: '创建',
|
create: '创建',
|
||||||
reset: '重置'
|
reset: '重置',
|
||||||
|
// 混合模式
|
||||||
|
blendMode: '混合模式',
|
||||||
|
compositeNormal: '正常',
|
||||||
|
compositeNormalTip: '正常:默认,新图形覆盖原内容',
|
||||||
|
compositeDarken: '变暗',
|
||||||
|
compositeDarkenTip: '变暗:取暗部颜色',
|
||||||
|
compositeMultiply: '正片叠底',
|
||||||
|
compositeMultiplyTip: '正片叠底:图像变暗',
|
||||||
|
compositeColorBurn: '颜色加深',
|
||||||
|
compositeColorBurnTip: '颜色加深:增加对比度,变暗底层颜色',
|
||||||
|
compositeLighten: '变亮',
|
||||||
|
compositeLightenTip: '变亮:取亮部颜色',
|
||||||
|
compositeScreen: '滤色',
|
||||||
|
compositeScreenTip: '滤色:图像变亮',
|
||||||
|
compositeColorDodge: '颜色减淡',
|
||||||
|
compositeColorDodgeTip: '颜色减淡:降低对比度,加亮底层颜色',
|
||||||
|
compositeLighter: '颜色减淡(添加)',
|
||||||
|
compositeLighterTip: '颜色减淡(添加):重叠部分亮度叠加',
|
||||||
|
compositeOverlay: '叠加',
|
||||||
|
compositeOverlayTip: '叠加:高光效果',
|
||||||
|
compositeSoftLight: '柔光',
|
||||||
|
compositeSoftLightTip: '柔光:混合效果',
|
||||||
|
compositeHardLight: '强光',
|
||||||
|
compositeHardLightTip: '强光:高光效果',
|
||||||
|
compositeDifference: '差值',
|
||||||
|
compositeDifferenceTip: '差值:取两图像颜色差',
|
||||||
|
compositeExclusion: '排除',
|
||||||
|
compositeExclusionTip: '排除:取两图像颜色差的绝对值',
|
||||||
|
compositeHue: '色相',
|
||||||
|
compositeHueTip: '色相:保留原图像颜色,改变新图像色相',
|
||||||
|
compositeSaturation: '饱和度',
|
||||||
|
compositeSaturationTip: '饱和度:保留原图像色相,改变新图像饱和度',
|
||||||
|
compositeColor: '颜色',
|
||||||
|
compositeColorTip: '颜色:保留原图像饱和度,改变新图像颜色',
|
||||||
|
compositeLuminosity: '亮度',
|
||||||
|
compositeLuminosityTip: '亮度:保留原图像颜色,改变新图像亮度',
|
||||||
},
|
},
|
||||||
clipDialog: {
|
clipDialog: {
|
||||||
title: '上传您的个人资料照片',
|
title: '上传您的个人资料照片',
|
||||||
|
|||||||
@@ -11,12 +11,16 @@
|
|||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const url =
|
const url =
|
||||||
'https://minio-api.aida.com.hk/fida-public-bucket/furniture/sketches/e3082a38-55d2-4313-ad53-55aad715cf67.png'
|
'https://www.minio-api.aida.com.hk/fida-user/2/d8512e53-f016-4ad6-8245-2f304d89e7b2.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20260331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260331T032733Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=25e5ec227a0ca22942e71eff3a4f07a23f8812ff3db5522e1466b3a77288be70'
|
||||||
const openCanvas = () => {
|
const openCanvas = () => {
|
||||||
myEvent.emit('openFlowCanvas', { url })
|
myEvent.emit('openFlowCanvas', { url })
|
||||||
}
|
}
|
||||||
const openDepthCanvas = () => {
|
const openDepthCanvas = () => {
|
||||||
myEvent.emit('openDepthCanvas', { url, canvasId: '' })
|
myEvent.emit('openDepthCanvas', {
|
||||||
|
url,
|
||||||
|
canvasId: '69cb3f244a1dd46c0bdbb432',
|
||||||
|
sketchId: '69c63417cb064e32ff6826a3'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (route.query.depth) {
|
if (route.query.depth) {
|
||||||
|
|||||||
Reference in New Issue
Block a user