ooder-A2UI 框架中的矢量图形全面指南

135 阅读20分钟

SVG(可缩放矢量图形)是A2UI框架中用于创建高质量矢量图形的重要组件。本专辑将全面介绍SVGPaper组件的使用、SVG形状类型、连接线系统、样式配置以及实际应用案例。

96187a0e-e827-4529-8583-e4d174bf3d3b.png

📋 目录

  1. SVGPaper 组件概述
  2. 快速入门
  3. SVG 形状类型大全
  4. 连接线系统
  5. 样式与渐变
  6. 实际应用案例
  7. API 参考
  8. 最佳实践
  9. 常见问题

SVGPaper 组件概述

SVGPaper 是 A2UI 框架中专门用于绘制和管理 SVG 矢量图形的组件。它继承自 Div 组件,提供了丰富的图形创建、编辑和交互功能。

核心特性

  • 矢量图形绘制:支持多种预定义形状和自定义路径
  • 流程图支持:专门的流程图形状和连接线系统
  • 交互支持:点击、悬停、拖拽等交互事件
  • 样式配置:丰富的描边、填充、渐变选项
  • 响应式设计:自动适应不同屏幕尺寸
  • 可访问性:ARIA 属性和键盘导航支持

技术架构

SVGPaper 基于以下技术构建:

  • Raphaël SVG 库:轻量级、跨浏览器的 SVG 库
  • A2UI 组件体系:标准的 UI 组件生命周期和事件系统
  • CSS 变量主题:支持主题切换和自定义样式

快速入门

1. 创建 SVG 画布

<!-- 引入核心库和SVGPaper组件 -->
<script type="text/javascript" src="ood/ood.js"></script>
<script type="text/javascript" src="ood/UI/SVGPaper.js"></script>

<!-- 创建画布容器 -->
<div id="svg-container"></div>

<script>
// 创建 SVGPaper 实例
var svgPaper = ood.UI.SVGPaper({
    width: '800px',
    height: '600px',
    scaleChildren: false,
    overflow: undefined,
    graphicZIndex: 0
}).appendTo('#svg-container');

// 画布创建完成,可以开始添加图形
</script>

2. 添加基本形状

// 添加圆形
svgPaper.append(
    ood.create("ood.svg.circle")
    .setHost(svgPaper, "circle1")
    .setSvgTag("Shapes:Circle")
    .setAttr({
        "KEY":{
            "cx": 100,
            "cy": 100,
            "r": 50,
            "fill": "#2196F3",
            "stroke": "#1976D2",
            "stroke-width": 3
        }
    })
);

// 添加矩形
svgPaper.append(
    ood.create("ood.svg.rect")
    .setHost(svgPaper, "rect1")
    .setSvgTag("Shapes:Rect")
    .setAttr({
        "KEY":{
            "x": 200,
            "y": 80,
            "width": 120,
            "height": 80,
            "fill": "90-#4CAF50-#C8E6C9",
            "stroke": "#388E3C",
            "stroke-width": 2
        }
    })
);

3. 添加文本和连接线

// 添加文本
svgPaper.append(
    ood.create("ood.svg.text")
    .setHost(svgPaper, "text1")
    .setSvgTag("Shapes:Text")
    .setAttr({
        "KEY":{
            "x": 150,
            "y": 250,
            "text": "SVG 示例",
            "fill": "#333333",
            "font-size": "20px",
            "font-weight": "bold"
        }
    })
);

// 添加连接线
svgPaper.append(
    ood.create("ood.svg.connector")
    .setHost(svgPaper, "connector1")
    .setSvgTag("Connectors:Straight")
    .setAttr({
        "KEY":{
            "path": "M,100,150L,300,150",
            "fill": "none",
            "stroke": "#666666",
            "stroke-width": 2,
            "arrow-start": "classic-wide-long",
            "arrow-end": "classic-wide-long"
        },
        "BG":{
            "fill": "none",
            "stroke": "#FFFFFF",
            "stroke-width": 4
        }
    })
    .setFromObj("circle1")
    .setFromPoint("bottom")
    .setToObj("rect1")
    .setToPoint("left")
);

SVG 形状类型大全

基础形状

形状ID名称描述关键属性
ood.svg.circle圆形标准圆形cx, cy, r, fill, stroke
ood.svg.ellipse椭圆椭圆形cx, cy, rx, ry
ood.svg.rect矩形矩形x, y, width, height
ood.svg.line直线直线段x1, y1, x2, y2
ood.svg.polygon多边形多边形points
ood.svg.polyline折线折线points

流程图专用形状

SVGPaper 提供了丰富的流程图形状,每个形状都有特定的用途:

流程控制形状

形状类型用途示例
FlowChart:Process处理过程服务器处理
FlowChart:Decision决策判断条件判断
FlowChart:Termination终止点流程结束

数据形状

形状类型用途示例
FlowChart:Data数据数据存储
FlowChart:Document文档报告文档
FlowChart:Database数据库数据库系统

输入输出形状

形状类型用途示例
FlowChart:ManualInput手动输入用户输入
FlowChart:Display显示结果展示

