矢量图制图实现的功能组态矢量图编辑器功能工具箱左侧面板矩形工具绘制矩形图元圆形工具绘制圆形图元通过椭圆实现椭圆工具绘制椭圆图元直线工具绘制直线段属性设置面板填充开关启用/禁用填充功能填充色选择6种颜色绿、红、蓝、橙、紫、白边框色选择6种颜色灰、红、蓝、橙、黑、白线宽调节滑块控制1-10像素画布区域右侧触摸拖动绘制图元实时预览绘制过程点击选中图元显示橙色虚线边框支持多种颜色和线宽设置操作按钮删除选中删除当前选中的图元清空画布清除所有图元状态栏显示图元总数显示当前选中的图元ID主要代码结构ShapeType枚举定义4种图元类型ShapeItem接口图元数据结构handleCanvasTouch处理触摸事件实现绘制逻辑RenderShape渲染已绘制的图元RenderPreview渲染绘制预览enum ShapeType { Rectangle, Circle, Ellipse, Line } interface Point { x: number; y: number; } interface ShapeItem { id: number; type: ShapeType; x: number; y: number; width: number; height: number; fillColor: string; strokeColor: string; strokeWidth: number; points?: ArrayPoint; } Entry Component struct Index { State shapes: ShapeItem[] []; State selectedTool: ShapeType ShapeType.Rectangle; State selectedShapeId: number -1; State fillColor: string #4CAF50; State strokeColor: string #333333; State strokeWidth: number 2; State isDrawing: boolean false; State startX: number 0; State startY: number 0; State currentX: number 0; State currentY: number 0; State nextId: number 1; State fillEnabled: boolean true; private canvasWidth: number 320; private canvasHeight: number 400; build() { Column() { Text(组态矢量图编辑器) .fontSize(24) .fontWeight(600) .textAlign(TextAlign.Center) .width(100%) .padding(15) .backgroundColor(#2196F3) .fontColor(#FFFFFF); Row() { Column() { Text(工具箱) .fontSize(16) .fontWeight(600) .margin({ bottom: 10 }); Column({ space: 8 }) { this.ToolButton(矩形, ShapeType.Rectangle); this.ToolButton(圆形, ShapeType.Circle); this.ToolButton(椭圆, ShapeType.Ellipse); this.ToolButton(直线, ShapeType.Line); } .padding(10) .backgroundColor(#f5f5f5) .borderRadius(8); Divider().margin({ top: 15, bottom: 15 }); Text(属性设置) .fontSize(16) .fontWeight(600) .margin({ bottom: 10 }); Column({ space: 10 }) { Row() { Text(填充:).width(60); Toggle({ type: ToggleType.Checkbox, isOn: this.fillEnabled }) .onChange((isOn: boolean) { this.fillEnabled isOn; }); } Row() { Text(填充色:).width(60); Column() { Row({ space: 4 }) { ForEach([#4CAF50, #F44336, #2196F3, #FF9800, #9C27B0, #FFFFFF], (color: string) { Circle() .size({ width: 20, height: 20 }) .fill(color) .strokeWidth(1) .stroke(color #FFFFFF ? #ccc : color) .onClick(() { this.fillColor color; }); }); } } } Row() { Text(边框色:).width(60); Column() { Row({ space: 4 }) { ForEach([#333333, #F44336, #2196F3, #FF9800, #000000, #FFFFFF], (color: string) { Circle() .size({ width: 20, height: 20 }) .fill(color) .strokeWidth(1) .stroke(color #FFFFFF ? #ccc : color) .onClick(() { this.strokeColor color; }); }); } } } Row() { Text(线宽:).width(60); Slider({ value: this.strokeWidth, min: 1, max: 10, step: 1 }) .onChange((value: number) { this.strokeWidth value; }) .width(120); Text(String(this.strokeWidth)).width(30); } } .padding(10) .backgroundColor(#f5f5f5) .borderRadius(8); Divider().margin({ top: 15, bottom: 15 }); Column({ space: 8 }) { Button(删除选中) .width(100%) .onClick(() { this.deleteSelected(); }); Button(清空画布) .width(100%) .backgroundColor(#F44336) .onClick(() { this.shapes []; this.selectedShapeId -1; }); } } .width(35%) .padding(10) .backgroundColor(#ffffff) .height(100%); Column() { Text(画布区域 (点击拖动绘制图元)) .fontSize(14) .margin({ bottom: 10 }); Stack() { Rect() .width(100%) .height(100%) .fill(#ffffff) .stroke(#cccccc) .strokeWidth(1); ForEach(this.shapes, (shape: ShapeItem) { this.RenderShape(shape); }); if (this.isDrawing) { this.RenderPreview(); } } .width(100%) .height(100%) .backgroundColor(#ffffff) .borderWidth(1) .borderColor(#cccccc) .borderRadius(4) .onTouch((event: TouchEvent) { this.handleCanvasTouch(event); }); } .width(65%) .padding(10) .height(100%); } .width(100%) .layoutWeight(1); Text(图元数量: ${this.shapes.length} | 选中: ${this.selectedShapeId 0 ? ID this.selectedShapeId : 无}) .fontSize(12) .textAlign(TextAlign.Center) .width(100%) .padding(8) .backgroundColor(#e0e0e0); } .width(100%) .height(100%) .backgroundColor(#f0f0f0); } Builder ToolButton(text: string, toolType: ShapeType) { Button(text) .width(100%) .backgroundColor(this.selectedTool toolType ? #2196F3 : #e0e0e0) .fontColor(this.selectedTool toolType ? #ffffff : #333333) .onClick(() { this.selectedTool toolType; this.selectedShapeId -1; }); } Builder RenderShape(shape: ShapeItem) { Stack() { if (shape.type ShapeType.Rectangle) { Rect() .width(shape.width) .height(shape.height) .fill(this.fillEnabled ? shape.fillColor : transparent) .stroke(shape.strokeColor) .strokeWidth(shape.strokeWidth) .position({ x: shape.x, y: shape.y }) .onClick(() { this.selectedShapeId shape.id; }); } else if (shape.type ShapeType.Circle) { Circle() .size({ width: Math.abs(shape.width), height: Math.abs(shape.height) }) .fill(this.fillEnabled ? shape.fillColor : transparent) .stroke(shape.strokeColor) .strokeWidth(shape.strokeWidth) .position({ x: shape.x, y: shape.y }) .onClick(() { this.selectedShapeId shape.id; }); } else if (shape.type ShapeType.Ellipse) { Ellipse() .size({ width: Math.abs(shape.width), height: Math.abs(shape.height) }) .fill(this.fillEnabled ? shape.fillColor : transparent) .stroke(shape.strokeColor) .strokeWidth(shape.strokeWidth) .position({ x: shape.x, y: shape.y }) .onClick(() { this.selectedShapeId shape.id; }); } else if (shape.type ShapeType.Line shape.points) { Path({ commands: M shape.points[0].x shape.points[0].y L shape.points[1].x shape.points[1].y }) .stroke(shape.strokeColor) .strokeWidth(shape.strokeWidth) .fill(transparent) .onClick(() { this.selectedShapeId shape.id; }); } if (this.selectedShapeId shape.id) { Rect() .width(shape.width 4) .height(shape.height 4) .fill(transparent) .stroke(#FF9800) .strokeWidth(2) .position({ x: shape.x - 2, y: shape.y - 2 }); } } .width(100%) .height(100%); } Builder RenderPreview() { Stack() { if (this.selectedTool ShapeType.Rectangle) { Rect() .width(Math.abs(this.currentX - this.startX)) .height(Math.abs(this.currentY - this.startY)) .fill(this.fillEnabled ? this.fillColor : transparent) .stroke(this.strokeColor) .strokeWidth(this.strokeWidth) .position({ x: (this.currentX - this.startX) 0 ? this.startX : this.currentX, y: (this.currentY - this.startY) 0 ? this.startY : this.currentY }); } else if (this.selectedTool ShapeType.Circle) { Circle() .size({ width: Math.abs(this.currentX - this.startX), height: Math.abs(this.currentY - this.startY) }) .fill(this.fillEnabled ? this.fillColor : transparent) .stroke(this.strokeColor) .strokeWidth(this.strokeWidth) .position({ x: (this.currentX - this.startX) 0 ? this.startX : this.currentX, y: (this.currentY - this.startY) 0 ? this.startY : this.currentY }); } else if (this.selectedTool ShapeType.Ellipse) { Ellipse() .size({ width: Math.abs(this.currentX - this.startX), height: Math.abs(this.currentY - this.startY) }) .fill(this.fillEnabled ? this.fillColor : transparent) .stroke(this.strokeColor) .strokeWidth(this.strokeWidth) .position({ x: (this.currentX - this.startX) 0 ? this.startX : this.currentX, y: (this.currentY - this.startY) 0 ? this.startY : this.currentY }); } else if (this.selectedTool ShapeType.Line) { Path({ commands: M this.startX this.startY L this.currentX this.currentY }) .stroke(this.strokeColor) .strokeWidth(this.strokeWidth) .fill(transparent); } } .width(100%) .height(100%); } handleCanvasTouch(event: TouchEvent) { if (event.type TouchType.Down) { this.isDrawing true; this.startX event.touches[0].x; this.startY event.touches[0].y; this.currentX this.startX; this.currentY this.startY; this.selectedShapeId -1; } else if (event.type TouchType.Move) { this.currentX event.touches[0].x; this.currentY event.touches[0].y; } else if (event.type TouchType.Up) { this.isDrawing false; this.currentX event.touches[0].x; this.currentY event.touches[0].y; this.addShape(); } } addShape() { let w this.currentX - this.startX; let h this.currentY - this.startY; if (Math.abs(w) 5 Math.abs(h) 5) { return; } let newShape: ShapeItem { id: this.nextId, type: this.selectedTool, x: w 0 ? this.startX : this.currentX, y: h 0 ? this.startY : this.currentY, width: w, height: h, fillColor: this.fillColor, strokeColor: this.strokeColor, strokeWidth: this.strokeWidth }; if (this.selectedTool ShapeType.Line) { let pointArr: ArrayPoint new Array(); pointArr.push({ x: this.startX, y: this.startY }); pointArr.push({ x: this.currentX, y: this.currentY }); newShape.points pointArr; newShape.x 0; newShape.y 0; } this.shapes.push(newShape); this.selectedShapeId newShape.id; } deleteSelected() { if (this.selectedShapeId 0) { let index this.shapes.findIndex((s: ShapeItem) s.id this.selectedShapeId); if (index 0) { this.shapes.splice(index, 1); this.selectedShapeId -1; } } } }