Two.js 渐变关键点(Two.Stop)完全指南:offset、color 与 opacity 的源码级解析
图形学前端【免费下载链接】two.jsA renderer agnostic two-dimensional drawing api for the web项目地址https://gitcode.com/gh_mirrors/tw/two.js点击查看免费下载Two.Stop 是 Two.js 中承载渐变颜色关键点color stop的核心数据类每一个 Stop 都以“位置offset 颜色color 不透明度opacity”三元组定义渐变轴上的一次颜色过渡是构建 Two.LinearGradient 与 Two.RadialGradient 的最小单元。本文以 wiki/docs/effects/stop/README.md 为骨架结合 src/effects/stop.js 源码与其在三大渲染器中的实际消费方式系统讲解 Two.Stop 的构造规则、默认值生成逻辑、实例方法、序列化机制以及渲染层映射帮助你彻底掌握 Two.js 渐变系统并可独立写出可运行的渐变示例。Two.Stop 在 Two.js 中的定位Two.js 是一个渲染器无关renderer agnostic的二维绘图 API支持 Canvas、SVG 与 WebGL 三种后端。渐变填充是其fill/stroke能力的重要组成部分而Two.Stop正是渐变填充的“调色板刻度”一个渐变Two.Gradient由若干stops组成它们是“有序”的渲染时按数组顺序在渐变轴上逐段过渡Two.Stop继承自 Two.Element拥有元素级的能力id、事件、序列化等源码 src/effects/gradient.js 中Gradient.Stop Stop即Two.Gradient.Stop与Two.Stop是同一个类两种写法等价测试代码中两种形式均有使用。因此掌握Two.Stop就等于掌握了 Two.js 渐变系统中“颜色如何随位置变化”的完整机制。构造函数与默认值“交替”逻辑Two.Stop的构造函数签名如下参见 src/effects/stop.js参数类型说明offsetNumber该关键点的位置百分比用 0~1 之间的值表示。不传时默认值会“交替翻转”见下文colorString该关键点的颜色。不传时默认值会在白色与黑色之间“交替翻转”opacityNumber不透明度值默认 1不能低于 0Two.Stop的构造函数在 src/effects/stop.js 中的实现如下constructor(offset, color, opacity) { super(); for (let prop in proto) { Object.defineProperty(this, prop, proto[prop]); } this._renderer.type stop; // offset 未传时根据全局计数器 Stop.Index 决定默认值 this.offset typeof offset number ? offset : Stop.Index 0 ? 0 : 1; // opacity 未传时默认 1 this.opacity typeof opacity number ? opacity : 1; // color 未传时根据全局计数器 Stop.Index 决定默认色 this.color typeof color string ? color : Stop.Index 0 ? #fff : #000; Stop.Index (Stop.Index 1) % 2; }这里有两个值得注意的细节Stop.Index全局计数器的翻转每创建一个未指定offset/color的 Stop静态属性Stop.Index就在0和1之间取模翻转(Index 1) % 2。于是连续新建的空参数 Stop 会自动获得“第一段在 0 处为白色、第二段在 1 处为黑色”的交替默认值——这正是文档所述“flip flops”的精确含义。内部下划线属性真正的数据存储在_offset、_color、_opacity三个私有字段中外部访问走的是proto中定义的存取器getter/settersetter 除了赋值还会触发脏标记见下文“属性更新机制”。实例属性offset、color 与 opacityoffset位置类型Number语义0 表示渐变轴的起点1 表示终点中间值按比例插值。默认值Stop.Index 0 ? 0 : 1。SVG 渲染时会被转换为100 * offset %如0.25→offset25%见 src/renderers/svg.js。color颜色类型String支持 CSS 颜色字符串包括#fff、#ff0000、rgb(255, 100, 100)、rgba(...)等形式。测试中大量使用new Two.Stop(0, rgb(255, 100, 100))这类写法见 tests/suite/canvas.js。默认值Stop.Index 0 ? #fff : #000。SVG 渲染时映射为stop-color属性见 src/renderers/svg.js。opacity不透明度类型Number默认1文档注明“不能低于 0”。渲染器支持限制文档与源码双重提示——opacity属性仅在 SVG 渲染器上原生支持映射为stop-opacity见 src/renderers/svg.js。Canvas 与 WebGL 渲染器通过ctx.createLinearGradientaddColorStop实现渐变见 src/renderers/canvas.js 与 src/renderers/webgl.js该 API 不支持独立的 stop 不透明度。跨渲染器等价方案文档给出的替代方案是“把 opacity 直接编码进color的rgba字符串”例如用rgba(255, 0, 0, 0.5)代替“红色 opacity 0.5”这样在 Canvas/WebGL 下同样能获得半透明过渡效果。静态成员Two.Stop.Index类型Number定义于 src/effects/stop.js源码默认值0。作用作为全局计数参照决定“未指定参数”的 Stop 的默认offset与color构造完成后(Index 1) % 2翻转。它是模块级共享状态会随 Stop 的创建次数在 0/1 间往复。Two.Stop.Properties类型String[]值[offset, opacity, color]见 src/effects/stop.js。作用声明所有Two.Stop实例共有的可序列化/可复制属性copy、clone、toObject、fromObject均以该数组为白名单循环处理。Two.Stop.fromObject(obj)返回Two.Stop实现位于 src/effects/stop.js内部new Stop().copy(obj)构造实例若obj含id字段则一并恢复从而保证反序列化后 id 不变。const stop Two.Stop.fromObject({ offset: 0.25, color: #ff0000, opacity: 0.8 }); // 等价于 new Two.Stop(0.25, #ff0000, 0.8)但 id 可由对象携带文档注明fromObject与toObject成对使用nota-bene 提示二者组合可实现 Stop 的完整 JSON 往返。实例方法copy、clone、toObjectcopy(stop)参数stop作为拷贝来源的Two.Stop引用。语义把一个 Stop 的属性完整复制到另一个 Stop 上。实现见 src/effects/stop.js先调用父类Element的copy再遍历Stop.Properties凡源对象含有的属性一律this[k] stop[k]走 setter因此会同步触发脏标记与父渐变更新。const a new Two.Stop(0, #ff0000); const b new Two.Stop(); // 默认值 b.copy(a); // b 现在与 a 属性一致clone(parent)参数parent可选目标父渐变Two.Gradient。返回Two.Stop语义以当前实例属性创建全新 Stop。实现见 src/effects/stop.js遍历Stop.Properties逐项赋值若传入parent且其存在stops集合会把克隆体push进parent.stops——这是Gradient.clone内部克隆 stops 时使用的同款机制见 src/effects/gradient.js。const parent new Two.LinearGradient(); // 已有 stops 集合 const s new Two.Stop(0.5, #00ff00); const twin s.clone(parent); // twin 属性与 s 相同并被加入 parent.stopstoObject()返回普通ObjectJSON 兼容。语义返回表示该 Stop 的纯对象。实现见 src/effects/stop.js调用父类toObject得到基础对象并设置renderer.type stop再把Stop.Properties三个字段逐一写入。const s new Two.Stop(0.5, #00ff00, 1); s.toObject(); // 输出类似{ renderer: { type: stop }, offset: 0.5, opacity: 1, color: #00ff00 }flagReset()内部方法私有方法文档归类为内部机制。实现见 src/effects/stop.js把_flagOffset、_flagColor、_flagOpacity三个脏标记统一复位为false。渲染器消费完一个 Stop 后调用它保证“只有真正变化的属性才会被更新”避免每帧重复写入 DOM 或重新构建渐变对象。属性更新机制脏标记与父渐变联动Two.Stop的属性全部由proto中的存取器托管见 src/effects/stop.js核心行为如下每个属性各自持有独立脏标记_flagOffset、_flagOpacity、_flagColor初始均为true表示首次渲染需要全量写入每次 setter 赋值都会设置对应脏标记为true并且如果存在this.parent父渐变会把parent._flagStops置为true通知父渐变“stops 已变更需要重建渐变效果”三个 setter 均为enumerable: true因此会被Object.assign、JSON.stringify等遍历到。与父渐变的联动还有另一层Two.Gradient通过Collection持有 stops见 src/effects/gradient.js并在插入/移除 stop 时调用BindStops/UnbindStopssrc/effects/gradient.js。BindStops会把每个 stop 的change事件绑定到渐变的_renderer.flagStops上——这意味着直接修改stop.color ...、stop.offset ...或stop.opacity ...时无需手动调用任何更新方法父渐变会在下一帧渲染时自动感知变化并重建渐变。这正是 Two.js “渲染前统一_update、仅对变化属性生效”的脏标记架构在渐变子系统中的落地。三大渲染器如何消费 StopSVG 渲染器原生支持 opacitySVG 渲染器会把每个 Stop 渲染为stop子元素挂在linearGradient/radialGradient的defs中。相关实现见 src/renderers/svg.js线性渐变与 src/renderers/svg.js径向渐变if (stop._flagOffset) { attrs.offset 100 * stop._offset %; } if (stop._flagColor) { attrs[stop-color] stop._color; } if (stop._flagOpacity) { attrs[stop-opacity] stop._opacity; } if (!stop._renderer.elem) { stop._renderer.elem svg.createElement(stop, attrs); } else { svg.setAttributes(stop._renderer.elem, attrs); }要点offset由 0~1 的浮点值换算为百分数字符串100 * offset %只有在对应脏标记为真时才写入该属性实现“变化才更新”每个 Stop 复用其_renderer.elem仅在 stops 数量变化lengthChanged时才重建子节点渲染完成后对每个 stop 调用flagReset()复位脏标记。Canvas 与 WebGL 渲染器addColorStopCanvas 与 WebGL 两种渲染器的渐变路径一致WebGL 的effect本质上是 2D 上下文的CanvasGradient先createLinearGradient/createRadialGradient再遍历 stops 调用addColorStop。见 src/renderers/canvas.js 与 src/renderers/webgl.jsthis._renderer.effect ctx.createLinearGradient(lx, ly, rx, ry); for (let i 0; i this.stops.length; i) { const stop this.stops[i]; this._renderer.effect.addColorStop(stop._offset, stop._color); }注意此处的addColorStop第二参数只接收颜色字符串因此Stop 的opacity属性在这两种渲染器下不会生效需要把透明度合并进color的rgba()字符串中才能得到半透明过渡。这是文档中明确标注的兼容性提示也是跨渲染器编写渐变时的关键注意事项。重建时机三种渲染器都以“效果对象不存在或相关脏标记为真”为重建渐变的触发条件。以 Canvas 线性渐变为例src/renderers/canvas.jsif ( !this._renderer.effect || this._flagEndPoints || this._flagStops || this._flagUnits ) { // 重建渐变对象并重新 addColorStop }修改任意 stop 的属性都会经由parent._flagStops true使该条件成立从而在下一帧完成渐变重建。实战从零搭建带渐变的 Two.js 场景基础用法新建 Stop 与 LinearGradientconst two new Two({ width: 400, height: 400 }).appendTo(document.body); // 方式一通过 Two.Gradient.Stop 创建关键点 const stops [ new Two.Gradient.Stop(0, rgb(255, 100, 100)), new Two.Gradient.Stop(1, rgb(100, 100, 255)) ]; // 方式二等价写法 // const stops [ // new Two.Stop(0, rgb(255, 100, 100)), // new Two.Stop(1, rgb(100, 100, 255)) // ]; const gradient new Two.LinearGradient(0, 0, 400, 0, stops); const rect two.makeRectangle(200, 200, 300, 200); rect.fill gradient; rect.noStroke(); two.update();动态更新 Stop利用“修改属性自动通知父渐变”的机制可以实时驱动颜色过渡two.bind(Two.Types.update, function () { const t (two.time % 1000) / 1000; // 0 ~ 1 往复 stops[1].offset t; // 移动第二个关键点位置 stops[1].color t 0.5 ? #ff0000 : #0000ff; });序列化往返toObject与fromObject组合可把渐变关键点序列化后再恢复配合Gradient.fromObject使用见 src/effects/gradient.js其中每个 stop 会经new Stop().copy(o)重建const json JSON.stringify(gradient.toObject()); // ...存储或传输... const restored Two.LinearGradient.fromObject(JSON.parse(json));半透明关键点的跨渲染器写法仅在 SVG 渲染器使用直接设stop.opacity 0.5需要兼容 Canvas/WebGL改用color携带 alpha例如new Two.Stop(0, rgba(255, 0, 0, 0.5))。类型定义与测试佐证TypeScript 类型完整声明位于 src/effects/stop.d.ts包含Stop.Index、Stop.Properties、static fromObject、offset/opacity/color实例属性以及copy、clone、toObject、flagReset的签名可直接用于 TS 项目。测试用例仓库测试套件在多处覆盖 Stop 的构造与渐变集成例如 tests/suite/canvas.js、tests/suite/svg.js、tests/suite/webgl.js 均以new Two.Gradient.Stop(0, rgb(255, 100, 100))形式构造双关键点渐变tests/suite/dispose.js 等文件则验证 Stop 在资源释放dispose场景下的正确性。这些测试也侧面印证了Two.Stop与Two.Gradient.Stop的等价性。小结Two.Stop虽小却是 Two.js 渐变系统的基石offset决定颜色过渡发生在渐变轴的何处color决定过渡的目标颜色opacity在 SVG 下提供额外的透明度维度全局计数器Stop.Index与Properties白名单驱动了默认值生成、复制、克隆与序列化的整套行为脏标记机制让 Stop 与父渐变自动联动实现“改一个属性、下一帧自动重绘”。在 Canvas/WebGL 渲染器下请记住把透明度写进rgba()颜色字符串以获得等效效果。相关源码与文档可继续深入 src/effects/stop.js、src/effects/gradient.js 以及 wiki/docs/effects/gradient/README.md。赞分享图形学前端【免费下载链接】two.jsA renderer agnostic two-dimensional drawing api for the web项目地址https://gitcode.com/gh_mirrors/tw/two.js点击查看免费下载相关推荐3步解锁Wand专业版免费增强游戏体验的完整指南3步解锁Wand专业版免费增强游戏体验的完整指南 还在为Wand原WeMod的2小时使用限制而烦恼吗想要免费享受专业版的所有特权功能Wand Enha图形学前端RPG Maker Decrypter三步解锁RPG游戏加密资源的革命性解决方案RPG Maker Decrypter三步解锁RPG游戏加密资源的革命性解决方案 对于RPG Maker游戏开发者和爱好者来说最令人头疼的问题莫过于面对那些图形学前端AFFiNE数据可视化终极指南打造你的智能工作空间AFFiNE数据可视化终极指南打造你的智能工作空间 在信息爆炸的时代如何高效管理和可视化数据成为每个知识工作者的核心挑战。AFFiNE作为一款开源一体化工作前端桌面应用移动开发知识管理协同办公AI 应用富文本上一篇MMPose 中的 CPMConvolutional Pose Machines骨干网络多阶段顺序预测与中间监督的源码级解析下一篇Samloader深度解析三星固件下载与解密的Python技术实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