存储形状

形状类型用途示例
FlowChart:StoredData存储数据数据缓存
FlowChart:InternalStorage内部存储内存存储

组合形状

组合形状是A2UI中特殊的SVG元素,将图形和文本组合在一起:

ood.svg.rectComb

矩形组合形状,支持渐变填充和文本:

ood.create("ood.svg.rectComb")
.setAttr({
    "KEY":{
        "x": 40,
        "y": 30,
        "width": 90,
        "height": 50,
        "fill": "90-#5198D3-#A1C8F6",
        "stroke": "#004A7F"
    },
    "TEXT":{
        "text": "服务器",
        "font-size": "12px",
        "fill": "#fff",
        "font-weight": "bold"
    }
})

ood.svg.pathComb

路径组合形状,用于复杂图形:

ood.create("ood.svg.pathComb")
.setAttr({
    "KEY":{
        "fill": "90-#5198D3-#A1C8F6",
        "stroke": "#004A7F",
        "path": "M,319,85C,310.7157314383532,85,304,71.56854048887718,304,55C,304,38.43145548427702,310.7157178477474,25,319,25M,319,85C,319,85,319,85,319,85C,310.7157314383532,85,304,71.56854048887718,304,55C,304,38.43145548427702,310.7157178477474,25,319,25M,319,25C,327.2842655415122,25,334,38.43145548427702,334,55C,334,71.56854048887718,327.2842655415122,85,319,85C,319,85,259,85,259,85C,250.7157118074781,85,244,71.56854048887718,244,55C,244,38.43145548427702,250.7157118074781,25,259,25C,259,25,319,25,319,25"
    },
    "TEXT":{
        "text": "网关",
        "font-size": "12px",
        "fill": "#fff",
        "font-weight": "bold"
    }
})

ood.svg.circleComb

圆形组合形状:

ood.create("ood.svg.circleComb")
.setAttr({
    "KEY":{
        "cx": 504,
        "cy": 55,
        "r": 40,
        "fill": "90-#5198D3-#A1C8F6",
        "stroke": "#004A7F"
    },
    "TEXT":{
        "text": "传感器",
        "font-size": "12px",
        "fill": "#fff",
        "font-weight": "bold"
    }
})

连接线系统

连接线是流程图和图表中连接不同元素的纽带。A2UI 提供了强大的连接线系统,支持自动路径计算和智能连接。

连接线类型

1. 直线连接线 (Connectors:Straight)

最简单的连接线类型,两点之间直接连接:

ood.create("ood.svg.connector")
.setSvgTag("Connectors:Straight")
.setAttr({
    "KEY":{
        "path": "M,100,100L,300,200",
        "fill": "none",
        "stroke": "#228B22",
        "stroke-width": 2,
        "arrow-start": "oval-midium-midium",
        "arrow-end": "classic-wide-long"
    },
    "BG":{
        "fill": "none",
        "stroke": "#FFFFFF",
        "stroke-width": 4
    }
})
.setFromObj("shape1")
.setFromPoint("right")
.setToObj("shape2")
.setToPoint("left")

2. 贝塞尔曲线连接线 (Connectors:Bezier)

平滑的曲线连接,适合避免交叉的情况:

ood.create("ood.svg.connector")
.setSvgTag("Connectors:Bezier")
.setAttr({
    "KEY":{
        "path": "M,100,100C,150,50,250,250,300,200",
        "fill": "none",
        "stroke": "#FF5722",
        "stroke-width": 2
    }
})

3. 流程图连接线 (Connectors:flowchart)

带拐角的连接线,典型的流程图风格:

ood.create("ood.svg.connector")
.setSvgTag("Connectors:flowchart")
.setAttr({
    "KEY":{
        "path": "M,100,100L,200,100L,200,200L,300,200",
        "fill": "none",
        "stroke": "#673AB7",
        "stroke-width": 2
    }
})

连接点系统

连接线可以连接到形状的特定位置:

// 连接到形状的不同位置
connector.setFromObj("serverRect")      // 起始形状
        .setFromPoint("right")          // 从右侧连接
        .setToObj("gatewayPath")        // 目标形状
        .setToPoint("left");            // 连接到左侧

支持的位置:

  • "left":左侧
  • "right":右侧
  • "top":顶部
  • "bottom":底部

箭头样式

连接线支持多种箭头样式:

// 箭头配置示例
"arrow-start": "classic-wide-long"     // 起始箭头
"arrow-end": "oval-midium-midium"      // 结束箭头

箭头类型:

  1. classic:经典箭头
    • classic-narrow-short
    • classic-midium-midium
    • classic-wide-long
  2. oval:椭圆形箭头
    • oval-midium-midium
  3. diamond:菱形箭头
  4. triangle:三角形箭头

样式与渐变

基本样式属性

属性类型描述示例
fillString填充颜色或渐变"#FF0000", "90-#FF0000-#0000FF"
strokeString描边颜色"#333333"
stroke-widthNumber描边宽度2
stroke-opacityNumber描边透明度0.8
fill-opacityNumber填充透明度0.5
opacityNumber整体透明度0.9

