Files
FiDA_Front/src/components/Canvas/DepthCanvas/depth-canvas.vue

205 lines
5.6 KiB
Vue
Raw Normal View History

2026-03-06 15:50:05 +08:00
<template>
<div class="depth-canvas">
<div class="canvas-container" ref="canvasContainerRef">
<canvas ref="canvasRef"></canvas>
</div>
2026-03-11 15:34:56 +08:00
<template v-if="isReady">
<layer-panel />
<details-panel />
2026-03-12 15:51:18 +08:00
<depth-header-tools
@export="exportCanvas"
@export-local="exportCanvasToLocalStorage"
@import-local="importCanvasFromLocalStorage"
@export-close="exportCanvasAndClose"
/>
2026-03-11 15:34:56 +08:00
<brush-control-panel :currentTool="toolManager.currentTool.value" />
<zoom
:zoom="canvasManager.currentZoom.value / 100"
is-home
@home="() => canvasManager.resetZoom()"
2026-03-16 11:38:58 +08:00
@add="() => canvasManager.zoomIn()"
@sub="() => canvasManager.zoomOut()"
2026-03-11 15:34:56 +08:00
/>
</template>
2026-03-06 15:50:05 +08:00
</div>
</template>
<script setup lang="ts">
import { fabric } from 'fabric-with-all'
2026-03-12 11:40:48 +08:00
import { computed, ref, markRaw, onMounted, nextTick, provide, onBeforeUnmount } from 'vue'
2026-03-11 15:34:56 +08:00
import { OperationType } from './tools/layerHelper'
2026-03-12 15:51:18 +08:00
import { exportCanvasToImage } from './tools/exportMethod'
2026-03-06 15:50:05 +08:00
// 组件
import layerPanel from './components/layer-panel/index.vue'
import detailsPanel from './components/details-panel/index.vue'
2026-03-11 15:34:56 +08:00
import depthHeaderTools from './components/depth-header-tools.vue'
2026-03-06 15:50:05 +08:00
import zoom from '../components/zoom.vue'
2026-03-11 15:34:56 +08:00
import brushControlPanel from './components/brush-control-panel.vue'
2026-03-06 15:50:05 +08:00
// 管理器
import { StateManager } from './manager/StateManager'
2026-03-09 16:45:30 +08:00
import { LayerManager } from './manager/LayerManager'
2026-03-09 13:44:32 +08:00
import { CanvasManager } from './manager/CanvasManager'
import { ToolManager } from './manager/ToolManager'
2026-03-12 11:40:48 +08:00
import { KeyEventManager } from './manager/events/KeyEventManager'
2026-03-06 15:50:05 +08:00
2026-03-12 15:51:18 +08:00
const emit = defineEmits(['close'])
2026-03-06 15:50:05 +08:00
const props = defineProps({
config: {
type: Object,
default: () => ({})
}
})
2026-03-12 15:51:18 +08:00
// 准备就绪
const isReady = ref(false)
const canvasContainerRef = ref(null)
const canvasRef = ref(null)
2026-03-06 15:50:05 +08:00
// 状态管理器
const stateManager = new StateManager({})
provide('stateManager', stateManager)
2026-03-09 13:44:32 +08:00
// 画布管理器
const canvasManager = new CanvasManager({ stateManager })
stateManager.setManager({ canvasManager, canvasRef })
provide('canvasManager', canvasManager)
2026-03-09 16:45:30 +08:00
// 图层管理器
const layerManager = new LayerManager({ stateManager, canvasManager })
stateManager.setManager({ layerManager })
provide('layerManager', layerManager)
2026-03-06 15:50:05 +08:00
// 工具管理器
2026-03-09 13:44:32 +08:00
const toolManager = new ToolManager({ stateManager, canvasManager })
2026-03-06 15:50:05 +08:00
stateManager.setManager({ toolManager })
provide('toolManager', toolManager)
2026-03-09 13:44:32 +08:00
2026-03-12 11:40:48 +08:00
//键盘事件管理器
const keyEventManager = new KeyEventManager({ stateManager })
stateManager.setManager({ keyEventManager })
provide('keyEventManager', keyEventManager)
2026-03-09 13:44:32 +08:00
const observer = ref(null)
onMounted(() => {
canvasManager.initCanvas({
canvasRef,
canvasViewWidth: canvasContainerRef.value.clientWidth,
canvasViewHeight: canvasContainerRef.value.clientHeight,
canvasWidth: 750,
canvasHeight: 600
2026-03-06 15:50:05 +08:00
})
2026-03-11 15:34:56 +08:00
stateManager?.onMounted?.()
canvasManager?.onMounted?.()
layerManager?.onMounted?.()
toolManager?.onMounted?.()
2026-03-12 11:40:48 +08:00
keyEventManager?.onMounted?.()
2026-03-09 13:44:32 +08:00
const trailingTimeout = ref(null)
observer.value = new ResizeObserver((entries) => {
clearTimeout(trailingTimeout.value)
trailingTimeout.value = setTimeout(async () => {
handleWindowResize()
}, 100)
2026-03-06 15:50:05 +08:00
})
2026-03-09 13:44:32 +08:00
observer.value.observe(canvasContainerRef.value)
2026-03-11 15:34:56 +08:00
isReady.value = true // 准备就绪
2026-03-06 15:50:05 +08:00
})
2026-03-12 11:40:48 +08:00
onBeforeUnmount(() => {
2026-03-13 17:31:47 +08:00
observer.value.disconnect()
2026-03-12 11:40:48 +08:00
canvasManager.dispose()
stateManager.dispose()
layerManager.dispose()
toolManager.dispose()
keyEventManager.dispose()
})
2026-03-09 13:44:32 +08:00
async function handleWindowResize() {
console.log('==========画布窗口大小变化==========')
canvasManager.setCanvasViewSize({
canvasViewWidth: canvasContainerRef.value.clientWidth,
canvasViewHeight: canvasContainerRef.value.clientHeight
})
canvasManager.resetZoom()
}
2026-03-11 15:34:56 +08:00
/** 导入本地图片 */
const importLocalImage = () => {
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 }
})
}
})
}
provide('importLocalImage', importLocalImage)
2026-03-09 16:45:30 +08:00
const exportCanvas = () => {
2026-03-12 15:51:18 +08:00
// 导出图片
exportCanvasToImage(canvasManager.canvas).then((url) => {
const a = document.createElement('a')
a.href = url
a.download = 'canvas.png'
a.click()
})
}
// 导出到本地存储
const exportCanvasToLocalStorage = () => {
2026-03-11 15:34:56 +08:00
const json = canvasManager.getCanvasJSON()
localStorage.setItem('canvasJSON', json)
}
2026-03-12 15:51:18 +08:00
// 从本地存储导入
const importCanvasFromLocalStorage = () => {
2026-03-11 15:34:56 +08:00
const json = localStorage.getItem('canvasJSON')
if (!json) return
canvasManager.loadJSON(json, (success) => {
if (success) {
console.log('导入成功')
} else {
console.log('导入失败')
}
2026-03-12 11:40:48 +08:00
stateManager.clearState(true)
2026-03-11 15:34:56 +08:00
})
2026-03-09 16:45:30 +08:00
}
2026-03-12 15:51:18 +08:00
// 导出画布并关闭
const exportCanvasAndClose = () => {
emit('close')
}
2026-03-06 15:50:05 +08:00
</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>