Figma Vector Networks: 形状、填充及描边

前言

《Figma Vector Networks: 重新定义矢量图形编辑》一文中,我们分析了Vector Networks (矢量网格)与SVG Path的根本差异。Vector Networks之所以被视为"更高维度"的表述,在于其独特的拓扑结构,这为矢量图形的编辑带来了前所未有的灵活性与效率。

本文将举例说明用Vector Networks表示下面图形的形状、填充及描边。

以上图形分为两类:左边是由直线组成的,右边是由曲线组成的,当然无论矢量图形有多复杂,都可以用Vector Networks表示。

概述

文章以具体图形为例,详细解析了 Vector Networks 的组成结构------包括节点(vertices)线条(segments)区域(regions) ,并展示了如何通过 JSON 结构描述直线、矩形、三角形、五角星、曲线和椭圆等常见图形。

同时,文章还区分了底层矢量引擎与上层工具开发者的职责,强调了 Vector Networks 在简化矢量图形编辑复杂度方面的重要作用。

化繁为简

Vector Networks主要由点、线、和区域组成。

对底层矢量引擎开发者来说,需要将Vector Networks这种描述协议转换成GPU可识别的渲染命令,而解析的核心功能是根据节点和线条自动识别区域。

对上层矢量工具开发者来说,不需要关心如何解析Vector Networks,只要关注矢量图形的编辑交互功能。

这样划分的好处是:底层矢量引擎将任意矢量图形抽象成Vector Networks,并自动识别出了矢量网格中的区域,暴露出矢量网格的点线编辑,大大简化了矢量图形编辑的复杂度。

公共部分

  • type 是图形类型
  • strokeWeight 描边线宽
  • strokeAlign 描边对齐方式,分为:Center、Inside、Outside
  • strokePaints 主要是描边颜色数组
  • fillPaints 主要是填充颜色数组
  • vectorNetwork存储的是矢量网格数据,包含节点数组、线条数组、区域数组
    • vertices是节点数组,每个节点有自己的坐标和样式索引styleID (默认对应到strokePaints数组下标)
    • segments是线条数组,每个线条有起始节点的索引vertex,和对应的控制点dx/dy(曲线会用到),结束点的索引vertex,和对应的控制点dx/dy,以及样式索引styleID
    • regions是区域数组,包含多个区域。
      • 每个区域的styleID (填充样式索引) 定义了当前区域的填充,默认对应到fillPaints数组下标,也可以对应到styleOverrideTable样式覆盖表里
      • 每个区域的loops (区域) 定义了当前区域的拓扑结构,由多个segments (环) 组成,如果只有一个segments则代表当前区域由一个环围城,多个segments一般代表由内环和外环共同围城的区域

直线