渐变填充

A2UI 支持多种渐变类型:

1. 线性渐变

"fill": "90-#5198D3-#A1C8F6"
  • 格式:"角度-起始颜色-结束颜色"
  • 角度:0-360,0°为从上到下,90°为从左到右

2. 径向渐变

"fill": "r-#FF0000-#FFFFFF"
  • 格式:"r-起始颜色-结束颜色"

3. 多色渐变

"fill": "90-#FF0000-#00FF00-#0000FF"
  • 支持多个颜色节点

样式应用示例

// 渐变矩形
var gradientRect = ood.create("ood.svg.rectComb")
.setAttr({
    "KEY":{
        "x": 100,
        "y": 100,
        "width": 200,
        "height": 100,
        "fill": "45-#FF6B6B-#4ECDC4",  // 45°线性渐变
        "stroke": "#2D3436",
        "stroke-width": 3,
        "stroke-dasharray": "5,5",      // 虚线描边
        "rx": 10,                       // 圆角半径
        "ry": 10
    },
    "TEXT":{
        "text": "渐变样式示例",
        "font-size": "16px",
        "fill": "#FFFFFF",
        "font-weight": "bold",
        "text-anchor": "middle",
        "dy": "0.35em"                  // 垂直居中调整
    }
});

// 添加阴影效果
gradientRect.on("mouseover", function() {
    this.attr({
        "filter": "url(#shadow)"        // SVG滤镜阴影
    });
});

gradientRect.on("mouseout", function() {
    this.attr({
        "filter": "none"
    });
});

实际应用案例

案例1:物联网系统架构图

基于用户提供的示例,创建一个完整的物联网系统架构图:

// 创建物联网系统架构图
function createIoTSystemDiagram(containerId) {
    var svgPaper = ood.UI.SVGPaper({
        width: '800px',
        height: '500px',
        scaleChildren: false
    }).appendTo(containerId);
    
    // 1. 云服务器
    svgPaper.append(
        ood.create("ood.svg.rectComb")
        .setHost(svgPaper, "cloudServer")
        .setSvgTag("FlowChart:Process")
        .setAttr({
            "KEY":{
                "x": 50,
                "y": 200,
                "width": 120,
                "height": 80,
                "fill": "90-#4285F4-#8AB4F8",
                "stroke": "#1A73E8"
            },
            "TEXT":{
                "text": "云服务器",
                "font-size": "14px",
                "fill": "#FFFFFF",
                "font-weight": "bold"
            }
        })
    );
    
    // 2. 网关设备
    svgPaper.append(
        ood.create("ood.svg.pathComb")
        .setHost(svgPaper, "gateway")
        .setSvgTag("FlowChart:DirectData")
        .setAttr({
            "KEY":{
                "fill": "90-#34A853-#81C995",
                "stroke": "#1E8E3E",
                "path": "M,250,200C,240,200,230,180,230,160C,230,140,240,120,250,120C,250,120,350,120,350,120C,358,120,360,140,360,160C,360,180,358,200,350,200C,350,200,250,200,250,200"
            },
            "TEXT":{
                "text": "智能网关",
                "font-size": "14px",
                "fill": "#FFFFFF",
                "font-weight": "bold"
            }
        })
    );
    
    // 3. 传感器节点
    svgPaper.append(
        ood.create("ood.svg.circleComb")
        .setHost(svgPaper, "sensor")
        .setSvgTag("FlowChart:OnPageRefrence")
        .setAttr({
            "KEY":{
                "cx": 550,
                "cy": 160,
                "r": 60,
                "fill": "r-#FBBC05-#FDE293",
                "stroke": "#F9AB00"
            },
            "TEXT":{
                "text": "温湿度传感器",
                "font-size": "12px",
                "fill": "#333333",
                "font-weight": "bold"
            }
        })
    );
    
    // 4. 连接线
    svgPaper.append(
        ood.create("ood.svg.connector")
        .setHost(svgPaper, "conn1")
        .setSvgTag("Connectors:Straight")
        .setAttr({
            "KEY":{
                "path": "M,170,240L,230,240",
                "fill": "none",
                "stroke": "#666666",
                "stroke-width": 2,
                "arrow-end": "classic-wide-long"
            }
        })
        .setFromObj("cloudServer")
        .setFromPoint("right")
        .setToObj("gateway")
        .setToPoint("left")
    );
    
    svgPaper.append(
        ood.create("ood.svg.connector")
        .setHost(svgPaper, "conn2")
        .setSvgTag("Connectors:Straight")
        .setAttr({
            "KEY":{
                "path": "M,350,240L,490,240",
                "fill": "none",
                "stroke": "#666666",
                "stroke-width": 2,
                "arrow-end": "classic-wide-long"
            }
        })
        .setFromObj("gateway")
        .setFromPoint("right")
        .setToObj("sensor")
        .setToPoint("left")
    );
    
    return svgPaper;
}

// 使用示例
var iotDiagram = createIoTSystemDiagram("#diagram-container");

案例2:业务流程管理图