用Python自建数据字典工具:从information_schema采集到增量维护

用Python自建数据字典工具:从information_schema采集到增量维护

简介:面向数据库开发者、DBA及需要撰写数据库设计文档的技术人员,这份2.58MB的ZIP压缩包提供了一款可直接运行的数据字典生成工具。工具能自动扫描MySQL、Oracle、SQL Server、PostgreSQL等主流数据库中的表、视图、存储过程、函数与触发器,提…

2026/9/25 5:48:35 阅读更多 →
从烘焙到Lumen:Unity与UE4全局光照技术对比

从烘焙到Lumen:Unity与UE4全局光照技术对比

1. 这轮对比的背景:PBR之后,光照才是渲染的真战场1.1 为什么Part2要单独写全局光照Part1我们聊了Unity URP、HDRP和UE4在PBR材质模型、Shader着色、法线细节上的差异。评论区不少人问:材质表现都差不多了,为什么画面放在一起还是差…

2026/9/25 5:47:35 阅读更多 →
mac配置GLSL(OpenGL Shading Language)开发环境:TaoToken统一Key接入vscode与glslang校验

mac配置GLSL(OpenGL Shading Language)开发环境:TaoToken统一Key接入vscode与glslang校验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 5:47:35 阅读更多 →

最新新闻

