Files
FiDA_Front/src/components/Canvas/DepthCanvas/depth-canvas.vue
2026-03-18 17:25:19 +08:00

217 lines
6.3 KiB
Vue

<template>
<div class="depth-canvas">
<div class="canvas-container" ref="canvasContainerRef">
<canvas ref="canvasRef"></canvas>
</div>
<template v-if="isReady">
<layer-panel />
<details-panel />
<depth-header-tools
@export="exportCanvas"
@export-local="exportCanvasToLocalStorage"
@import-local="importCanvasFromLocalStorage"
@workbench="(v) => emit('workbench', v)"
/>
<brush-control-panel :currentTool="toolManager.currentTool.value" />
<zoom
:zoom="canvasManager.currentZoom.value / 100"
is-home
@home="() => canvasManager.resetZoom()"
@add="() => canvasManager.zoomIn()"
@sub="() => canvasManager.zoomOut()"
/>
</template>
</div>
</template>
<script setup lang="ts">
import { fabric } from 'fabric-with-all'
import { computed, ref, markRaw, onMounted, nextTick, provide, onBeforeUnmount } from 'vue'
import { OperationType } from './tools/layerHelper'
import { exportCanvasToImage } from './tools/exportMethod'
// 组件
import layerPanel from './components/layer-panel/index.vue'
import detailsPanel from './components/details-panel/index.vue'
import depthHeaderTools from './components/depth-header-tools.vue'
import zoom from '../components/zoom.vue'
import brushControlPanel from './components/brush-control-panel.vue'
// 管理器
import { StateManager } from './manager/StateManager'
import { LayerManager } from './manager/LayerManager'
import { CanvasManager } from './manager/CanvasManager'
import { ToolManager } from './manager/ToolManager'
import { KeyEventManager } from './manager/events/KeyEventManager'
import { ObjectManager } from './manager/ObjectManager'
const emit = defineEmits(['workbench', 'close'])
const props = defineProps({
config: {
type: Object,
default: () => ({})
}
})
// 准备就绪
const isReady = ref(false)
const canvasContainerRef = ref(null)
const canvasRef = ref(null)
// 状态管理器
const stateManager = new StateManager({})
provide('stateManager', stateManager)
// 画布管理器
const canvasManager = new CanvasManager({ stateManager })
stateManager.setManager({ canvasManager, canvasRef })
provide('canvasManager', canvasManager)
// 图层管理器
const layerManager = new LayerManager({ stateManager, canvasManager })
stateManager.setManager({ layerManager })
provide('layerManager', layerManager)
// 工具管理器
const toolManager = new ToolManager({ stateManager, canvasManager })
stateManager.setManager({ toolManager })
provide('toolManager', toolManager)
//键盘事件管理器
const keyEventManager = new KeyEventManager({ stateManager })
stateManager.setManager({ keyEventManager })
provide('keyEventManager', keyEventManager)
// 对象管理器
const objectManager = new ObjectManager({ stateManager, canvasManager, layerManager })
stateManager.setManager({ objectManager })
provide('objectManager', objectManager)
const observer = ref(null)
onMounted(async () => {
keyEventManager.registerEvents()
await canvasManager.initCanvas({
canvasRef,
canvasViewWidth: canvasContainerRef.value.clientWidth,
canvasViewHeight: canvasContainerRef.value.clientHeight,
canvasWidth: props.config.width || 750,
canvasHeight: props.config.height || 600,
url: props.config.url || ''
})
stateManager.onMounted()
canvasManager.onMounted()
layerManager.onMounted()
toolManager.onMounted()
keyEventManager.onMounted()
objectManager.onMounted()
const trailingTimeout = ref(null)
observer.value = new ResizeObserver((entries) => {
clearTimeout(trailingTimeout.value)
trailingTimeout.value = setTimeout(async () => {
handleWindowResize()
}, 100)
})
observer.value.observe(canvasContainerRef.value)
isReady.value = true // 准备就绪
})
onBeforeUnmount(() => {
observer.value.disconnect()
canvasManager.dispose()
stateManager.dispose()
layerManager.dispose()
toolManager.dispose()
keyEventManager.dispose()
objectManager.dispose()
})
async function handleWindowResize() {
console.log('==========画布窗口大小变化==========')
canvasManager.setCanvasViewSize({
canvasViewWidth: canvasContainerRef.value.clientWidth,
canvasViewHeight: canvasContainerRef.value.clientHeight
})
canvasManager.resetZoom(true, true)
}
/** 导入本地图片 */
const importLocalImage = (isRecord = true) => {
return new Promise((resolve, reject) => {
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.click()
input.addEventListener('change', (e: any) => {
const file = e.target.files[0]
if (!file) return
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
toolManager.setTool(OperationType.SELECT)
const url = reader.result as string
layerManager
.createImageLayer(url, { info: { name: file.name } }, isRecord)
.then((v) => resolve(v))
}
})
})
}
provide('importLocalImage', importLocalImage)
const exportCanvas = () => {
// 导出图片
// exportCanvasToImage(canvasManager.canvas).then((url) => {
// const a = document.createElement('a')
// a.href = url
// a.download = 'canvas.png'
// a.click()
// })
const object = canvasManager.getCanvasDisUrlJSON()
console.log(object)
const canvas = canvasManager.processCanvasDisUrlJSON(object)
console.log(canvas)
}
// 导出到本地存储
const exportCanvasToLocalStorage = () => {
const json = canvasManager.getCanvasJSON()
localStorage.setItem('canvasJSON', json)
}
// 从本地存储导入
const importCanvasFromLocalStorage = () => {
const json = localStorage.getItem('canvasJSON')
if (!json) return
canvasManager.loadJSON(json, (success) => {
if (success) {
console.log('导入成功')
} else {
console.log('导入失败')
}
stateManager.clearState(true)
})
}
</script>
<style lang="less">
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style lang="less" scoped>
.depth-canvas {
position: relative;
width: 100%;
height: 100%;
user-select: none;
> .canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
> canvas {
width: 100%;
height: 100%;
}
&:deep(.canvas-container) {
filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.3));
}
}
}
</style>