// 创建订单处理流程图
function createOrderProcessDiagram(containerId) {
    var svgPaper = ood.UI.SVGPaper({
        width: '1000px',
        height: '600px'
    }).appendTo(containerId);
    
    var shapes = [];
    
    // 订单接收
    shapes.push(svgPaper.append(
        ood.create("ood.svg.rectComb")
        .setHost(svgPaper, "orderReceive")
        .setSvgTag("FlowChart:Process")
        .setAttr({
            "KEY":{
                "x": 100,
                "y": 100,
                "width": 150,
                "height": 60,
                "fill": "90-#2196F3-#64B5F6",
                "stroke": "#1976D2"
            },
            "TEXT":{
                "text": "订单接收",
                "font-size": "14px",
                "fill": "#FFFFFF"
            }
        })
    ));
    
    // 库存检查(决策)
    shapes.push(svgPaper.append(
        ood.create("ood.svg.pathComb")
        .setHost(svgPaper, "inventoryCheck")
        .setSvgTag("FlowChart:Decision")
        .setAttr({
            "KEY":{
                "fill": "90-#FF9800-#FFB74D",
                "stroke": "#F57C00",
                "path": "M,300,100L,400,160L,300,220L,200,160Z"
            },
            "TEXT":{
                "text": "库存检查",
                "font-size": "12px",
                "fill": "#FFFFFF"
            }
        })
    ));
    
    // 更多流程节点...
    
    // 连接所有节点
    for (var i = 0; i < shapes.length - 1; i++) {
        svgPaper.append(
            ood.create("ood.svg.connector")
            .setSvgTag("Connectors:Straight")
            .setAttr({
                "KEY":{
                    "path": "M," + (shapes[i].getBBox().x + shapes[i].getBBox().width) + "," + (shapes[i].getBBox().y + shapes[i].getBBox().height/2) + 
                           "L," + (shapes[i+1].getBBox().x) + "," + (shapes[i+1].getBBox().y + shapes[i+1].getBBox().height/2),
                    "fill": "none",
                    "stroke": "#666666",
                    "stroke-width": 2,
                    "arrow-end": "classic-wide-long"
                }
            })
            .setFromObj(shapes[i].alias)
            .setFromPoint("right")
            .setToObj(shapes[i+1].alias)
            .setToPoint("left")
        );
    }
    
    return svgPaper;
}

案例3:组织结构图

// 创建公司组织结构图
function createOrgChart(containerId, orgData) {
    var svgPaper = ood.UI.SVGPaper({
        width: '1200px',
        height: '800px'
    }).appendTo(containerId);
    
    // 按层级布局节点
    var levelPositions = {};
    
    // 遍历组织数据,创建节点
    orgData.forEach(function(dept, index) {
        var level = dept.level || 0;
        var position = levelPositions[level] || {x: 100, y: 100 + level * 150};
        
        var shape = ood.create("ood.svg.rectComb")
            .setHost(svgPaper, "dept_" + dept.id)
            .setSvgTag("FlowChart:Document")
            .setAttr({
                "KEY":{
                    "x": position.x,
                    "y": position.y,
                    "width": 180,
                    "height": 80,
                    "fill": getDeptColor(dept.type),
                    "stroke": "#333333",
                    "rx": 8,
                    "ry": 8
                },
                "TEXT":{
                    "text": dept.name + "\n" + (dept.manager || ""),
                    "font-size": "12px",
                    "fill": "#FFFFFF",
                    "text-anchor": "middle"
                }
            });
            
        svgPaper.append(shape);
        
        // 更新位置
        levelPositions[level] = {
            x: position.x + 220,
            y: position.y
        };
        
        // 连接到上级部门
        if (dept.parentId) {
            svgPaper.append(
                ood.create("ood.svg.connector")
                .setSvgTag("Connectors:Straight")
                .setAttr({
                    "KEY":{
                        "path": calculateOrgPath(dept.parentId, dept.id),
                        "fill": "none",
                        "stroke": "#999999",
                        "stroke-width": 2
                    }
                })
                .setFromObj("dept_" + dept.parentId)
                .setFromPoint("bottom")
                .setToObj("dept_" + dept.id)
                .setToPoint("top")
            );
        }
    });
    
    return svgPaper;
}

// 辅助函数
function getDeptColor(deptType) {
    var colors = {
        "executive": "90-#D32F2F-#F44336",
        "management": "90-#1976D2-#2196F3", 
        "technical": "90-#388E3C-#4CAF50",
        "support": "90-#F57C00-#FF9800"
    };
    return colors[deptType] || "90-#607D8B-#90A4AE";
}

原始示例代码深度分析

以下是您提供的原始物联网系统流程图代码的详细分析,展示了A2UI中SVG的核心用法:

代码结构解析

// 1. 创建SVG画布并添加到FormLayout中
host.xui_ui_formlayout1.append(
    ood.create("ood.UI.SVGPaper")
    .setHost(host,"xui_ui_svgpaper7")
    .setLeft("0em")
    .setTop("0em")
    .setWidth("61.416666666666664em")
    .setHeight("9.333333333333334em"),
    "A1"
);

