diff --git a/src/assets/icons/dc/arrow.svg b/src/assets/icons/dc/arrow.svg
new file mode 100644
index 0000000..4911aad
--- /dev/null
+++ b/src/assets/icons/dc/arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/dc/copy.svg b/src/assets/icons/dc/copy.svg
new file mode 100644
index 0000000..2edd3e6
--- /dev/null
+++ b/src/assets/icons/dc/copy.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/dc/dui.svg b/src/assets/icons/dc/dui.svg
new file mode 100644
index 0000000..0b4d3f1
--- /dev/null
+++ b/src/assets/icons/dc/dui.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/dc/ellipse.svg b/src/assets/icons/dc/ellipse.svg
new file mode 100644
index 0000000..8ba4aee
--- /dev/null
+++ b/src/assets/icons/dc/ellipse.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/dc/line.svg b/src/assets/icons/dc/line.svg
new file mode 100644
index 0000000..bfc76e8
--- /dev/null
+++ b/src/assets/icons/dc/line.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/dc/star.svg b/src/assets/icons/dc/star.svg
new file mode 100644
index 0000000..30b0b5c
--- /dev/null
+++ b/src/assets/icons/dc/star.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/dc/triangle.svg b/src/assets/icons/dc/triangle.svg
new file mode 100644
index 0000000..7160af0
--- /dev/null
+++ b/src/assets/icons/dc/triangle.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/Canvas/DepthCanvas/components/depth-header-tools.vue b/src/components/Canvas/DepthCanvas/components/depth-header-tools.vue
index 040aac7..42c82f9 100644
--- a/src/components/Canvas/DepthCanvas/components/depth-header-tools.vue
+++ b/src/components/Canvas/DepthCanvas/components/depth-header-tools.vue
@@ -2,14 +2,31 @@
+
Gap X
@@ -101,6 +114,7 @@
const gapX = ref(0)
const gapY = ref(0)
const offset = ref({ x: 0, y: 0 })
+ const opacity = ref(100)
const updateData = async () => {
await nextTick()
@@ -113,6 +127,7 @@
x: Math.round((fill.offsetX / props.object.width) * 100),
y: Math.round((fill.offsetY / props.object.height) * 100)
}
+ opacity.value = Math.round(props.object.opacity * 100)
}
updateData()
@@ -138,6 +153,15 @@
objectManager.updateFillRepeatGap(id.value, options, isRecord)
}
+ const inputOpacity = () => setOpacity(false)
+ const changeOpacity = () => setOpacity(true)
+ const setOpacity = (isRecord: boolean) => {
+ const options = {
+ opacity: opacity.value / 100
+ }
+ objectManager.updateOpacity(id.value, options, isRecord)
+ }
+
stateManager.event.add('canvas:undo', updateData)
stateManager.event.add('canvas:redo', updateData)
onBeforeUnmount(() => {
diff --git a/src/components/Canvas/DepthCanvas/components/layer-panel/layer-item.vue b/src/components/Canvas/DepthCanvas/components/layer-panel/layer-item.vue
index 51f044a..d1a72bb 100644
--- a/src/components/Canvas/DepthCanvas/components/layer-panel/layer-item.vue
+++ b/src/components/Canvas/DepthCanvas/components/layer-panel/layer-item.vue
@@ -22,7 +22,7 @@
>
-
+
diff --git a/src/components/Canvas/DepthCanvas/components/layer-panel/layer-list.vue b/src/components/Canvas/DepthCanvas/components/layer-panel/layer-list.vue
index 0f6f19f..d4852e3 100644
--- a/src/components/Canvas/DepthCanvas/components/layer-panel/layer-list.vue
+++ b/src/components/Canvas/DepthCanvas/components/layer-panel/layer-list.vue
@@ -63,7 +63,7 @@
layerManager.dragSort(data.info.id, newIndex)
}
const addLayer = () => {
- layerManager.createEmptyLayer()
+ layerManager.createEmptyLayer(true, true)
}
diff --git a/src/components/Canvas/DepthCanvas/manager/LayerManager.ts b/src/components/Canvas/DepthCanvas/manager/LayerManager.ts
index 0711283..b193e07 100644
--- a/src/components/Canvas/DepthCanvas/manager/LayerManager.ts
+++ b/src/components/Canvas/DepthCanvas/manager/LayerManager.ts
@@ -3,6 +3,7 @@ import { fabric } from 'fabric-with-all'
import { createId } from '../../tools/tools'
import { exportObjectsToImage, exportObjectToThumbnail } from '../tools/exportMethod'
import { OperationType } from '../tools/layerHelper'
+import { getArrowPath, cloneObjects, getStarArr } from '../tools/canvasMethod'
export class LayerManager {
stateManager: any
@@ -53,6 +54,7 @@ export class LayerManager {
this.canvasManager.renderAll()
}
}
+ /** 删除指定图层 */
deleteLayerById(id, isActive = true) {
this.canvasManager.deleteObjectById(id)
if (id === this.activeID.value && isActive) {
@@ -60,6 +62,24 @@ export class LayerManager {
}
if (isActive) this.stateManager.recordState()
}
+ /** 复制指定图层 */
+ copyLayerById(id) {
+ const object = this.canvasManager.getObjectById(id)
+ if (!object) return console.warn('复制图层失败,对象不存在ID:', id)
+ cloneObjects([object]).then(objects => {
+ const newObject = objects[0]
+ const info = JSON.parse(JSON.stringify(newObject.info))
+ info.id = createId("image")
+ // info.name = info.name
+ newObject.set({
+ top: newObject.top + 15,
+ left: newObject.left + 15,
+ info: info,
+ })
+ this.canvasManager.add(newObject)
+ this.setActiveID(newObject.info.id)
+ })
+ }
// 拖拽排序
dragSort(id, newIndex) {
const index = Math.abs(this.layers.value.length - newIndex - 1)
@@ -90,7 +110,7 @@ export class LayerManager {
}
}
/** 创建空图层 */
- createEmptyLayer(isRecord = true) {
+ createEmptyLayer(isRecord = true, isActive = false) {
const emptyObject = new fabric.Rect({
width: 0,
height: 0,
@@ -102,6 +122,7 @@ export class LayerManager {
})
this.setLayerPosition(emptyObject)
this.canvasManager.add(emptyObject, isRecord)
+ if (isActive) this.setActiveID(emptyObject.info.id, false)
return emptyObject
}
/** 创建文本图层 */
@@ -138,23 +159,109 @@ export class LayerManager {
if (isActive) this.setActiveID(rectObject.info.id)
return rectObject
}
- /** 创建圆形图层 */
- async createCircleLayer(options?: any, isActive = false) {
- const circleObject = new fabric.Circle({
+ /** 创建直线图层 */
+ async createLineLayer(options?: any, isActive = false) {
+ const line = [options?.x1 || 0, options?.y1 || 0, options?.x2 || 100, options?.y2 || 0]
+ delete options.x1
+ delete options.y1
+ delete options.x2
+ delete options.y2
+ const lineObject = new fabric.Line(line, {
+ stroke: 'black', // 线条颜色
+ strokeWidth: 2, // 线条粗细
+ ...(options || {}),
+ info: {
+ id: createId("line"),
+ name: '直线图层',
+ ...(options?.info || {}),
+ }
+ })
+ this.setLayerPosition(lineObject, options)
+ await this.canvasManager.add(lineObject)
+ if (isActive) this.setActiveID(lineObject.info.id)
+ return lineObject
+ }
+ /** 创建椭圆图层 */
+ async createEllipseLayer(options?: any, isActive = false) {
+ const ellipseObject = new fabric.Ellipse({
radius: 50,
fill: '#000',
...(options || {}),
info: {
- id: createId("circle"),
- name: '圆形图层',
+ id: createId("ellipse"),
+ name: '椭圆图层',
...(options?.info || {}),
}
})
- this.setLayerPosition(circleObject, options)
- await this.canvasManager.add(circleObject)
- if (isActive) this.setActiveID(circleObject.info.id)
- return circleObject
+ this.setLayerPosition(ellipseObject, options)
+ await this.canvasManager.add(ellipseObject)
+ if (isActive) this.setActiveID(ellipseObject.info.id)
+ return ellipseObject
}
+ /** 创建三角形图层 */
+ async createTriangleLayer(options?: any, isActive = false) {
+ const triangleObject = new fabric.Triangle({
+ width: 100,
+ height: 100,
+ fill: '#000',
+ ...(options || {}),
+ info: {
+ id: createId("triangle"),
+ name: '三角形图层',
+ ...(options?.info || {}),
+ }
+ })
+ this.setLayerPosition(triangleObject, options)
+ await this.canvasManager.add(triangleObject)
+ if (isActive) this.setActiveID(triangleObject.info.id)
+ return triangleObject
+ }
+ /** 创建五角星图层 */
+ async createStarLayer(options?: any, isActive = false) {
+ const width = options?.width || 100
+ const height = options?.height || 100
+ delete options.points
+ const starObject = new fabric.Polygon(getStarArr(width, height), {
+ fill: '#000',
+ ...(options || {}),
+ info: {
+ id: createId("star"),
+ name: '五角星图层',
+ ...(options?.info || {}),
+ }
+ })
+ this.setLayerPosition(starObject, options)
+ await this.canvasManager.add(starObject)
+ if (isActive) this.setActiveID(starObject.info.id)
+ return starObject
+ }
+ /** 创建箭头图层 */
+ async createArrowLayer(options?: any, isActive = false) {
+ const width = options?.width || 100
+ const height = options?.height || 10
+ delete options.width
+ delete options.height
+ const arrowObject = new fabric.Path(getArrowPath(width, height), {
+ stroke: '#000', // 只设置边框颜色
+ strokeWidth: 3, // 边框宽度
+ fill: 'transparent', // 不填充
+ strokeLineCap: 'round',
+ strokeLineJoin: 'round',
+ ...(options || {}),
+ info: {
+ id: createId("star"),
+ name: '箭头图层',
+ ...(options?.info || {}),
+ }
+ });
+ this.setLayerPosition(arrowObject, options)
+ this.canvasManager.add(arrowObject)
+ if (isActive) this.setActiveID(arrowObject.info.id)
+ return arrowObject
+ }
+
+
+
/** 创建图片图层 */
async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any, isRecord = true) {
const canvasWidth = this.canvasManager.canvasWidth
diff --git a/src/components/Canvas/DepthCanvas/manager/ObjectManager.ts b/src/components/Canvas/DepthCanvas/manager/ObjectManager.ts
index e7b3e13..363808c 100644
--- a/src/components/Canvas/DepthCanvas/manager/ObjectManager.ts
+++ b/src/components/Canvas/DepthCanvas/manager/ObjectManager.ts
@@ -207,5 +207,24 @@ export class ObjectManager {
}
}
+
+ /** 修改透明度
+ * @param id 目标对象ID
+ * @param options 透明度参数
+ * @param options.opacity 透明度
+ * @param isRecord 是否记录
+ */
+ async updateOpacity(id: string, options: any, isRecord: boolean) {
+ const object = this.getFillRepeatObject(id)
+ if (!object) return null
+ const opacity = options.opacity
+ object.set("opacity", opacity);
+ this.canvasManager.renderAll()
+ if (isRecord) {
+ this.stateManager.recordState()
+ this.layerManager.updateLayerThumbnailsById(id)
+ }
+ }
+
dispose() { }
}
\ No newline at end of file
diff --git a/src/components/Canvas/DepthCanvas/manager/RectToolManager.ts b/src/components/Canvas/DepthCanvas/manager/ShapeToolManager copy.ts
similarity index 93%
rename from src/components/Canvas/DepthCanvas/manager/RectToolManager.ts
rename to src/components/Canvas/DepthCanvas/manager/ShapeToolManager copy.ts
index 2c5eeab..3356852 100644
--- a/src/components/Canvas/DepthCanvas/manager/RectToolManager.ts
+++ b/src/components/Canvas/DepthCanvas/manager/ShapeToolManager copy.ts
@@ -1,3 +1,4 @@
+import { OperationType, OperationTypes } from "../tools/layerHelper";
import { fabric } from 'fabric-with-all'
/** 矩形工具管理器 */
export class RectToolManager {
@@ -10,6 +11,9 @@ export class RectToolManager {
startX: number = 0
startY: number = 0
demoObject: any
+ tools = [
+ OperationType.RECTANGLE
+ ]
constructor(options) {
this.canvasManager = options.canvasManager
this.stateManager = options.stateManager
diff --git a/src/components/Canvas/DepthCanvas/manager/ShapeToolManager.ts b/src/components/Canvas/DepthCanvas/manager/ShapeToolManager.ts
new file mode 100644
index 0000000..018d298
--- /dev/null
+++ b/src/components/Canvas/DepthCanvas/manager/ShapeToolManager.ts
@@ -0,0 +1,255 @@
+import { OperationType, OperationTypes } from "../tools/layerHelper";
+import { getStarArr, getArrowPath, distance, angleBetweenPointsDegrees } from "../tools/canvasMethod";
+import { fabric } from 'fabric-with-all'
+/** 形状管理器 */
+export class ShapeToolManager {
+ // 管理器
+ canvasManager: any
+ stateManager: any
+ layerManager: any
+ toolManager: any
+
+ isDragging: boolean = false
+ startX: number = 0
+ startY: number = 0
+ demoObject: any
+ tools = [
+ OperationType.RECTANGLE,
+ OperationType.LINE,
+ OperationType.ARROW,
+ OperationType.ELLIPSE,
+ OperationType.TRIANGLE,
+ OperationType.STAR,
+ ]
+ constructor(options) {
+ this.canvasManager = options.canvasManager
+ this.stateManager = options.stateManager
+ this.layerManager = options.layerManager
+ this.toolManager = options.toolManager
+ }
+ mouseDownEvent(e) {
+ this.isDragging = false
+ this.demoObject = null
+
+ this.startX = e.absolutePointer.x
+ this.startY = e.absolutePointer.y
+ const currentTool = this.toolManager.currentTool.value
+ if (currentTool === OperationType.RECTANGLE) {
+ this.demoObject = this.downRectangle()
+ } else if (currentTool === OperationType.LINE) {
+ this.demoObject = this.downLine()
+ } else if (currentTool === OperationType.ELLIPSE) {
+ this.demoObject = this.downEllipse()
+ } else if (currentTool === OperationType.TRIANGLE) {
+ this.demoObject = this.downTriangle()
+ } else if (currentTool === OperationType.STAR) {
+ this.demoObject = this.downStar()
+ } else if (currentTool === OperationType.ARROW) {
+ this.demoObject = this.downArrow()
+ }
+ if (!this.demoObject) return;
+ this.demoObject.set({
+ evented: false,
+ })
+ this.demoObject.set
+ this.isDragging = true
+ this.canvasManager.canvas.add(this.demoObject)
+ this.canvasManager.canvas.renderAll()
+ }
+ mouseMoveEvent(e) {
+ if (!this.isDragging) return;
+ var width = e.absolutePointer.x - this.startX
+ var height = e.absolutePointer.y - this.startY
+ var left = this.startX
+ var top = this.startY
+ if (width < 0) {
+ left += width
+ width = -width
+ }
+ if (height < 0) {
+ top += height
+ height = -height
+ }
+ const currentTool = this.toolManager.currentTool.value
+ if (currentTool === OperationType.RECTANGLE) {
+ this.moveRectangle({ width, height, left, top })
+ } else if (currentTool === OperationType.LINE) {
+ this.moveLine(e.absolutePointer)
+ } else if (currentTool === OperationType.ELLIPSE) {
+ this.moveEllipse({ width, height, left, top })
+ } else if (currentTool === OperationType.TRIANGLE) {
+ this.moveTriangle({ width, height, left, top })
+ } else if (currentTool === OperationType.STAR) {
+ this.moveStar({ width, height, left, top })
+ } else if (currentTool === OperationType.ARROW) {
+ this.moveArrow(e.absolutePointer)
+ }
+ this.demoObject.set({
+ evented: false,
+ })
+ this.canvasManager.canvas.renderAll()
+ }
+ mouseUpEvent(e) {
+ if (!this.isDragging) return;
+ this.isDragging = false;
+ const object = this.demoObject.toJSON("evented")
+ const currentTool = this.toolManager.currentTool.value
+ if (currentTool === OperationType.RECTANGLE) {
+ this.upRectangle(object)
+ } else if (currentTool === OperationType.LINE) {
+ this.upLine(object)
+ } else if (currentTool === OperationType.ELLIPSE) {
+ this.upEllipse(object)
+ } else if (currentTool === OperationType.TRIANGLE) {
+ this.upTriangle(object)
+ } else if (currentTool === OperationType.STAR) {
+ this.upStar(object)
+ } else if (currentTool === OperationType.ARROW) {
+ this.upArrow(object)
+ }
+ this.canvasManager.canvas.remove(this.demoObject)
+ this.demoObject = null
+ this.canvasManager.canvas.renderAll()
+ }
+
+ /** 绘制矩形 */
+ downRectangle() {
+ const rect = new fabric.Rect({
+ left: this.startX,
+ top: this.startY,
+ width: 0,
+ height: 0,
+ fill: '#000',
+ })
+ return rect
+ }
+ moveRectangle({ width, height, left, top }) {
+ this.demoObject.set({ width, height, left, top })
+
+ }
+ upRectangle(object) {
+ if (object.width === 0) object.width = 100
+ if (object.height === 0) object.height = 100
+ this.layerManager.createRectLayer(object, true)
+ }
+
+ /** 绘制直线 */
+ downLine() {
+ const line = new fabric.Line([this.startX, this.startY, this.startX, this.startY], {
+ stroke: 'black', // 线条颜色
+ strokeWidth: 2 // 线条粗细
+ })
+ return line
+ }
+ moveLine({ x, y }) {
+ this.demoObject.set({
+ x1: this.startX,
+ y1: this.startY,
+ x2: x,
+ y2: y,
+ })
+ }
+ upLine(object) {
+ this.layerManager.createLineLayer(object, true)
+ }
+
+ /** 绘制椭圆 */
+ downEllipse() {
+ const circle = new fabric.Ellipse({
+ left: this.startX,
+ top: this.startY,
+ fill: '#000',
+ })
+ return circle
+ }
+ moveEllipse({ width, height, left, top }) {
+ this.demoObject.set({ rx: width / 2, ry: height / 2, left, top })
+ }
+ upEllipse(object) {
+ if (object.rx === 0) object.rx = 50
+ if (object.ry === 0) object.ry = 50
+ this.layerManager.createEllipseLayer(object, true)
+ }
+
+
+ /** 绘制三角形 */
+ downTriangle() {
+ const triangle = new fabric.Triangle({
+ left: this.startX,
+ top: this.startY,
+ width: 0,
+ height: 0,
+ fill: '#000',
+ })
+ return triangle
+ }
+ moveTriangle({ width, height, left, top }) {
+ this.demoObject.set({ width, height, left, top })
+ }
+ upTriangle(object) {
+ if (object.width === 0) object.width = 100
+ if (object.height === 0) object.height = 100
+ this.layerManager.createTriangleLayer(object, true)
+ }
+
+
+ /** 绘制五角星 */
+ downStar() {
+ const star = new fabric.Polygon(getStarArr(0, 0), {
+ left: this.startX,
+ top: this.startY,
+ width: 0,
+ height: 0,
+ fill: '#000',
+ strokeLineJoin: 'round', // 圆角连接
+ strokeLineCap: 'round', // 圆角端点
+ });
+
+ return star
+ }
+ moveStar({ width, height, left, top }) {
+ this.demoObject.set({ left, top, width, height, points: getStarArr(width, height) })
+ }
+ upStar(object) {
+ if (object.width === 0) object.width = 100
+ if (object.height === 0) object.height = 100
+ this.layerManager.createStarLayer(object, true)
+ }
+
+ /** 绘制箭头 */
+ downArrow() {
+ return new fabric.Path();
+ }
+ moveArrow({ x, y }) {
+ const width = distance(this.startX, this.startY, x, y)
+ const angle = angleBetweenPointsDegrees(this.startX, this.startY, x, y)
+ this.canvasManager.canvas.remove(this.demoObject)
+ const arrow = new fabric.Path(getArrowPath(width, 10), {
+ left: this.startX,
+ top: this.startY,
+ stroke: '#000', // 只设置边框颜色
+ strokeWidth: 3, // 边框宽度
+ fill: 'transparent', // 不填充
+ strokeLineCap: 'round',
+ strokeLineJoin: 'round',
+ originY: 'center',
+ angle: angle,
+ });
+ this.canvasManager.canvas.add(arrow)
+ this.demoObject = arrow
+ }
+ upArrow(object) {
+ if (object.originY !== "center") {
+ this.layerManager.createArrowLayer({
+ left: this.startX,
+ top: this.startY,
+ }, true)
+ } else {
+ this.layerManager.createArrowLayer(object, true)
+ }
+ }
+
+
+
+ dispose() { }
+}
diff --git a/src/components/Canvas/DepthCanvas/manager/ToolManager.ts b/src/components/Canvas/DepthCanvas/manager/ToolManager.ts
index 8b17c25..cd640d8 100644
--- a/src/components/Canvas/DepthCanvas/manager/ToolManager.ts
+++ b/src/components/Canvas/DepthCanvas/manager/ToolManager.ts
@@ -54,6 +54,32 @@ export class ToolManager {
name: OperationType.RECTANGLE,
cursor: "crosshair",
},
+ /** 直线工具 */
+ {
+ name: OperationType.LINE,
+ cursor: "crosshair",
+ },
+ /** 箭头工具 */
+ {
+ name: OperationType.ARROW,
+ cursor: "crosshair",
+ },
+ /** 椭圆工具 */
+ {
+ name: OperationType.ELLIPSE,
+ cursor: "crosshair",
+ },
+ /** 三角形工具 */
+ {
+ name: OperationType.TRIANGLE,
+ cursor: "crosshair",
+ },
+ /** 五角星工具 */
+ {
+ name: OperationType.STAR,
+ cursor: "crosshair",
+ },
+
]
}
onMounted() {
diff --git a/src/components/Canvas/DepthCanvas/manager/events/CanvasEventManager.js b/src/components/Canvas/DepthCanvas/manager/events/CanvasEventManager.js
index 55f0b2a..335a056 100644
--- a/src/components/Canvas/DepthCanvas/manager/events/CanvasEventManager.js
+++ b/src/components/Canvas/DepthCanvas/manager/events/CanvasEventManager.js
@@ -1,6 +1,6 @@
import { isBoolean } from "lodash-es";
import { OperationType, OperationTypes } from "../../tools/layerHelper";
-import { RectToolManager } from "../RectToolManager"
+import { ShapeToolManager } from "../ShapeToolManager"
import { AISelectboxToolManager } from "../AISelectboxToolManager"
@@ -32,7 +32,7 @@ export class CanvasEventManager {
toolManager: this.toolManager,
layerManager: this.layerManager,
}
- this.rectToolManager = new RectToolManager(managers)
+ this.shapeToolManager = new ShapeToolManager(managers)
this.aiSelectboxToolManager = new AISelectboxToolManager(managers)
// 初始化所有事件
@@ -209,9 +209,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseDownEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseDownEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseDownEvent(opt);
} else if (opt.e.altKey || opt.e.which === 2 || currentTool === OperationType.PAN) {
this.canvas.isDragging = true;
this.canvas.lastPosX = opt.e.clientX;
@@ -237,9 +237,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseMoveEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseMoveEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseMoveEvent(opt);
} else if (this.canvas.isDragging) {
const vpt = this.canvas.viewportTransform;
vpt[4] += opt.e.clientX - this.canvas.lastPosX;
@@ -321,9 +321,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseUpEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseDownEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseDownEvent(opt);
} else if (currentTool === OperationType.PAN) {
// 平滑停止任何正在进行的惯性动画
@@ -386,9 +386,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseMoveEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseMoveEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseMoveEvent(opt);
} else if (currentTool === OperationType.PAN) {
// 检查是否是触摸事件
@@ -496,9 +496,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseUpEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseUpEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseUpEvent(opt);
} else if (currentTool === OperationType.PAN) {
// 重置触摸状态
@@ -668,9 +668,9 @@ export class CanvasEventManager {
} else if (currentTool === OperationType.SELECTBOX) {
// 选择框模式
this.aiSelectboxToolManager.mouseUpEvent(opt);
- } else if (currentTool === OperationType.RECTANGLE) {
- // 矩形模式
- this.rectToolManager.mouseUpEvent(opt);
+ } else if (this.shapeToolManager.tools.includes(currentTool)) {
+ // 形状模式
+ this.shapeToolManager.mouseUpEvent(opt);
} else if (this.canvas.isDragging) {
// if (this.lastMousePositions.length > 1 && opt && opt.e) {
// this.animationManager.applyInertiaEffect(
@@ -1074,7 +1074,7 @@ export class CanvasEventManager {
}
dispose() {
- this.rectToolManager?.dispose()
+ this.shapeToolManager?.dispose()
this.aiSelectboxToolManager?.dispose()
// 移除所有事件监听
this.canvas.off();
diff --git a/src/components/Canvas/DepthCanvas/manager/events/KeyEventManager.ts b/src/components/Canvas/DepthCanvas/manager/events/KeyEventManager.ts
index eb347d3..6511043 100644
--- a/src/components/Canvas/DepthCanvas/manager/events/KeyEventManager.ts
+++ b/src/components/Canvas/DepthCanvas/manager/events/KeyEventManager.ts
@@ -9,13 +9,14 @@ export class KeyEventManager {
/** 处理键盘事件 */
_handleKeyDown: any
handleKeyDown(event: any) {
+ const activeID = this.stateManager.layerManager.activeID.value
const ctrl = event.ctrlKey ? 'ctrl-' : "";
const shift = event.shiftKey ? 'shift-' : "";
const key = event.key;
const reg = new RegExp(`^${ctrl}${shift}${key}$`, 'i')
const list = [
- // { key: "ctrl-c", handler: () => this.handleCopy(event) },
- // { key: "delete", handler: () => this.handleDelete(event) },
+ { key: "ctrl-c", handler: () => this.stateManager.layerManager.copyLayerById(activeID) },
+ { key: "delete", handler: () => this.stateManager.layerManager.deleteLayerById(activeID) },
{ key: "ctrl-z", handler: () => this.stateManager.undoState() },
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
]
diff --git a/src/components/Canvas/DepthCanvas/tools/canvasMethod.js b/src/components/Canvas/DepthCanvas/tools/canvasMethod.js
index acd568a..a506e8d 100644
--- a/src/components/Canvas/DepthCanvas/tools/canvasMethod.js
+++ b/src/components/Canvas/DepthCanvas/tools/canvasMethod.js
@@ -39,4 +39,57 @@ export async function getObjectsBoundingBox(objects = []) {
width: box2.x - box1.x,
height: box2.y - box1.y,
}
-}
\ No newline at end of file
+}
+
+/** 获取五角星数组 */
+export function getStarArr(width = 0, height = 0) {
+ const arr = [
+ { x: 0, y: -0.5 }, // 顶点0 (上)
+ { x: 0.15, y: -0.15 }, // 顶点1 (内)
+ { x: 0.50, y: -0.15 }, // 顶点2 (右上外)
+ { x: 0.20, y: 0.10 }, // 顶点3 (内)
+ { x: 0.30, y: 0.50 }, // 顶点4 (右下外)
+ { x: 0.0, y: 0.25 }, // 顶点5 (内)
+ { x: -0.30, y: 0.50 }, // 顶点6 (左下外)
+ { x: -0.20, y: 0.10 }, // 顶点7 (内)
+ { x: -0.50, y: -0.15 }, // 顶点8 (左上外)
+ { x: -0.15, y: -0.15 } // 顶点9 (内)
+ ]
+ return arr.map(item => ({
+ x: item.x * width,
+ y: item.y * height,
+ }))
+}
+/** 获取箭头路径 */
+export function getArrowPath(width = 0, height = 0) {
+ const arr = [
+ ["M", 0, height / 2],
+ ["L", width, height / 2],
+ ["M", width - 8, 0],
+ ["L", width, height / 2],
+ ["L", width - 8, height],
+ ]
+ var path = ""
+ arr.forEach(item => {
+ path += item.join(" ") + " "
+ })
+ return path
+}
+
+/** 计算两点之间的距离 */
+export function distance(x1, y1, x2, y2) {
+ const dx = x2 - x1;
+ const dy = y2 - y1;
+ return Math.sqrt(dx * dx + dy * dy);
+}
+/** 计算两点之间的角度(角度) */
+export function angleBetweenPointsDegrees(x1, y1, x2, y2) {
+ const dx = x2 - x1;
+ const dy = y2 - y1;
+
+ // 计算弧度并转换为角度
+ const rad = Math.atan2(dy, dx);
+ const deg = rad * 180 / Math.PI;
+
+ return deg;
+}
diff --git a/src/components/Canvas/DepthCanvas/tools/layerHelper.js b/src/components/Canvas/DepthCanvas/tools/layerHelper.js
index cbead70..acdb191 100644
--- a/src/components/Canvas/DepthCanvas/tools/layerHelper.js
+++ b/src/components/Canvas/DepthCanvas/tools/layerHelper.js
@@ -29,12 +29,16 @@ export const OperationType = {
PAN: "pan", // 拖拽模式
DRAW: "draw", // 绘画模式
ERASER: "eraser", // 橡皮擦模式
- IMAGE: "image",// 图片工具模式
SELECTBOX: "selectbox",// 选择框工具模式
+
RECTANGLE: "rectangle",// 矩形工具模式
+ LINE: "line",// 直线工具模式
+ ARROW: "arrow",// 箭头工具模式
+ ELLIPSE: "ellipse",// 椭圆工具模式
+ TRIANGLE: "triangle",// 三角形工具模式
+ STAR: "star",// 五角星工具模式
+
TEXT: "text",// 文字工具模式
- UNDO: "undo",// 撤销工具模式
- REDO: "redo",// 重做工具模式
};
// 所有操作模式类型列表
diff --git a/src/main.ts b/src/main.ts
index f630064..9cc7718 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -17,9 +17,12 @@ import 'element-plus/dist/index.css'
import ignoredWarning from './ignoredWarning'
+import vEllipsis from './utils/ellispsis'
+
const app = createApp(App)
ignoredWarning(app)
+app.directive('ellipsis', vEllipsis)
app.use(router)
.use(ElementPlus)
.use(store)
diff --git a/src/utils/ellispsis.ts b/src/utils/ellispsis.ts
new file mode 100644
index 0000000..23f6ec8
--- /dev/null
+++ b/src/utils/ellispsis.ts
@@ -0,0 +1,52 @@
+import type { Directive } from 'vue'
+/**
+ * 多行文本省略指令(悬浮显示完整内容)
+ * @directive v-ellipsis
+ * @param {number} [value=3] - 超过value行数时显示省略号,不传参数默认为3
+ */
+
+const applyStyles = (el: HTMLElement, binding: any) => {
+ const lines = typeof binding.value === 'number' && binding.value > 0 ? binding.value : 3
+
+ el.style.display = '-webkit-box'
+ el.style.webkitBoxOrient = 'vertical'
+ el.style.overflow = 'hidden'
+ el.style.webkitLineClamp = lines.toString()
+
+ el.style.maxHeight = `${lines}lh`
+}
+
+const checkTruncated = (el: HTMLElement) => {
+ const isTruncated = el.scrollHeight > el.clientHeight + 1
+ if (isTruncated) {
+ el.title = el.textContent?.trim() || ''
+ } else {
+ el.removeAttribute('title')
+ }
+}
+
+const vEllipsis: Directive = {
+ mounted(el, binding) {
+ applyStyles(el, binding)
+ checkTruncated(el)
+
+ const ro = new ResizeObserver(() => checkTruncated(el))
+ ro.observe(el)
+ ;(el as any)._ellipsisObserver = ro
+ },
+
+ updated(el, binding) {
+ applyStyles(el, binding)
+ checkTruncated(el)
+ },
+
+ unmounted(el) {
+ const ro = (el as any)._ellipsisObserver
+ if (ro) {
+ ro.disconnect()
+ delete (el as any)._ellipsisObserver
+ }
+ }
+}
+
+export default vEllipsis
diff --git a/src/views/home/agent/components/Preview.vue b/src/views/home/agent/components/Preview.vue
index b21caff..8fd42dd 100644
--- a/src/views/home/agent/components/Preview.vue
+++ b/src/views/home/agent/components/Preview.vue
@@ -53,12 +53,12 @@
-
-
+
+
{{ item }}
-
{{ item }}
+
{{ item }}
@@ -328,16 +328,27 @@
.url-item {
width: 24rem;
height: 28.7rem;
+ line-height: 2rem;
word-break: break-all;
background: url('@/assets/images/web-card.png') no-repeat;
background-size: 100% 100%;
padding: 5rem 1.5rem;
+ row-gap: 0.6rem;
+ // .url-title,.url-link{
+ // // 两行省略
+ // display: -webkit-box;
+ // -webkit-line-clamp: 2;
+ // line-clamp: 2;
+ // -webkit-box-orient: vertical;
+ // overflow: hidden;
+ // text-overflow: ellipsis;
+ // }
.url-title {
cursor: pointer;
font-family: 'Medium';
font-size: 1.6rem;
color: #232323;
- padding-bottom: 0.6rem;
+ max-height: 4rem;
.link-outer {
width: 1.2rem;
height: 1.2rem;
diff --git a/src/views/home/agent/index.vue b/src/views/home/agent/index.vue
index bb46454..8ce3efe 100644
--- a/src/views/home/agent/index.vue
+++ b/src/views/home/agent/index.vue
@@ -87,7 +87,8 @@
)
}
- const handleGetProjectInfoAndHistory = () => {
+const handleGetProjectInfoAndHistory = () => {
+ handleOpenSketch()
getProjectInfo({ id: route.params.id }).then((res) => {
if (res) agentRef.value.setChatInfo(res)
let data = res?.project || res