javascript 复制代码
const line = {
    "type": "VECTOR", // 图形类型是矢量网格
    "strokeWeight": 1, // 描边宽度为1个单位
    "strokeAlign": "CENTER", // 描边对齐方式为居中
    "strokeJoin": "MITER", // 描边连接方式为尖角连接
    "strokePaints": [
        {
            "type": "SOLID",
            "color": { // 描边颜色
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": { // 矢量网络数据
        "vertices": [ // 顶点数组
            {
                "styleID": 0, // 顶点样式ID,对应描边样式数组的第一个样式
                "x": 0,
                "y": 1
            },
            {
                "styleID": 0,
                "x": 100,
                "y": 0
            }
        ],
        "segments": [ // 线条数组
            {
                "styleID": 0, // 线条样式ID,对应描边样式数组的第一个样式
                "start": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                }
            }
        ],
        "regions": [] // 区域数组为空,表示没有可填充区域
    }
};
export default line;

矩形

javascript 复制代码
const rectangle = {
    "type": "ROUNDED_RECTANGLE",
    "strokeWeight": 1,
    "strokeAlign": "INSIDE",
    "strokeJoin": "MITER",
    "fillPaints": [
        {
            "type": "SOLID",
            "color": { // 填充颜色
                "r": 0.8509804010391235,
                "g": 0.8509804010391235,
                "b": 0.8509804010391235,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "strokePaints": [
        {
            "type": "SOLID",
            "color": { // 描边颜色
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": {
        "vertices": [
            {
                "styleID": 0,
                "x": 0,
                "y": 0
            },
            {
                "styleID": 0,
                "x": 100,
                "y": 0
            },
            {
                "styleID": 0,
                "x": 100,
                "y": 50
            },
            {
                "styleID": 0,
                "x": 0,
                "y": 50
            }
        ],
        "segments": [
            {
                "styleID": 0,
                "start": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 3,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 3,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                }
            }
        ],
        "regions": [ // 区域数组里有一个区域
            {
                "styleID": 0,
                "windingRule": "NONZERO",
                "loops": [ // 当前区域由一个环围城
                    {
                        "segments": [ // 当前环由边 0/1/2/3 四条边围城
                            0,
                            1,
                            2,
                            3
                        ]
                    }
                ]
            }
        ]
    }
};
export default rectangle;

三角形

javascript 复制代码
const polygon = {
    "type": "REGULAR_POLYGON",
    "strokeWeight": 1,
    "strokeAlign": "INSIDE",
    "strokeJoin": "MITER",
    "fillPaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0.8509804010391235,
                "g": 0.8509804010391235,
                "b": 0.8509804010391235,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "strokePaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": {
        "vertices": [
            {
                "styleID": 0,
                "x": 50,
                "y": 0
            },
            {
                "styleID": 0,
                "x": 93.30126953125,
                "y": 75
            },
            {
                "styleID": 0,
                "x": 6.69873046875,
                "y": 75
            }
        ],
        "segments": [
            {
                "styleID": 0,
                "start": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                }
            }
        ],
        "regions": [
            {
                "styleID": 0,
                "windingRule": "NONZERO",
                "loops": [
                    {
                        "segments": [ // 当前环由三个边围成
                            0,
                            1,
                            2
                        ]
                    }
                ]
            }
        ]
    }
};
export default polygon;

五角星

javascript 复制代码
const star = {
    "type": "STAR",
    "strokeWeight": 1,
    "strokeAlign": "INSIDE",
    "strokeJoin": "MITER",
    "fillPaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0.8509804010391235,
                "g": 0.8509804010391235,
                "b": 0.8509804010391235,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "strokePaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": {
        "vertices": [
            {
                "styleID": 0,
                "x": 50,
                "y": 0
            },
            {
                "styleID": 0,
                "x": 61.22570037841797,
                "y": 34.54914855957031
            },
            {
                "styleID": 0,
                "x": 97.55282592773438,
                "y": 34.54914855957031
            },
            {
                "styleID": 0,
                "x": 68.16356658935547,
                "y": 55.90169906616211
            },
            {
                "styleID": 0,
                "x": 79.38926696777344,
                "y": 90.45085144042969
            },
            {
                "styleID": 0,
                "x": 50,
                "y": 69.09829711914062
            },
            {
                "styleID": 0,
                "x": 20.610736846923828,
                "y": 90.45085144042969
            },
            {
                "styleID": 0,
                "x": 31.836435317993164,
                "y": 55.90169906616211
            },
            {
                "styleID": 0,
                "x": 2.447174072265625,
                "y": 34.54914855957031
            },
            {
                "styleID": 0,
                "x": 38.77429962158203,
                "y": 34.54914855957031
            }
        ],
        "segments": [
            {
                "styleID": 0,
                "start": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 1,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 3,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 3,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 4,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 4,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 5,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 5,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 6,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 6,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 7,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 7,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 8,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 8,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 9,
                    "dx": 0,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 9,
                    "dx": 0,
                    "dy": 0
                },
                "end": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 0
                }
            }
        ],
        "regions": [
            {
                "styleID": 0,
                "windingRule": "NONZERO",
                "loops": [
                    {
                        "segments": [ 当前环由十条边围城
                            0,
                            1,
                            2,
                            3,
                            4,
                            5,
                            6,
                            7,
                            8,
                            9
                        ]
                    }
                ]
            }
        ]
    }
};
export default star;

曲线

javascript 复制代码
const line2 = {
    "type": "VECTOR",
    "strokeWeight": 1,
    "strokeAlign": "CENTER",
    "strokeJoin": "MITER",
    "strokePaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": {
        "vertices": [
            {
                "styleID": 0,
                "x": 0,
                "y": 23.836986541748047
            },
            {
                "styleID": 0,
                "x": 100,
                "y": 22.8122615814209
            },
            {
                "styleID": 1,
                "x": 50,
                "y": 23.324623107910156
            }
        ],
        "segments": [
            {
                "styleID": 0,
                "start": {
                    "vertex": 0,
                    "dx": 19.28675651550293, // 起始点的控制点x坐标(相对于当前点偏移量)
                    "dy": -29.784029006958008 // 起始点的控制点y坐标(相对于当前点偏移量)
                },
                "end": {
                    "vertex": 2,
                    "dx": -22.682817459106445, // 结束点的控制点x坐标(相对于当前点偏移量)
                    "dy": -33.02580642700195 // 结束点的控制点y坐标(相对于当前点偏移量)
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 2,
                    "dx": 22.682817459106445,
                    "dy": 33.02580642700195
                },
                "end": {
                    "vertex": 1,
                    "dx": -14.171252250671387,
                    "dy": 28.461177825927734
                }
            }
        ],
        "regions": []
    }
};
export default line2;

椭圆

javascript 复制代码
const ellipse = {
    "type": "ELLIPSE",
    "strokeWeight": 1,
    "strokeAlign": "INSIDE",
    "strokeJoin": "MITER",
    "fillPaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0.8509804010391235,
                "g": 0.8509804010391235,
                "b": 0.8509804010391235,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "strokePaints": [
        {
            "type": "SOLID",
            "color": {
                "r": 0,
                "g": 0,
                "b": 0,
                "a": 1
            },
            "opacity": 1,
            "visible": true,
            "blendMode": "NORMAL"
        }
    ],
    "vectorNetwork": {
        "vertices": [
            {
                "styleID": 0,
                "x": 100,
                "y": 25
            },
            {
                "styleID": 0,
                "x": 50,
                "y": 50
            },
            {
                "styleID": 0,
                "x": 0,
                "y": 25
            },
            {
                "styleID": 0,
                "x": 50,
                "y": 0
            }
        ],
        "segments": [
            {
                "styleID": 0,
                "start": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": 13.80711841583252
                },
                "end": {
                    "vertex": 1,
                    "dx": 27.61423683166504,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 1,
                    "dx": -27.61423683166504,
                    "dy": 0
                },
                "end": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": 13.80711841583252
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 2,
                    "dx": 0,
                    "dy": -13.80711841583252
                },
                "end": {
                    "vertex": 3,
                    "dx": -27.61423683166504,
                    "dy": 0
                }
            },
            {
                "styleID": 0,
                "start": {
                    "vertex": 3,
                    "dx": 27.61423683166504,
                    "dy": 0
                },
                "end": {
                    "vertex": 0,
                    "dx": 0,
                    "dy": -13.80711841583252
                }
            }
        ],
        "regions": [
            {
                "styleID": 0,
                "windingRule": "NONZERO",
                "loops": [
                    {
                        "segments": [ // 当前环由四条曲线组成
                            0,
                            1,
                            2,
                            3
                        ]
                    }
                ]
            }
        ]
    }
};
export default ellipse;