关键点:

  • ood.create("ood.UI.SVGPaper"):创建SVGPaper组件实例
  • .setHost(host,"xui_ui_svgpaper7"):设置宿主和唯一标识符
  • .setWidth()/.setHeight():使用em单位实现响应式设计
  • "A1":布局位置标识符

2. 创建流程图节点

// 服务器节点(矩形)
host.xui_ui_svgpaper7.append(
    ood.create("ood.svg.rectComb")
    .setHost(host,"xui_svg_rectcomb1")
    .setSvgTag("FlowChart:Process")
    .setAttr({
        "KEY":{
            "x":40,
            "y":30,
            "width":90,
            "height":50,
            "fill":"90-#5198D3-#A1C8F6",
            "stroke":"#004A7F"
        },
        "TEXT":{
            "text":"服务器",
            "font-size":"12px",
            "fill":"#fff",
            "font-weight":"bold"
        }
    })
);

技术细节:

  • ood.svg.rectComb:矩形组合形状类
  • FlowChart:Process:流程图处理节点类型
  • 渐变填充:"90-#5198D3-#A1C8F6"(90°线性渐变)
  • 文本配置:白色粗体,12px大小

3. 创建网关节点(路径形状)

host.xui_ui_svgpaper7.append(
    ood.create("ood.svg.pathComb")
    .setHost(host,"xui_svg_pathcomb49")
    .setSvgTag("FlowChart:DirectData")
    .setAttr({
        "KEY":{
            "fill":"90-#5198D3-#A1C8F6",
            "stroke":"#004A7F",
            "path":"M,319,85C,310.7157314383532,85,304,71.56854048887718,304,55C,304,38.43145548427702,310.7157178477474,25,319,25M,319,85C,319,85,319,85,319,85C,310.7157314383532,85,304,71.56854048887718,304,55C,304,38.43145548427702,310.7157178477474,25,319,25M,319,25C,319,25,319,25,319,25C,327.2842655415122,25,334,38.43145548427702,334,55C,334,71.56854048887718,327.2842655415122,85,319,85C,319,85,259,85,259,85C,250.7157118074781,85,244,71.56854048887718,244,55C,244,38.43145548427702,250.7157118074781,25,259,25C,259,25,319,25,319,25"
        },
        "TEXT":{
            "text":"网关",
            "font-size":"12px",
            "fill":"#fff",
            "font-weight":"bold"
        }
    })
);

路径语法解析:

  • M:移动到起点 (319,85)
  • C:三次贝塞尔曲线到目标点
  • 控制点计算确保平滑过渡
  • 复杂路径实现专业的流程图符号

4. 传感器节点(圆形)

host.xui_ui_svgpaper7.append(
    ood.create("ood.svg.circleComb")
    .setHost(host,"xui_svg_circlecomb1")
    .setSvgTag("FlowChart:OnPageRefrence")
    .setAttr({
        "KEY":{
            "cx":504,
            "cy":55,
            "r":40,
            "fill":"90-#5198D3-#A1C8F6",
            "stroke":"#004A7F"
        },
        "TEXT":{
            "text":"传感器",
            "font-size":"12px",
            "fill":"#fff",
            "font-weight":"bold"
        }
    })
);

圆形属性:

  • cx, cy:圆心坐标,精确定位
  • r:半径大小
  • FlowChart:OnPageRefrence:页面引用类型

5. 智能连接线系统

// 服务器 → 网关连接线
host.xui_ui_svgpaper7.append(
    ood.create("ood.svg.connector")
    .setHost(host,"xui_svg_connector19")
    .setSvgTag("Connectors:Straight")
    .setAttr({
        "KEY":{
            "path":"M,130,55L,244,55",
            "fill":"#B6E026",
            "stroke":"#228B22",
            "stroke-width":2,
            "arrow-start":"oval-midium-midium",
            "arrow-end":"classic-wide-long"
        },
        "BG":{
            "fill":"none",
            "stroke":"#fff",
            "stroke-width":4
        }
    })
    .setFromObj("xui_svg_rectcomb1")
    .setFromPoint("right")
    .setToObj("xui_svg_pathcomb49")
    .setToPoint("left")
);

连接线高级特性:

  • 双箭头系统:起始箭头+结束箭头
  • BG层:白色背景描边,增强可读性
  • 自动路径计算:基于形状位置
  • 智能连接点:rightleft 自然流向

设计模式总结

  1. 分层架构

    • SVGPaper(画布层)
    • 形状组合(图形层)
    • 连接线系统(关系层)
    • 文本标注(信息层)
  2. 样式系统

    • 一致性:相同渐变和描边
    • 可读性:对比色和适当大小
    • 专业性:标准流程图符号
  3. 交互设计

    • 逻辑连接:服务器→网关→传感器
    • 视觉引导:箭头方向和路径
    • 信息层次:标题和位置

扩展建议

  1. 动态数据绑定:将节点数据与后端API连接
  2. 交互增强:添加拖拽、缩放、选择功能
  3. 主题系统:支持暗色/亮色主题切换
  4. 导出功能:支持PNG、PDF、SVG格式导出

