深度画布 矩形工具
This commit is contained in:
@@ -15,10 +15,13 @@
|
|||||||
<span class="icon"><svg-icon name="export" size="12" /></span>
|
<span class="icon"><svg-icon name="export" size="12" /></span>
|
||||||
<span class="text">Export</span>
|
<span class="text">Export</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="export" @click="emit('import')">
|
<button class="export" @click="emit('export-local')">
|
||||||
<span class="text">import</span>
|
<span class="text">保存本地</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="workbench">
|
<button class="export" @click="emit('import-local')">
|
||||||
|
<span class="text">本地导入</span>
|
||||||
|
</button>
|
||||||
|
<button class="workbench" @click="emit('export-close')">
|
||||||
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
|
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
|
||||||
<span class="text">Workbench</span>
|
<span class="text">Workbench</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -32,7 +35,7 @@
|
|||||||
zoom: { default: 1, type: Number },
|
zoom: { default: 1, type: Number },
|
||||||
step: { default: 0.1, type: Number }
|
step: { default: 0.1, type: Number }
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['export', 'import'])
|
const emit = defineEmits(['export', 'export-local', 'import-local', 'export-close'])
|
||||||
const importLocalImage = inject('importLocalImage') as () => void
|
const importLocalImage = inject('importLocalImage') as () => void
|
||||||
const stateManager = inject('stateManager') as any
|
const stateManager = inject('stateManager') as any
|
||||||
const toolManager = inject('toolManager') as any
|
const toolManager = inject('toolManager') as any
|
||||||
|
|||||||
@@ -61,7 +61,6 @@
|
|||||||
}
|
}
|
||||||
const onClickLayer = () => {
|
const onClickLayer = () => {
|
||||||
layerManager.setActiveID(props.layer.info.id)
|
layerManager.setActiveID(props.layer.info.id)
|
||||||
toolManager.setTool(OperationType.SELECT)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,12 @@
|
|||||||
<template v-if="isReady">
|
<template v-if="isReady">
|
||||||
<layer-panel />
|
<layer-panel />
|
||||||
<details-panel />
|
<details-panel />
|
||||||
<depth-header-tools @export="exportCanvas" @import="importCanvas" />
|
<depth-header-tools
|
||||||
|
@export="exportCanvas"
|
||||||
|
@export-local="exportCanvasToLocalStorage"
|
||||||
|
@import-local="importCanvasFromLocalStorage"
|
||||||
|
@export-close="exportCanvasAndClose"
|
||||||
|
/>
|
||||||
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
||||||
<zoom
|
<zoom
|
||||||
:zoom="canvasManager.currentZoom.value / 100"
|
:zoom="canvasManager.currentZoom.value / 100"
|
||||||
@@ -22,6 +27,7 @@
|
|||||||
import { fabric } from 'fabric-with-all'
|
import { fabric } from 'fabric-with-all'
|
||||||
import { computed, ref, markRaw, onMounted, nextTick, provide, onBeforeUnmount } from 'vue'
|
import { computed, ref, markRaw, onMounted, nextTick, provide, onBeforeUnmount } from 'vue'
|
||||||
import { OperationType } from './tools/layerHelper'
|
import { OperationType } from './tools/layerHelper'
|
||||||
|
import { exportCanvasToImage } from './tools/exportMethod'
|
||||||
// 组件
|
// 组件
|
||||||
import layerPanel from './components/layer-panel/index.vue'
|
import layerPanel from './components/layer-panel/index.vue'
|
||||||
import detailsPanel from './components/details-panel/index.vue'
|
import detailsPanel from './components/details-panel/index.vue'
|
||||||
@@ -36,11 +42,7 @@
|
|||||||
import { ToolManager } from './manager/ToolManager'
|
import { ToolManager } from './manager/ToolManager'
|
||||||
import { KeyEventManager } from './manager/events/KeyEventManager'
|
import { KeyEventManager } from './manager/events/KeyEventManager'
|
||||||
|
|
||||||
// 准备就绪
|
const emit = defineEmits(['close'])
|
||||||
const isReady = ref(false)
|
|
||||||
const canvasContainerRef = ref(null)
|
|
||||||
const canvasRef = ref(null)
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -48,6 +50,11 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 准备就绪
|
||||||
|
const isReady = ref(false)
|
||||||
|
const canvasContainerRef = ref(null)
|
||||||
|
const canvasRef = ref(null)
|
||||||
|
|
||||||
// 状态管理器
|
// 状态管理器
|
||||||
const stateManager = new StateManager({})
|
const stateManager = new StateManager({})
|
||||||
provide('stateManager', stateManager)
|
provide('stateManager', stateManager)
|
||||||
@@ -136,10 +143,21 @@
|
|||||||
provide('importLocalImage', importLocalImage)
|
provide('importLocalImage', importLocalImage)
|
||||||
|
|
||||||
const exportCanvas = () => {
|
const exportCanvas = () => {
|
||||||
|
// 导出图片
|
||||||
|
exportCanvasToImage(canvasManager.canvas).then((url) => {
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
a.download = 'canvas.png'
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 导出到本地存储
|
||||||
|
const exportCanvasToLocalStorage = () => {
|
||||||
const json = canvasManager.getCanvasJSON()
|
const json = canvasManager.getCanvasJSON()
|
||||||
localStorage.setItem('canvasJSON', json)
|
localStorage.setItem('canvasJSON', json)
|
||||||
}
|
}
|
||||||
const importCanvas = () => {
|
// 从本地存储导入
|
||||||
|
const importCanvasFromLocalStorage = () => {
|
||||||
const json = localStorage.getItem('canvasJSON')
|
const json = localStorage.getItem('canvasJSON')
|
||||||
if (!json) return
|
if (!json) return
|
||||||
canvasManager.loadJSON(json, (success) => {
|
canvasManager.loadJSON(json, (success) => {
|
||||||
@@ -151,6 +169,10 @@
|
|||||||
stateManager.clearState(true)
|
stateManager.clearState(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 导出画布并关闭
|
||||||
|
const exportCanvasAndClose = () => {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import '@vue-flow/core/dist/style.css';
|
@import '@vue-flow/core/dist/style.css';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<fullscreen-dialog v-model="dialogVisible" hide-destroy>
|
<fullscreen-dialog v-model="dialogVisible" hide-destroy>
|
||||||
<div class="canvas-box">
|
<div class="canvas-box">
|
||||||
<depth-canvas :config="config" />
|
<depth-canvas :config="config" @close="close" />
|
||||||
</div>
|
</div>
|
||||||
</fullscreen-dialog>
|
</fullscreen-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ export class CanvasManager {
|
|||||||
this.setupCanvasEvents()
|
this.setupCanvasEvents()
|
||||||
this.setupBrushEvents()
|
this.setupBrushEvents()
|
||||||
|
|
||||||
this.stateManager.toolManager.setTool(OperationType.SELECT)
|
|
||||||
// 创建矩形
|
// 创建矩形
|
||||||
const rect = this.layerManager.createRectLayer({
|
const rect = this.layerManager.createRectLayer({
|
||||||
left: 400,
|
left: 400,
|
||||||
@@ -86,6 +85,7 @@ export class CanvasManager {
|
|||||||
this.layerManager.updateLayers()
|
this.layerManager.updateLayers()
|
||||||
this.layerManager.setActiveID(text.info.id)
|
this.layerManager.setActiveID(text.info.id)
|
||||||
this.stateManager.recordState()
|
this.stateManager.recordState()
|
||||||
|
// this.stateManager.toolManager.setTool(OperationType.RECTANGLE)
|
||||||
}
|
}
|
||||||
/** 画布添加对象 */
|
/** 画布添加对象 */
|
||||||
add(obj: any, isUpdate = true) {
|
add(obj: any, isUpdate = true) {
|
||||||
@@ -95,6 +95,14 @@ export class CanvasManager {
|
|||||||
this.renderAll()
|
this.renderAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 画布移除对象 */
|
||||||
|
remove(obj: any, isUpdate = true) {
|
||||||
|
this.canvas.remove(obj)
|
||||||
|
if (isUpdate) {
|
||||||
|
this.layerManager.updateLayers()
|
||||||
|
this.renderAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 设置画布事件 */
|
/** 设置画布事件 */
|
||||||
setupCanvasEvents() {
|
setupCanvasEvents() {
|
||||||
@@ -112,6 +120,7 @@ export class CanvasManager {
|
|||||||
/** 设置激活对象 */
|
/** 设置激活对象 */
|
||||||
setActiveObjectByID(id: string) {
|
setActiveObjectByID(id: string) {
|
||||||
const obj = this.getObjectById(id)
|
const obj = this.getObjectById(id)
|
||||||
|
console.log(obj)
|
||||||
if (obj) this.canvas.setActiveObject(obj)
|
if (obj) this.canvas.setActiveObject(obj)
|
||||||
this.renderAll()
|
this.renderAll()
|
||||||
}
|
}
|
||||||
@@ -122,7 +131,7 @@ export class CanvasManager {
|
|||||||
return this.canvas.getObjects() || []
|
return this.canvas.getObjects() || []
|
||||||
}
|
}
|
||||||
getObjectById(id: string) {
|
getObjectById(id: string) {
|
||||||
return this.getObjects().find((item: any) => item.info.id === id)
|
return this.getObjects().find((item: any) => item?.info?.id === id)
|
||||||
}
|
}
|
||||||
renderAll() {
|
renderAll() {
|
||||||
this.canvas.renderAll()
|
this.canvas.renderAll()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ref } from 'vue'
|
|||||||
import { fabric } from 'fabric-with-all'
|
import { fabric } from 'fabric-with-all'
|
||||||
import { createId } from '../../tools/tools'
|
import { createId } from '../../tools/tools'
|
||||||
import { exportObjectsToImage } from '../tools/exportMethod'
|
import { exportObjectsToImage } from '../tools/exportMethod'
|
||||||
|
import { OperationType } from '../tools/layerHelper'
|
||||||
|
|
||||||
export class LayerManager {
|
export class LayerManager {
|
||||||
stateManager: any
|
stateManager: any
|
||||||
@@ -18,6 +19,7 @@ export class LayerManager {
|
|||||||
this.activeID.value = id
|
this.activeID.value = id
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
this.canvasManager.setActiveObjectByID(id)
|
this.canvasManager.setActiveObjectByID(id)
|
||||||
|
this.stateManager.toolManager.setTool(OperationType.SELECT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getLayerByID(id) {
|
getLayerByID(id) {
|
||||||
@@ -114,7 +116,7 @@ export class LayerManager {
|
|||||||
return textLayer
|
return textLayer
|
||||||
}
|
}
|
||||||
/** 创建矩形图层 */
|
/** 创建矩形图层 */
|
||||||
createRectLayer(options?: any) {
|
createRectLayer(options?: any, isActive = false) {
|
||||||
const rectLayer = new fabric.Rect({
|
const rectLayer = new fabric.Rect({
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100,
|
height: 100,
|
||||||
@@ -128,10 +130,11 @@ export class LayerManager {
|
|||||||
})
|
})
|
||||||
this.setLayerPosition(rectLayer, options)
|
this.setLayerPosition(rectLayer, options)
|
||||||
this.canvasManager.add(rectLayer)
|
this.canvasManager.add(rectLayer)
|
||||||
|
if (isActive) this.setActiveID(rectLayer.info.id)
|
||||||
return rectLayer
|
return rectLayer
|
||||||
}
|
}
|
||||||
/** 创建圆形图层 */
|
/** 创建圆形图层 */
|
||||||
createCircleLayer(options?: any) {
|
createCircleLayer(options?: any, isActive = false) {
|
||||||
const circleLayer = new fabric.Circle({
|
const circleLayer = new fabric.Circle({
|
||||||
radius: 50,
|
radius: 50,
|
||||||
fill: '#000',
|
fill: '#000',
|
||||||
@@ -144,6 +147,7 @@ export class LayerManager {
|
|||||||
})
|
})
|
||||||
this.setLayerPosition(circleLayer, options)
|
this.setLayerPosition(circleLayer, options)
|
||||||
this.canvasManager.add(circleLayer)
|
this.canvasManager.add(circleLayer)
|
||||||
|
if (isActive) this.setActiveID(circleLayer.info.id)
|
||||||
return circleLayer
|
return circleLayer
|
||||||
}
|
}
|
||||||
/** 创建图片图层 */
|
/** 创建图片图层 */
|
||||||
@@ -215,5 +219,5 @@ export class LayerManager {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
dispose() {}
|
dispose() { }
|
||||||
}
|
}
|
||||||
56
src/components/Canvas/DepthCanvas/manager/RectToolManager.ts
Normal file
56
src/components/Canvas/DepthCanvas/manager/RectToolManager.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { fabric } from 'fabric-with-all'
|
||||||
|
/** 矩形工具管理器 */
|
||||||
|
export class RectToolManager {
|
||||||
|
// 管理器
|
||||||
|
canvasManager: any
|
||||||
|
stateManager: any
|
||||||
|
layerManager: any
|
||||||
|
|
||||||
|
isDragging: boolean = false
|
||||||
|
startX: number = 0
|
||||||
|
startY: number = 0
|
||||||
|
demoObject: any
|
||||||
|
constructor(options) {
|
||||||
|
this.canvasManager = options.canvasManager
|
||||||
|
this.stateManager = options.stateManager
|
||||||
|
this.layerManager = options.layerManager
|
||||||
|
}
|
||||||
|
mouseDownEvent(e) {
|
||||||
|
this.isDragging = true
|
||||||
|
this.startX = e.absolutePointer.x
|
||||||
|
this.startY = e.absolutePointer.y
|
||||||
|
const rect = new fabric.Rect({
|
||||||
|
left: this.startX,
|
||||||
|
top: this.startY,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
fill: '#000',
|
||||||
|
evented: false,
|
||||||
|
})
|
||||||
|
this.demoObject = rect
|
||||||
|
this.canvasManager.canvas.add(rect)
|
||||||
|
this.canvasManager.canvas.renderAll()
|
||||||
|
}
|
||||||
|
mouseMoveEvent(e) {
|
||||||
|
if (!this.isDragging) return;
|
||||||
|
const width = e.absolutePointer.x - this.startX
|
||||||
|
const height = e.absolutePointer.y - this.startY
|
||||||
|
this.demoObject.set({ width, height })
|
||||||
|
this.canvasManager.canvas.renderAll()
|
||||||
|
}
|
||||||
|
mouseUpEvent(e) {
|
||||||
|
if (!this.isDragging) return;
|
||||||
|
this.isDragging = false;
|
||||||
|
var width = e.absolutePointer.x - this.startX
|
||||||
|
var height = e.absolutePointer.y - this.startY
|
||||||
|
if(width === 0) width = 50
|
||||||
|
if(height === 0) height = 50
|
||||||
|
this.demoObject.set({ width, height })
|
||||||
|
const object = this.demoObject.toJSON("evented")
|
||||||
|
this.layerManager.createRectLayer(object, true)
|
||||||
|
this.canvasManager.canvas.remove(this.demoObject)
|
||||||
|
this.canvasManager.canvas.renderAll()
|
||||||
|
|
||||||
|
}
|
||||||
|
dispose() { }
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { isBoolean } from "lodash-es";
|
import { isBoolean } from "lodash-es";
|
||||||
import { OperationType, OperationTypes } from "../../tools/layerHelper";
|
import { OperationType, OperationTypes } from "../../tools/layerHelper";
|
||||||
|
import { RectToolManager } from "../RectToolManager"
|
||||||
|
|
||||||
export class CanvasEventManager {
|
export class CanvasEventManager {
|
||||||
constructor(canvas, options = {}) {
|
constructor(canvas, options = {}) {
|
||||||
@@ -22,6 +23,15 @@ export class CanvasEventManager {
|
|||||||
this.longPressTimer = null;
|
this.longPressTimer = null;
|
||||||
this.longPressThreshold = 500;
|
this.longPressThreshold = 500;
|
||||||
|
|
||||||
|
|
||||||
|
const managers = {
|
||||||
|
canvasManager: this.canvasManager,
|
||||||
|
stateManager: this.stateManager,
|
||||||
|
toolManager: this.toolManager,
|
||||||
|
layerManager: this.layerManager,
|
||||||
|
}
|
||||||
|
this.rectToolManager = new RectToolManager(managers)
|
||||||
|
|
||||||
// 初始化所有事件
|
// 初始化所有事件
|
||||||
this.initEvents();
|
this.initEvents();
|
||||||
}
|
}
|
||||||
@@ -188,31 +198,44 @@ export class CanvasEventManager {
|
|||||||
// console.log("==========选择模式鼠标右击画布对象")
|
// console.log("==========选择模式鼠标右击画布对象")
|
||||||
|
|
||||||
// } else
|
// } else
|
||||||
if (
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
opt.e.altKey ||
|
if (currentTool === OperationType.DRAW) {
|
||||||
opt.e.which === 2 ||
|
// 绘画模式
|
||||||
this.toolManager.currentTool.value === OperationType.PAN
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
) {
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseDownEvent(opt);
|
||||||
|
} else if (opt.e.altKey || opt.e.which === 2 || currentTool === OperationType.PAN) {
|
||||||
this.canvas.isDragging = true;
|
this.canvas.isDragging = true;
|
||||||
this.canvas.lastPosX = opt.e.clientX;
|
this.canvas.lastPosX = opt.e.clientX;
|
||||||
this.canvas.lastPosY = opt.e.clientY;
|
this.canvas.lastPosY = opt.e.clientY;
|
||||||
this.canvas.defaultCursor = "grabbing";
|
// this.canvas.defaultCursor = "grabbing";
|
||||||
|
|
||||||
// 记录拖动开始时间和位置,用于计算速度
|
// 记录拖动开始时间和位置,用于计算速度
|
||||||
this.dragStartTime = Date.now();
|
this.dragStartTime = Date.now();
|
||||||
this.lastMousePositions = []; // 重置位置历史
|
this.lastMousePositions = []; // 重置位置历史
|
||||||
|
|
||||||
if (this.canvas.isDragging) {
|
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 鼠标移动事件
|
// 鼠标移动事件
|
||||||
this.canvas.on("mouse:move", (opt) => {
|
this.canvas.on("mouse:move", (opt) => {
|
||||||
if (!this.canvas.isDragging) return;
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
|
if (currentTool === OperationType.DRAW) {
|
||||||
|
// 绘画模式
|
||||||
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseMoveEvent(opt);
|
||||||
|
} else if (this.canvas.isDragging) {
|
||||||
const vpt = this.canvas.viewportTransform;
|
const vpt = this.canvas.viewportTransform;
|
||||||
vpt[4] += opt.e.clientX - this.canvas.lastPosX;
|
vpt[4] += opt.e.clientX - this.canvas.lastPosX;
|
||||||
vpt[5] += opt.e.clientY - this.canvas.lastPosY;
|
vpt[5] += opt.e.clientY - this.canvas.lastPosY;
|
||||||
@@ -233,6 +256,7 @@ export class CanvasEventManager {
|
|||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
this.canvas.lastPosX = opt.e.clientX;
|
this.canvas.lastPosX = opt.e.clientX;
|
||||||
this.canvas.lastPosY = opt.e.clientY;
|
this.canvas.lastPosY = opt.e.clientY;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 鼠标抬起事件
|
// 鼠标抬起事件
|
||||||
@@ -284,9 +308,17 @@ export class CanvasEventManager {
|
|||||||
// 使用标准的mouse事件,Fabric.js会自动处理触摸转换
|
// 使用标准的mouse事件,Fabric.js会自动处理触摸转换
|
||||||
this.canvas.on("mouse:down", (opt) => {
|
this.canvas.on("mouse:down", (opt) => {
|
||||||
// 只在PAN模式下处理触摸事件
|
// 只在PAN模式下处理触摸事件
|
||||||
if (this.toolManager.currentTool.value !== OperationType.PAN) {
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
return;
|
if (currentTool === OperationType.DRAW) {
|
||||||
}
|
// 绘画模式
|
||||||
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseDownEvent(opt);
|
||||||
|
} else if (currentTool === OperationType.PAN) {
|
||||||
|
|
||||||
// 平滑停止任何正在进行的惯性动画
|
// 平滑停止任何正在进行的惯性动画
|
||||||
this.stopInertiaAnimation(true);
|
this.stopInertiaAnimation(true);
|
||||||
@@ -334,14 +366,23 @@ export class CanvasEventManager {
|
|||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
opt.e.preventDefault();
|
opt.e.preventDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触摸移动事件 - 优化性能
|
// 触摸移动事件 - 优化性能
|
||||||
this.canvas.on("mouse:move", (opt) => {
|
this.canvas.on("mouse:move", (opt) => {
|
||||||
// 只在PAN模式下处理
|
|
||||||
if (this.toolManager.currentTool.value !== OperationType.PAN) {
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
return;
|
if (currentTool === OperationType.DRAW) {
|
||||||
}
|
// 绘画模式
|
||||||
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseMoveEvent(opt);
|
||||||
|
} else if (currentTool === OperationType.PAN) {
|
||||||
|
|
||||||
// 检查是否是触摸事件
|
// 检查是否是触摸事件
|
||||||
const isTouch = opt.e.type && opt.e.type.includes("touch");
|
const isTouch = opt.e.type && opt.e.type.includes("touch");
|
||||||
@@ -435,20 +476,29 @@ export class CanvasEventManager {
|
|||||||
this.canvas.lastPosX = currentX;
|
this.canvas.lastPosX = currentX;
|
||||||
this.canvas.lastPosY = currentY;
|
this.canvas.lastPosY = currentY;
|
||||||
opt.e.preventDefault();
|
opt.e.preventDefault();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触摸结束事件
|
// 触摸结束事件
|
||||||
this.canvas.on("mouse:up", (opt) => {
|
this.canvas.on("mouse:up", (opt) => {
|
||||||
// 只在PAN模式下处理
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
if (this.toolManager.currentTool.value !== OperationType.PAN) {
|
if (currentTool === OperationType.DRAW) {
|
||||||
return;
|
// 绘画模式
|
||||||
}
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseUpEvent(opt);
|
||||||
|
} else if (currentTool === OperationType.PAN) {
|
||||||
|
|
||||||
// 重置触摸状态
|
// 重置触摸状态
|
||||||
this.touchState.isZooming = false;
|
this.touchState.isZooming = false;
|
||||||
this.touchState.initialDistance = 0;
|
this.touchState.initialDistance = 0;
|
||||||
|
|
||||||
this.handleDragEnd(opt, true);
|
this.handleDragEnd(opt, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加原生触摸事件监听器作为备用方案
|
// 添加原生触摸事件监听器作为备用方案
|
||||||
@@ -602,25 +652,29 @@ export class CanvasEventManager {
|
|||||||
* 处理拖动结束(鼠标抬起或触摸结束)
|
* 处理拖动结束(鼠标抬起或触摸结束)
|
||||||
*/
|
*/
|
||||||
handleDragEnd(opt, isTouch = false) {
|
handleDragEnd(opt, isTouch = false) {
|
||||||
if (this.canvas.isDragging) {
|
const currentTool = this.toolManager.currentTool.value;
|
||||||
// 使用动画管理器处理惯性效果
|
if (currentTool === OperationType.DRAW) {
|
||||||
|
// 绘画模式
|
||||||
|
} else if (currentTool === OperationType.ERASER) {
|
||||||
|
// 橡皮擦模式
|
||||||
|
} else if (currentTool === OperationType.SELECTBOX) {
|
||||||
|
// 选择框模式
|
||||||
|
} else if (currentTool === OperationType.RECTANGLE) {
|
||||||
|
// 矩形模式
|
||||||
|
this.rectToolManager.mouseUpEvent(opt);
|
||||||
|
} else if (this.canvas.isDragging) {
|
||||||
// if (this.lastMousePositions.length > 1 && opt && opt.e) {
|
// if (this.lastMousePositions.length > 1 && opt && opt.e) {
|
||||||
// this.animationManager.applyInertiaEffect(
|
// this.animationManager.applyInertiaEffect(
|
||||||
// this.lastMousePositions,
|
// this.lastMousePositions,
|
||||||
// isTouch
|
// isTouch
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
this.canvas.isDragging = false;
|
this.canvas.isDragging = false;
|
||||||
|
|
||||||
if (this.toolManager) {
|
|
||||||
// this.toolManager.restoreSelectionState(); // 恢复选择状态
|
|
||||||
}
|
|
||||||
const vpt = this.canvas.viewportTransform;
|
const vpt = this.canvas.viewportTransform;
|
||||||
this.canvas.setViewportTransform(vpt);
|
this.canvas.setViewportTransform(vpt);
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setupSelectionEvents() {
|
setupSelectionEvents() {
|
||||||
// 监听对象选择事件
|
// 监听对象选择事件
|
||||||
@@ -827,30 +881,6 @@ export class CanvasEventManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
|
||||||
// 移除所有事件监听
|
|
||||||
this.canvas.off();
|
|
||||||
|
|
||||||
// 清理 Mac 专用的原生事件监听器
|
|
||||||
if (this.deviceInfo.isMac && this.canvas.upperCanvasEl) {
|
|
||||||
const upperCanvas = this.canvas.upperCanvasEl;
|
|
||||||
|
|
||||||
// 移除手势事件监听器
|
|
||||||
upperCanvas.removeEventListener("gesturestart", null);
|
|
||||||
upperCanvas.removeEventListener("gesturechange", null);
|
|
||||||
upperCanvas.removeEventListener("gestureend", null);
|
|
||||||
upperCanvas.removeEventListener("wheel", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除计时器
|
|
||||||
if (this.longPressTimer) {
|
|
||||||
clearTimeout(this.longPressTimer);
|
|
||||||
this.longPressTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 停止所有动画
|
|
||||||
this.stopInertiaAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 精确检测设备类型,区分 PC、Mac、平板和移动设备
|
* 精确检测设备类型,区分 PC、Mac、平板和移动设备
|
||||||
@@ -1032,4 +1062,30 @@ export class CanvasEventManager {
|
|||||||
{ passive: true }
|
{ passive: true }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
this.rectToolManager?.dispose()
|
||||||
|
// 移除所有事件监听
|
||||||
|
this.canvas.off();
|
||||||
|
|
||||||
|
// 清理 Mac 专用的原生事件监听器
|
||||||
|
if (this.deviceInfo.isMac && this.canvas.upperCanvasEl) {
|
||||||
|
const upperCanvas = this.canvas.upperCanvasEl;
|
||||||
|
|
||||||
|
// 移除手势事件监听器
|
||||||
|
upperCanvas.removeEventListener("gesturestart", null);
|
||||||
|
upperCanvas.removeEventListener("gesturechange", null);
|
||||||
|
upperCanvas.removeEventListener("gestureend", null);
|
||||||
|
upperCanvas.removeEventListener("wheel", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除计时器
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止所有动画
|
||||||
|
this.stopInertiaAnimation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
import { createStaticCanvas } from './canvasFactory'
|
import { createStaticCanvas } from './canvasFactory'
|
||||||
import { getObjectsBoundingBox, cloneObjects } from './canvasMethod'
|
import { getObjectsBoundingBox, cloneObjects } from './canvasMethod'
|
||||||
|
/** 导出画布为图片 */
|
||||||
|
export async function exportCanvasToImage(canvas) {
|
||||||
|
const clonedObjects = await cloneObjects(canvas.getObjects())
|
||||||
|
const staticCanvas = createStaticCanvas(document.createElement('canvas'))
|
||||||
|
const width = canvas.clipPath.width
|
||||||
|
const height = canvas.clipPath.height
|
||||||
|
staticCanvas.setWidth(width)
|
||||||
|
staticCanvas.setHeight(height)
|
||||||
|
clonedObjects.forEach(obj => staticCanvas.add(obj))
|
||||||
|
// 导出图片
|
||||||
|
const dataURL = staticCanvas.toDataURL({
|
||||||
|
type: 'image/png',
|
||||||
|
quality: 1,
|
||||||
|
})
|
||||||
|
return dataURL
|
||||||
|
}
|
||||||
/** 导出指定对象 */
|
/** 导出指定对象 */
|
||||||
export async function exportObjectsToImage(objects = [], isDetails = false) {
|
export async function exportObjectsToImage(objects = [], isDetails = false) {
|
||||||
const clonedObjects = await cloneObjects(objects)
|
const clonedObjects = await cloneObjects(objects)
|
||||||
|
|||||||
Reference in New Issue
Block a user