总结

Figma Vector Networks 提供了一种更高维度的矢量图形描述方式 ,它不仅突破了传统 SVG Path 的编辑限制,还通过其独特的拓扑结构 实现了更灵活、高效的图形构建与渲染。本文通过多个实际图形示例,系统演示了如何使用 Vector Networks 的结构化数据(如 verticessegmentsregions)来定义图形的几何形状、描边样式与填充区域。无论是直线、多边形还是曲线图形,Vector Networks 都能以统一而强大的方式予以支持,极大地降低了矢量图形编辑的复杂度,为图形工具的开发与使用提供了新的可能性。

更多精彩内容可关注 风起的博客 ,微信公众号:听风说图

相关推荐
用户66006766853913 分钟前
CSS定位全解析:从static到sticky,彻底搞懂布局核心
前端·css
hanliu200318 分钟前
实训11 ,百度评分
前端
Y***K43423 分钟前
TypeScript模块解析
前端·javascript·typescript
JarvanMo25 分钟前
Xcode 没人想解决的问题:为什么苹果对平庸感到满意
前端
合作小小程序员小小店39 分钟前
web网页开发,在线%餐饮点餐%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·数据库·html·intellij-idea·springboot
鹏多多1 小时前
HTML的Video从基础使用到高级实战+兼容的完全指南
前端·javascript·vue.js
晓得迷路了1 小时前
栗子前端技术周刊第 107 期 - Angular v21、pnpm 10.22、React 2025 现状调查...
前端·javascript·angular.js
韩曙亮1 小时前
【Web APIs】JavaScript 事件高级 ③ ( DOM 事件流 | 捕获阶段 | 目标阶段 | 冒泡阶段 )
前端·javascript·web apis·捕获阶段·目标阶段·冒泡阶段·dom 事件流
p***h6431 小时前
React数据分析应用
前端·react.js·前端框架