这个示例展示了A2UI SVG系统的强大功能,从基础形状创建到复杂的流程图构建,为各种数据可视化和图表应用提供了完整的解决方案。

API 参考

SVGPaper 类

构造函数

new ood.UI.SVGPaper(config)

配置选项

属性类型默认值描述
widthString/Object'32em'画布宽度
heightString/Object'25em'画布高度
scaleChildrenBooleanfalse是否缩放子元素
overflowStringundefined溢出处理
graphicZIndexNumber0图形层级

实例方法

append(shape)

添加SVG形状到画布。

参数:

  • shape (Object): SVG形状对象

返回:

  • (Object): SVGPaper实例
removeChildren()

移除所有子元素。

返回:

  • (Object): SVGPaper实例
getPaper()

获取底层的Raphaël paper对象。

返回:

  • (Object): Raphaël paper实例
getSVGString()

获取SVG内容的字符串表示。

返回:

  • (String): SVG字符串
setChildren(shapes)

替换所有子元素。

参数:

  • shapes (Array): 形状对象数组

返回:

  • (Object): SVGPaper实例

形状创建 API

ood.create(type)

创建指定类型的SVG形状。

参数:

  • type (String): 形状类型标识符

返回:

  • (Object): 形状实例

常用形状类型

  • "ood.svg.circle":圆形
  • "ood.svg.rect":矩形
  • "ood.svg.rectComb":矩形组合
  • "ood.svg.pathComb":路径组合
  • "ood.svg.circleComb":圆形组合
  • "ood.svg.connector":连接线

形状配置方法

setHost(host, alias)

设置宿主和别名。

参数:

  • host (Object): 宿主对象
  • alias (String): 形状别名

返回:

  • (Object): 形状实例

setSvgTag(tag)

设置SVG标签类型。

参数:

  • tag (String): SVG标签标识符

返回:

  • (Object): 形状实例

setAttr(attributes)

设置形状属性。

参数:

  • attributes (Object): 属性对象

返回:

  • (Object): 形状实例

连接线配置方法

setFromObj(objAlias)

设置起始形状。

参数:

  • objAlias (String): 起始形状别名

返回:

  • (Object): 连接线实例

setFromPoint(point)

设置起始连接点。

参数:

  • point (String): 连接点位置(left/right/top/bottom)

返回:

  • (Object): 连接线实例

setToObj(objAlias)

设置目标形状。

参数:

  • objAlias (String): 目标形状别名

返回:

  • (Object): 连接线实例

setToPoint(point)

设置目标连接点。

参数:

  • point (String): 连接点位置(left/right/top/bottom)

返回:

  • (Object): 连接线实例

最佳实践

1. 性能优化

批量操作:

// 不推荐:单独添加每个形状
shapes.forEach(function(shape) {
    svgPaper.append(shape);
});

// 推荐:批量添加
svgPaper.setChildren(shapes);

图形复用:

// 创建模板形状
var templateShape = ood.create("ood.svg.rectComb")
    .setAttr({ /* 基础配置 */ });

// 批量创建相似形状
var shapes = data.map(function(item, index) {
    return templateShape.clone()
        .setHost(svgPaper, "shape_" + index)
        .setAttr({
            "KEY":{
                "x": index * 120,
                "y": 100
            },
            "TEXT":{
                "text": item.name
            }
        });
});

2. 可维护性

模块化设计:

// 形状工厂
var ShapeFactory = {
    createServerNode: function(x, y, name) {
        return ood.create("ood.svg.rectComb")
            .setSvgTag("FlowChart:Process")
            .setAttr({
                "KEY":{
                    "x": x,
                    "y": y,
                    "width": 120,
                    "height": 60,
                    "fill": "90-#4285F4-#8AB4F8"
                },
                "TEXT":{
                    "text": name,
                    "fill": "#FFFFFF"
                }
            });
    },
    
    createDecisionNode: function(x, y, name) {
        return ood.create("ood.svg.pathComb")
            .setSvgTag("FlowChart:Decision")
            .setAttr({ /* 配置 */ });
    }
};

配置集中管理:

// 样式配置
var StyleConfig = {
    colors: {
        primary: "90-#4285F4-#8AB4F8",
        success: "90-#34A853-#81C995",
        warning: "90-#FBBC05-#FDE293",
        danger: "90-#EA4335-#F28B82"
    },
    
    sizes: {
        node: { width: 120, height: 60 },
        text: { fontSize: "14px" }
    }
};

3. 响应式设计

// 响应式布局调整
function adjustDiagramLayout(svgPaper, viewportWidth) {
    var scale = 1;
    
    if (viewportWidth < 768) {
        scale = 0.8;
    } else if (viewportWidth < 480) {
        scale = 0.6;
    }
    
    // 缩放所有形状
    svgPaper.each(function(shape) {
        shape.attr({
            "transform": "scale(" + scale + ")"
        });
    });
}

// 监听窗口大小变化
window.addEventListener('resize', function() {
    adjustDiagramLayout(svgPaper, window.innerWidth);
});

4. 可访问性

