Two.js 的 Two.Points 图元详解:从散点绘制到渲染器源码级剖析
发布时间:2026/9/25 2:51:15来源:尧图网络
图形学前端【免费下载链接】two.jsA renderer agnostic two-dimensional drawing api for the web项目地址https://gitcode.com/gh_mirrors/tw/two.js点击查看免费下载Two.Points 是 Two.js 中专门用于快速绘制一组独立点的核心图元primitive类。它允许你通过一个顶点列表Two.Vector[]定义任意数量的坐标位置再由 Three.js 无关的渲染器Canvas / SVG / WebGL分别绘制为独立的实心圆点。阅读完本文你将掌握Two.Points的完整构造方式、全部样式与几何属性的语义与默认值、基于Two.makePoints的实战用法以及它在三种渲染器下的底层实现原理。本文以仓库文档 wiki/docs/shapes/points/README.md 为骨架结合源码 src/shapes/points.js 与测试用例 tests/suite/shapes.js、tests/suite/canvas.js 进行纵深展开。概述Two.Points 是什么Two.Points是 Two.js 的一级基础图元类用于“快速、轻松地绘制点”。它继承自 Two.Shape对应源码 src/shape.js因此天然具备 Two.js 统一的变换系统平移、旋转、缩放、倾斜、样式系统以及事件绑定能力。与 Two.Path 用折线/曲线连接顶点不同Two.Points的每个顶点都被渲染为一个独立的圆点顶点之间不存在连线。这使得它非常适合绘制散点图、粒子系统、星图、经纬坐标点作为 UI 上的锚点标记、数据可视化中的标记点需要海量小圆点且追求性能的场景配合 WebGL 渲染器。从源码看Points类的类签名与文档一致// src/shapes/points.js export class Points extends Shape { ... constructor(vertices) { super(); ... this._renderer.type points; ... } }构造函数唯一接收的参数是vertices——一组Two.Vector实际运行时多会被装箱为Two.Anchor它们的有序集合定义了点的坐标。所有未特别说明的方法均返回当前Two.Points实例本身以便链式调用。构造函数与创建方式直接实例化const points new Two.Points([ new Two.Anchor(0, 0), new Two.Anchor(100, 100), new Two.Anchor(200, 200), ]); two.add(points);构造函数参数说明参数类型描述verticesTwo.Vector[]一组 Two.Vector有序列表决定绘制点的位置坐标测试 tests/suite/shapes.js 验证了“传入 4 个 Anchor 后points.vertices.length为 4”。通过 Two.makePoints 工厂方法更常见的做法是使用 Two 实例上的工厂方法two.makePoints(...)它会自动把创建好的Two.Points加入当前场景并返回实例。源码位于 src/two.js支持两种传参方式// 方式一传入顶点数组 const pointsA two.makePoints([ new Two.Vector(0, 0), new Two.Vector(100, 50), ]); // 方式二直接传交替的 x / y 数值 const pointsB two.makePoints(200, 200, 220, 200, 180, 200);从makePoints的源码实现src/two.js可以看到当传入的不是数组时它会以步长 2 依次消费参数把相邻的x、y组装为new Two.Vector(x, y)再交给new Points(vertices)if (!Array.isArray(p)) { vertices []; for (let i 0; i l; i 2) { const x arguments[i]; if (typeof x ! number) { break; } const y arguments[i 1]; vertices.push(new Vector(x, y)); } }因此two.makePoints(200, 200, 220, 200, 180, 200)会生成三个点(200,200)、(220,200)、(180,200)。Canvas 渲染测试正是以此创建了三个点并设置了size 10见 tests/suite/canvas.js对应基准图 tests/images/canvas/points1x.png。核心属性全景文档列出了每个Two.Points上都存在的属性清单Two.Points.Properties定义于 src/shapes/points.js。逐一说明如下属性类型默认值说明fillString \| Two.Gradient \| Two.Texture#fff点的填充颜色或填充效果strokeString \| Two.Gradient \| Two.Texture#000点的描边颜色或描边效果linewidthNumber1描边的像素粗细opacityNumber1整体不透明度visibleBooleantrue是否显示sizeNumber1每个点的直径单位像素sizeAttenuationBooleanfalse点的大小是否随父级矩阵缩放beginningNumber0从顶点列表的哪个百分比开始渲染endingNumber1到顶点列表的哪个百分比结束渲染dashesNumber[][]应用于描边的虚线数组strokeAttenuationBooleantrue描边宽度是否随变换缩放其中strokeAttenuation属性同样包含在静态Properties列表中且与其余属性一样会被copy、clone、toObject处理源码见 src/shapes/points.js。几何与位置相关属性size每个点的直径size是Number类型描述每个点应具有的直径diameter单位为像素。默认值为1。设置它会同步影响三种渲染器中的圆点半径Canvas 渲染器中radius size * 0.5src/renderers/canvas.jsSVG 渲染器通过svg.pointsToString生成带半径r size * 0.5的弧命令src/renderers/svg.jsWebGL 渲染器则把它作为离屏纹理的尺寸src/renderers/webgl.js。points.size 10; // 直径为 10 像素的圆点sizeAttenuation大小是否随父级缩放sizeAttenuation是布尔值决定 Two.js 是否根据其矩阵层级matrix hierarchy缩放点的大小设为true点的大小相对于其父级Group / Scene的 scale 值缩放即父级放大时点也跟着变大设为false忽略父级缩放点始终保持在屏幕上的像素尺寸。默认值是false。从实现看Canvas 渲染器在sizeAttenuation为false时会用worldMatrix反算出最大缩放系数并做补偿src/renderers/canvas.jsSVG 渲染器也有同样的补偿逻辑src/renderers/svg.js。注意默认sizeAttenuation false是文档与源码一致的默认值src/shapes/points.js即默认点大小不随父级缩放。beginning 与 ending分段渲染控制beginning介于 0 与 1 之间的数值表示渲染器应从路径顶点序列的哪个百分比位置开始绘制点默认0ending介于 0 与 1 之间的数值表示渲染器应绘制到顶点序列的哪个百分比位置停止默认1。在_update的实现中src/shapes/points.jsTwo.js 会先计算总长度_length再通过getIdByLength把beginning * length与ending * length换算成顶点区间只有落在该区间内的顶点才会进入_renderer.collection被渲染。测试用例中将beginning与ending同时设为0.5也不会报错tests/suite/shapes.js。vertices有序顶点列表vertices是一组有序的Two.Vector对象决定在哪些坐标绘制点。文档特别提示该数组在实际操作时其实是一个Two.Collectionsrc/collection.js。源码 settersrc/shapes/points.js说明了这一点当赋值非 Collection 的数组时Two.js 会把它包装成new Collection(vertices)并自动绑定insert/remove事件——这意味着你向vertices集合push或删除顶点时_update会被自动触发无需手动刷新。points.vertices.push(new Two.Anchor(400, 400)); // 动态新增一个点length总长度length是只读属性表示所有顶点之间距离的总和The sum of distances between all Two.Points#vertices。它由_updateLength计算复用 src/path.js 的实现见 src/shapes/points.js供beginning/ending的分段渲染计算使用。由于是惰性求值getter 中带_flagLength判断只在需要时才重算src/shapes/points.js。样式属性fill填充fill决定点的填充内容。默认#fff。可以是CSS 颜色字符串例如red、#00AEFF参考 CSS color_value 规范Two.GradientLinearGradient / RadialGradientTwo.Texturewiki/docs/effects/texture/README.md。从 setter 实现src/shapes/points.js可以看到当 fill 是 Gradient / Texture 等效果对象时Two.js 会为它绑定change事件使效果对象的任何修改都能自动触发该Two.Points的重绘。stroke描边stroke决定点的描边内容默认#000。取值类型与fill相同CSS 颜色字符串或 Gradient / Texture。其 setter 同样会对效果对象做事件绑定src/shapes/points.js。linewidth描边粗细linewidth是描边的像素厚度默认1。它参与三种渲染器的线宽计算Canvas 中ctx.lineWidth、SVG 中stroke-width属性、WebGL 离屏纹理的绘制src/renderers/webgl.js。opacity不透明度opacity表示整个点的透明程度默认1。文档提示可以与带 alpha 值的 CSS 颜色配合使用实现双重透明叠加效果。Canvas 渲染器中opacity会与父级的渲染 opacity 相乘src/renderers/canvas.js体现 Two.js 的分层合成语义。classNameCSS 类名className是应用于元素以便与 CSS 样式兼容的类名默认。文档强调仅在 SVG 渲染器中会写入 DOM。这意味着如果你在 WebGL 或 Canvas 模式下使用className它不会被反映到渲染结果中。visible显隐控制visible控制是否显示这些点默认true。文档特别说明了一个性能要点对于 Two.CanvasRenderer 和 Two.WebGLRenderer当visible设为false时所有更新都会被禁用当场景中有大量对象时可大幅提升性能。对应的源码行为在 Canvas 渲染器中被显式处理src/renderers/canvas.js。dashes虚线描边dashes是数字数组表示应用到描边上的重复“线段长度”与“间隔长度”奇数索引代表 dash length线段长度偶数索引代表 dash space间隔长度。例如points.dashes [2, 2]表示 2 像素线段 2 像素间隔的虚线。测试 tests/suite/shapes.js 验证了该赋值与内部_dashes的一致性。语义上对应 SVG 的stroke-dasharray属性。points.dashes [10, 5, 2, 5]; // 10 实、5 空、2 实、5 空循环往复dashes.offset虚线偏移dashes.offset是以像素为单位的数值用于偏移dashes的显示位置默认0。Canvas 渲染器会把该值写入ctx.lineDashOffsetsrc/renderers/canvas.jsSVG 渲染器则对应stroke-dashoffset属性。常用于制作描边虚线流动动画。strokeAttenuation描边衰减strokeAttenuation控制描边宽度与变换的关系true默认描边宽度随变换缩放例如父级 Group 放大时描边变粗false描边宽度保持屏幕空间的恒定视觉厚度即使缩放、缩放视口zoom也不会变粗。当为false时Two.js 会自动根据对象的 world transform scale 补偿线宽src/shapes/points.js这对数据可视化中需要恒定粗细的标记点非常有用。常用方法fromObject静态Two.Points.fromObject(obj)从一个Two.Points的对象表示object notation创建新实例返回Two.Points。文档提示它与toObject配合使用。源码实现src/shapes/points.js的要点当obj.fill是字符串时直接沿用否则通过getEffectFromObject重建 Gradient / Texture 效果对象若obj携带id则会一并恢复。因此它可以安全地完成“序列化 → 反序列化”的往返。toObject实例方法toObject()返回一个 JSON 兼容的纯对象表示当前 points 对象。源码src/shapes/points.js会把renderer.type标记为points、把vertices映射为各顶点的toObject()并把Points.Properties中已定义的全部属性写入结果。测试 tests/suite/shapes.js 验证了完整的往返流程toObject生成对象 →fromObject(obj)恢复出坐标一致的Two.Points同时copy也能产生完全一致的副本。const obj points.toObject(); const restored Two.Points.fromObject(obj);copy 与 clonecopy(points)把一个Two.Points的属性复制到另一个之上。它会深拷贝顶点Anchor.clone()或new Anchor().copy(v)再遍历Points.Properties复制样式属性src/shapes/points.jsclone(parent?)创建一个具有当前 points 相同属性的新Two.Points可选传入父级 Group 直接加入src/shapes/points.js。如果提供了parentclone 会被自动parent.add()到该父级。disposedispose()释放渲染器资源并解除全部事件。按源码注释src/shapes/points.js它会依次调用父类dispose保留渲染器类型解绑 vertices 集合事件与每个顶点的独立事件对 fill / stroke 中的效果对象调用dispose()Gradient / Texture 的彻底清理或退化为unbind()同时保留renderer.type以便将来重新挂载到新渲染器。对应测试见 tests/suite/dispose.js。便捷方法noFill / noStroke / corner / center / getBoundingClientRect / subdivide这些方法均复用Path.prototype的实现src/shapes/points.jsnoFill()快捷地把fill设为nonenoStroke()快捷地把stroke设为nonecorner()把形状顶点对齐到 points 对象的左上角center()把形状顶点对齐到 points 对象的中心getBoundingClientRect(shallow?)返回包含top、left、right、bottom、width、height的对象shallow为true时基于局部矩阵计算否则基于世界矩阵subdivide(limit)在vertices的每一项之间插入中点Two.Vectorlimit控制递归细分次数src/shapes/points.js。由于Two.Points的顶点之间不连线该操作主要用于配合beginning/ending做更平滑的分段动画。实战示例散点图的完整用法结合 Two.makePoints 与测试中的渲染配置tests/suite/canvas.js下面是一个可以直接运行的完整示例!DOCTYPE html html body div idcontainer/div script srchttps://cdn.jsdelivr.net/npm/two.jslatest/script script const two new Two({ type: Two.Types.canvas, // 或 Two.Types.svg / Two.Types.webgl width: 400, height: 400, }).appendTo(document.getElementById(container)); // 方式一工厂方法 交替坐标参数 const points two.makePoints(200, 200, 220, 200, 180, 200); // 方式二工厂方法 顶点数组 // const points two.makePoints([ // new Two.Vector(200, 200), // new Two.Vector(220, 200), // new Two.Vector(180, 200), // ]); points.size 10; // 每个点直径 10px points.fill #00AEFF; // 亮蓝实心圆点 points.noStroke(); // 取消描边 points.sizeAttenuation false; // 点大小不随父级缩放默认 two.update(); // 触发一次渲染 /script /body /html运行结果对应基准图 tests/images/canvas/points1x.png白色画布上 3 个等间距排列的亮蓝色圆点。进阶用法利用beginning/ending让点集合“逐点出现”做出入场动画利用dashesdashes.offset制作描边流动利用clone()批量复制点群利用visible false配合大量对象隐藏时的性能优化。三种渲染器下的实现细节Canvas 渲染器Canvas 渲染器对points类型的渲染逻辑位于 src/renderers/canvas.js。核心步骤取出_renderer.collection作为“命令集”即被beginning/ending筛选后的顶点子集应用矩阵变换ctx.save()ctx.transform仅当矩阵非默认时依次设置fillStyle/strokeStyle/globalAlpha/lineDashOffset对每个顶点执行ctx.moveTo(x radius, y)与ctx.arc(x, y, radius, 0, TWO_PI)最后统一fill()/stroke()。也就是说Canvas 模式下每个点都是一段独立的圆弧路径一次fill()/stroke()批量绘制。SVG 渲染器SVG 渲染器对points类型的实现位于 src/renderers/svg.js配套的工具函数svg.pointsToString见 src/renderers/svg.js。它把每个点编码成 SVG 的path元素d属性M x (y - r) a r r 0 1 0 0.001 0 Z即先moveTo到点顶部再用一个小圆弧绘制出整个圆。当sizeAttenuation为false时同样会用worldMatrix反算缩放系数来补偿半径src/renderers/svg.js。此外className只会在此渲染器中被写入 DOM对应文档提示fill / stroke 为 Gradient 或 Texture 时会被序列化为url(#effectId)引用。WebGL 渲染器WebGL 渲染器采用“单顶点纹理”策略先在离屏 canvas 上把“一个点”的样式fill、stroke、linewidth、opacity、dashes、size绘制成纹理再为每个顶点实例化一个四边形进行批量贴图渲染。核心逻辑见 src/renderers/webgl.jsconst canvas this.canvas; const ctx this.ctx; const ratio gl.renderer.ratio; ... const size elem._size * ratio; let dimension size; if (!webgl.isHidden.test(stroke)) { dimension linewidth; } canvas.width getPoT(dimension); canvas.height canvas.width;其中getPoT把纹理尺寸对齐到 2 的幂次power of two以适配 WebGL 纹理约束。这种“一个点一份纹理 实例化渲染”的设计让大量点集的场景在 WebGL 下拥有良好的吞吐性能。对象往返与持久化Two.Points支持完整的 JSON 化往返流程const point new Two.Points(new Two.Anchor(50, 50)); point.id my-point; const obj point.toObject(); // - { id, vertices:[...], fill, stroke, ... } const newPoint Two.Points.fromObject(obj); // 还原出坐标一致的新实例测试 tests/suite/shapes.js 用 7 个断言覆盖了这一过程toObject返回对象、保留顶点 x/y、保留id、fromObject还原坐标、copy生成完全一致的副本。这意味着你可以把散点数据序列化保存之后无缝重建。延伸阅读Two.Shape 基类Two.Points的继承基类Two.Vector顶点坐标对象Two.Collectionvertices的实际容器Two.Path复用其noFill、corner、center、subdivide等实现Canvas 渲染器、SVG 渲染器、WebGL 渲染器三种渲染模式源码src/shapes/points.js测试tests/suite/shapes.js、tests/suite/canvas.js、tests/suite/dispose.js。赞分享图形学前端【免费下载链接】two.jsA renderer agnostic two-dimensional drawing api for the web项目地址https://gitcode.com/gh_mirrors/tw/two.js点击查看免费下载相关推荐Two.js Changelog 全解读从 v0.1.0 到 v0.8.24 的渲染器无关 2D 绘图 API 演进史Two.js Changelog 全解读从 v0.1.0 到 v0.8.24 的渲染器无关 2D 绘图 API 演进史 Two.js 是一个渲染器无关ren图形学前端Two.js CanvasRenderer 详解场景图到 canvas / 的 2D 渲染管线Two.js CanvasRenderer 详解场景图到 canvas / 的 2D 渲染管线 导读 Two.CanvasRenderer 是 Two.js图形学前端Two.js SVG 渲染器Two.SVGRenderer深度解析从场景图到 svg / 的渲染管线与实战指南Two.js SVG 渲染器Two.SVGRenderer深度解析从场景图到 svg / 的渲染管线与实战指南 Two.SVGRenderer 是 Tw图形学前端上一篇如何让老款Mac焕发新生OpenCore Legacy Patcher完整使用指南下一篇BuildingBlocks主题切换系统动态主题与夜间模式的完整实现方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网