Atlas 300V部署YOLO实战:从环境配置到多路视频推理调优

Atlas 300V部署YOLO实战:从环境配置到多路视频推理调优

早两个月我把一张Atlas 300V插进服务器的时候,第一反应是:这卡到底算不算运算加速卡?插上去之后系统里没有nvidia-smi,没有CUDA,连安装包都换了一整套名字。查了一圈才搞明白,它确实是运算加速卡&#xff0…

2026/9/25 7:20:44 阅读更多 →
Linux软死锁soft lockup故障排查与修复指南

Linux软死锁soft lockup故障排查与修复指南

1. 项目概述:这不是Dream-RAC的锅,是内核调度与硬件协同的“卡点”实录刚接触Dream-RAC这套分布式训练框架时,我跟大多数工程师一样,习惯性地把安装流程当成“照着文档敲命令”的标准化操作。直到在节点1执行grid软件安装阶段&…

2026/9/25 7:20:44 阅读更多 →
电商数据库设计实战:7张表+事务+索引+审计

电商数据库设计实战:7张表+事务+索引+审计

简介:本资源是一套面向数据库初学者与Web开发学习者的MySQL实战项目资料,聚焦购物网站系统(MyShop商城)的数据库设计与实现,解决电商类应用中用户、商品、购物车、订单等核心模块的数据建模与业务逻辑支撑问题。压缩包…