// 增强可访问性
function enhanceAccessibility(svgPaper) {
    svgPaper.attr({
        "role": "img",
        "aria-label": "系统架构图"
    });
    
    // 为每个形状添加描述
    svgPaper.each(function(shape) {
        var text = shape.getAttr("TEXT")?.text || "图形元素";
        shape.attr({
            "aria-label": text,
            "tabindex": "0"  // 支持键盘导航
        });
    });
}

5. 事件处理最佳实践

事件委托模式

// 为整个画布添加事件委托,而不是为每个形状单独绑定
svgPaper.on("click", ".node-shape", function(event) {
    var shape = event.target;
    console.log("节点被点击:", shape.alias);
    
    // 高亮显示被点击的节点
    shape.attr({
        "stroke": "#FF5722",
        "stroke-width": 3
    });
});

// 添加鼠标悬停效果
svgPaper.on("mouseover", ".node-shape", function(event) {
    event.target.attr({
        "cursor": "pointer",
        "filter": "url(#hover-shadow)"
    });
});

svgPaper.on("mouseout", ".node-shape", function(event) {
    event.target.attr({
        "filter": "none"
    });
});

自定义事件系统

// 创建自定义事件触发器
function createInteractiveShape(svgPaper, config) {
    var shape = ood.create(config.type)
        .setHost(svgPaper, config.alias)
        .setAttr(config.attr);
    
    // 添加自定义事件
    shape.on("custom:select", function() {
        this.attr({
            "fill": "#FFEB3B",
            "stroke": "#FF9800"
        });
    });
    
    shape.on("custom:deselect", function() {
        this.attr({
            "fill": config.attr.KEY.fill,
            "stroke": config.attr.KEY.stroke
        });
    });
    
    return shape;
}

6. 动画效果应用

平滑过渡动画

// 创建形状移动动画
function animateShapeMove(shape, targetX, targetY, duration) {
    var currentX = shape.attr("x") || shape.attr("cx");
    var currentY = shape.attr("y") || shape.attr("cy");
    
    shape.animate({
        "x": targetX,
        "y": targetY
    }, duration, "linear", function() {
        console.log("动画完成");
    });
}

// 创建连接线流动效果
function createFlowAnimation(connector) {
    var path = connector.attr("path");
    var length = connector.getTotalLength();
    
    // 创建虚线流动效果
    connector.attr({
        "stroke-dasharray": "10,5",
        "stroke-dashoffset": length
    });
    
    connector.animate({
        "stroke-dashoffset": 0
    }, 2000, "linear", function() {
        // 循环动画
        connector.attr({
            "stroke-dashoffset": length
        });
        createFlowAnimation(connector);
    });
}

交互反馈动画

// 点击脉冲效果
function createPulseEffect(shape) {
    shape.on("click", function() {
        var originalStroke = shape.attr("stroke-width");
        
        // 脉冲动画
        shape.animate({
            "stroke-width": originalStroke * 3
        }, 200, ">", function() {
            shape.animate({
                "stroke-width": originalStroke
            }, 300);
        });
    });
}

// 悬停缩放效果
function createHoverScale(shape) {
    shape.on("mouseover", function() {
        shape.animate({
            "transform": "s1.1"
        }, 200);
    });
    
    shape.on("mouseout", function() {
        shape.animate({
            "transform": "s1"
        }, 200);
    });
}

7. 与其他A2UI组件集成

与MDialog集成创建图形编辑器

function createSVGEditorDialog() {
    var dialog = ood.create("ood.UI.MDialog")
        .setTitle("SVG 图形编辑器")
        .setWidth("800px")
        .setHeight("600px");
    
    // 在对话框中添加SVGPaper
    var svgPaper = ood.create("ood.UI.SVGPaper")
        .setWidth("100%")
        .setHeight("100%");
    
    dialog.append(svgPaper);
    
    // 添加工具栏
    var toolbar = ood.create("ood.UI.ToolBar")
        .addButton("矩形", function() {
            // 创建矩形形状
            svgPaper.append(createRectShape());
        })
        .addButton("圆形", function() {
            // 创建圆形形状
            svgPaper.append(createCircleShape());
        });
    
    dialog.append(toolbar);
    
    return dialog;
}

与MFormLayout集成创建属性编辑器

function createShapePropertyEditor(shape) {
    var form = ood.create("ood.UI.MFormLayout")
        .setLabelWidth("100px");
    
    // 添加形状属性编辑控件
    form.addItem("x", "位置X", {
        type: "textbox",
        value: shape.attr("x") || shape.attr("cx"),
        onValueChange: function(value) {
            shape.attr("x", parseInt(value));
        }
    });
    
    form.addItem("y", "位置Y", {
        type: "textbox",
        value: shape.attr("y") || shape.attr("cy"),
        onValueChange: function(value) {
            shape.attr("y", parseInt(value));
        }
    });
    
    form.addItem("fill", "填充颜色", {
        type: "colorpicker",
        value: shape.attr("fill"),
        onValueChange: function(value) {
            shape.attr("fill", value);
        }
    });
    
    return form;
}

8. 数据可视化最佳实践

数据绑定模式

function createDataVisualization(svgPaper, data) {
    var maxValue = Math.max.apply(null, data.map(d => d.value));
    var barWidth = 40;
    var spacing = 20;
    
    data.forEach(function(item, index) {
        var barHeight = (item.value / maxValue) * 300;
        var x = index * (barWidth + spacing) + 50;
        var y = 350 - barHeight;
        
        // 创建数据柱状图
        var bar = ood.create("ood.svg.rectComb")
            .setHost(svgPaper, "bar_" + index)
            .setAttr({
                "KEY":{
                    "x": x,
                    "y": y,
                    "width": barWidth,
                    "height": barHeight,
                    "fill": getColorByValue(item.value)
                },
                "TEXT":{
                    "text": item.label,
                    "x": x + barWidth/2,
                    "y": 370,
                    "text-anchor": "middle",
                    "font-size": "12px"
                }
            });
        
        // 添加数值标签
        var valueText = ood.create("ood.svg.text")
            .setHost(svgPaper, "value_" + index)
            .setAttr({
                "KEY":{
                    "x": x + barWidth/2,
                    "y": y - 10,
                    "text": item.value,
                    "text-anchor": "middle",
                    "font-size": "11px",
                    "fill": "#333"
                }
            });
        
        svgPaper.append(bar);
        svgPaper.append(valueText);
    });
}

function getColorByValue(value) {
    if (value > 80) return "90-#FF5252-#FF8A80";
    if (value > 60) return "90-#FF9800-#FFCC80";
    if (value > 40) return "90-#4CAF50-#A5D6A7";
    return "90-#2196F3-#90CAF9";
}

实时数据更新

// 实时更新数据可视化
function updateDataVisualization(svgPaper, newData) {
    // 平滑过渡更新
    newData.forEach(function(item, index) {
        var bar = svgPaper.getChild("bar_" + index);
        if (bar) {
            // 计算新的柱状图高度
            var maxValue = Math.max.apply(null, newData.map(d => d.value));
            var barHeight = (item.value / maxValue) * 300;
            var y = 350 - barHeight;
            
            // 动画更新
            bar.animate({
                "height": barHeight,
                "y": y
            }, 500);
            
            // 更新数值标签
            var valueText = svgPaper.getChild("value_" + index);
            if (valueText) {
                valueText.animate({
                    "y": y - 10
                }, 500);
                
                valueText.attr({
                    "text": item.value
                });
            }
        }
    });
}

常见问题

1. 图形不显示

可能原因:

  • 画布尺寸未正确设置
  • 形状坐标超出画布范围
  • 样式配置错误

解决方案:

// 检查画布配置
console.log('画布尺寸:', svgPaper.width(), svgPaper.height());

// 检查形状坐标
shape.attr({
    "fill": "#FF0000",  // 使用简单颜色测试
    "stroke": "#000000"
});

2. 连接线不连接

可能原因:

  • 形状别名不正确
  • 连接点位置无效
  • 路径计算错误

解决方案:

// 验证形状别名
console.log('起始形状别名:', connector.properties.fromObj);
console.log('目标形状别名:', connector.properties.toObj);

// 检查连接点
console.log('连接点位置:', {
    from: connector.properties.fromPoint,
    to: connector.properties.toPoint
});

3. 渐变效果不显示

可能原因:

  • 渐变格式不正确
  • 浏览器不支持
  • 颜色值格式错误

解决方案:

// 使用标准颜色测试
shape.attr({
    "fill": "#FF0000"  // 替换渐变测试
});

// 检查渐变格式
var gradient = "90-#FF0000-#0000FF";
console.log('渐变格式:', gradient.split('-'));

4. 交互事件不触发

可能原因:

  • 事件绑定时机不对
  • 事件名不正确
  • 形状层级问题

解决方案:

// 确保在形状渲染后绑定事件
shape.on("click", function() {
    console.log('形状被点击');
});

// 检查事件系统
console.log('形状事件监听器:', shape._events);

总结

SVGPaper 是 A2UI 框架中强大的矢量图形组件,为创建复杂的图表、流程图和数据可视化提供了完整的解决方案。通过本专辑的学习,您应该能够:

  1. 掌握 SVGPaper 的核心功能:创建画布、添加形状、配置样式
  2. 了解 SVG 形状类型:基础形状、流程图专用形状、组合形状
  3. 熟练使用连接线系统:直线、曲线、流程图连接线
  4. 应用高级样式:渐变填充、阴影效果、交互样式
  5. 构建实际应用:系统架构图、业务流程、组织结构图

下一步建议

  1. 实践练习:根据本专辑的示例,创建自己的SVG图表
  2. 探索高级特性:深入研究Raphaël SVG库的高级功能
  3. 集成数据绑定:将SVG图形与动态数据结合
  4. 性能优化:对于大规模图形,实施虚拟化和懒加载
  5. 主题系统:创建可切换的主题样式

相关资源


本专辑基于 A2UI 框架和实际应用案例编写,内容将持续更新和完善。如有任何问题或建议,欢迎提交反馈。

© 2025 A2UI 项目组 | MIT License