2026/9/25 7:20:44 阅读更多 →
kv4cj API参考手册:MMKV类全接口速查(附常用示例代码)

kv4cj API参考手册:MMKV类全接口速查(附常用示例代码)

kv4cj API参考手册:MMKV类全接口速查(附常用示例代码) 【免费下载链接】kv4cj 一个轻量级的键值存储库 项目地址: https://gitcode.com/Cangjie-TPC/kv4cj kv4cj 是一个用仓颉语言(Cangjie)封装的高性能键值存储…

2026/9/25 7:20:44 阅读更多 →
PHP: The Right Way —— 用 Vagrant 为 PHP 项目构建可复现的虚拟开发环境

PHP: The Right Way —— 用 Vagrant 为 PHP 项目构建可复现的虚拟开发环境

文档教程 【免费下载链接】php-the-right-way An easy-to-read, quick reference for PHP best practices, accepted coding standards, and links to authoritative tutorials around the Web 项目地址: https://gitcode.com/gh_mirrors/ph/php-the-right-way 点击…

2026/9/25 7:20:44 阅读更多 →
VoltAgent Trace Logs 实战指南:利用结构化日志快速定位 Agent 运行错误与元数据

VoltAgent Trace Logs 实战指南:利用结构化日志快速定位 Agent 运行错误与元数据

人工智能AI AgentAgent 框架后端多智能体RAG工具调用Agent 记忆 【免费下载链接】voltagent AI Agent Engineering Platform built on an Open Source TypeScript AI Agent Framework 项目地址: https://gitcode.com/gh_mirrors/vo/voltagent 点击查看 免费下载 Tr…

2026/9/25 7:19:43 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →