ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

tsParticles 自定义 Shape 插件开发指南:模板 Shape 的加载、注册与绘制原理

tsParticles 自定义 Shape 插件开发指南:模板 Shape 的加载、注册与绘制原理 tsParticles 自定义 Shape 插件开发指南模板 Shape 的加载、注册与绘制原理【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles导读tsParticles 允许开发者通过插件机制注册任意自定义粒子形状Shape从而在particles.shape.type中直接使用自己的图形。本文以 cli/commands/create/files/create-shape/README.mdtsparticles-shape-template模板 Shape 文档为骨架完整讲解 CDN、ESM、CommonJS 三种接入方式并深入到引擎源码剖析IShapeDrawer接口、ShapeDrawer绘制约定、渲染管线与addShape注册机制最后以 heart 形状插件的真实实现为参照给出从模板到正式插件的完整开发路径。读完本文你将掌握编写、加载并调试一个 tsParticles 自定义形状插件的完整技术方案。模板 Shape 是什么一份可直接复用的自定义形状脚手架tsparticles-shape-template是 tsParticles 提供的模板形状包它的作用不是提供一个具体的图形而是给开发者一份最小可运行的自定义 Shape 项目骨架把其中的#template#占位符替换成你的形状名在draw方法里写下绘制代码即可得到一个完整的形状插件。模板项目的源码结构非常精简共 4 个 TypeScript 文件见 cli/commands/create/files/create-shape/src文件职责ShapeDrawer.ts实现引擎的IShapeDrawer接口定义形状类型名与draw绘制逻辑index.ts导出异步加载函数loadTemplateShape(engine)将绘制器注册进引擎index.lazy.ts懒加载动态import版本的加载函数适合按需拆包browser.ts浏览器全局版入口把loadTemplateShape挂到globalThis上在 index.ts 中加载函数的实现只有三行核心逻辑export async function loadTemplateShape(engine: Engine): Promisevoid { await engine.addShape(new ShapeDrawer()); }这段代码是脚手架的最简示意它说明了一个形状插件的最小注册动作。需要留意的是引擎真正的addShapeAPI 签名是addShape(shapes: string[], drawer: ShapeInitializer)见下文注册机制一节正式插件需要把形状名称数组与初始化器一并传入——heart 插件的写法就是标准范式。方式一CDN / Vanilla JS / jQuery 快速接入如果项目通过script标签引入脚本Vanilla JS 或 jQuery 场景只需要一个文件tsparticles.shape.template.min.js。该文件加载完成后会导出一个全局函数loadTemplateShape其全局挂载逻辑见 browser.ts文件将loadTemplateShape写入globalThis并顺带初始化了__tsParticlesInternals内部命名空间同时通过export *保留模块化导出能力。页面引入并调用加载函数后即可初始化 tsParticles 实例并使用该形状(async () { await loadTemplateShape(tsParticles); await tsParticles.load({ id: tsparticles, options: { /* options */ /* here you can use particles.shape.type: template */ }, }); })();代码要点loadTemplateShape(tsParticles)必须在tsParticles.load(...)之前await完成因为形状需要先注册进引擎后续创建的实例才能解析shape.typeid: tsparticles对应页面上承载动画的容器元素 id与 Vue、React 等框架包装器最终渲染出的 canvas 容器命名规则一致options.particles.shape.type填写模板中声明的形状类型名模板占位为#template#README 注释中以template示意实际应替换为你自己的形状标识见下文validTypes 与 shape.type 的对应关系。方式二ESM / CommonJS 模块化接入模板包同时兼容 ES Module 与 CommonJS。首先安装依赖$ npm install tsparticles-shape-template或使用 Yarn$ yarn add tsparticles-shape-templateCommonJSconst { tsParticles } require(tsparticles/engine); const { loadTemplateShape } require(tsparticles-shape-template); (async () { await loadTemplateShape(tsParticles); })();ES Moduleimport { tsParticles } from tsparticles/engine; import { loadTemplateShape } from tsparticles-shape-template; (async () { await loadTemplateShape(tsParticles); })();两条路线都从tsparticles/engine取出单例tsParticles引擎再把模板包导出的加载函数注入其中。加载函数内部会实例化ShapeDrawer并完成注册见 index.ts。如果你的打包体积敏感还可以改用 index.lazy.ts 的懒加载版本——它通过await import(./ShapeDrawer.js)动态引入绘制器让形状代码进入独立 chunk、按需加载。validTypes 与 shape.type 的对应关系模板 ShapeDrawer.ts 中通过validTypes声明了形状的类型标识readonly validTypes [#template#] as const;引擎解析粒子配置时会用particles.shape.type的值去匹配各绘制器的validTypes命中即调用该绘制器的draw完成渲染。因此README 注释中的template属于示意写法真正使用时shape.type必须与validTypes中声明的字符串完全一致开发自定义形状时第一步就是把#template#替换成你自己的类型名如heart、star并在配置里使用同名标识validTypes是一个字符串数组意味着一个绘制器可以同时响应多个形状类型名例如同时声明[hexagon, hex]让两个别名共享同一绘制逻辑。源码剖析一draw 方法的绘制约定模板 ShapeDrawer.ts 的draw方法体留空但注释给出了编写任何形状都必须遵守的四条核心约定context 已居中canvas 上下文已经被平移setTransform到粒子中心绘制时以(0, 0)为图形中心即可无需手动计算粒子坐标绘制边界为-radius到radius粒子的radius缩放后的drawRadius就是绘制坐标系中的半边长超出边界的部分可能被裁剪delta是帧间时间差毫秒实现动态形状如旋转、呼吸缩放时用它乘上速度系数动画速率就不会随帧率漂移pixelRatio是实例的像素比在高 DPIRetina屏幕上需要按它缩放线条宽度或绘制密度避免图形发虚。此外模板刻意把用不到的形参加了下划线前缀如_data这是为了通过 lint 检查正式开发时按需去下划线并解构使用。源码剖析二IShapeDrawer 的完整生命周期钩子模板只实现了draw但引擎为形状绘制器预留了完整的生命周期接口见 engine/src/Core/Interfaces/IShapeDrawer.ts按需实现即可增强形状能力钩子触发时机典型用途draw(data)每帧绘制粒子时必选绘制形状路径afterDraw(data)形状路径绘制完成后追加描边、发光等后处理beforeDraw(data)绘制形状路径之前设置渐变、阴影等前置状态init(container)形状随容器初始化时异步加载图片/字体等资源loadShape(particle)粒子使用该形状时解析形状专属的 particle 选项particleInit(container, particle)粒子初始化时为粒子准备绘制缓存particleDestroy(particle)粒子销毁时释放该粒子的资源getSidesCount(particle)引擎需要边数时供polygon类算法与角度计算使用isInsideCanvas(data)边界检查时自定义出界判定优化剔除destroy(container)容器销毁时释放全局资源源码剖析三IShapeDrawData 的数据结构draw收到的data是引擎统一构造的IShapeDrawData见 engine/src/Core/Interfaces/IShapeDrawData.ts常用字段如下contextOffscreenCanvasRenderingContext2D实际绘制上下文radius/drawRadius粒子原始半径与缩放后的半径绘制时通常以drawRadius为基准drawPosition/position缩放后的绘制坐标与粒子原始坐标delta{ value, factor }形式的帧间差用于时间驱动的动画pixelRatio设备像素比用于高 DPI 适配fill/stroke该粒子是否启用了填充/描边由shape.fill、particles.shape.stroke等配置决定opacity粒子当前透明度particle当前粒子对象可读取其属性、选项甚至变换数据transformData{ a, b, c, d }变换矩阵分量分别表示水平缩放、水平斜切、垂直斜切、垂直缩放。在 RenderManager.ts 中可以确认引擎每帧为粒子组装出这样一份数据然后交给绘制器链处理。源码剖析四引擎的渲染管线与注册机制渲染管线引擎在RenderManager的#drawParticle中完成一次粒子绘制的完整编排见 engine/src/Core/RenderManager.ts根据粒子的effect、shape从绘制器表取出对应的 effect 绘制器与 shape 绘制器context.setTransform(...)将坐标系原点平移到粒子中心并应用旋转/缩放依次调用#drawBeforeEffect→#drawShapeBeforeDraw→#drawShape→#drawShapeAfterDraw→#drawAfterEffect#drawShapeRenderManager.ts内部的固定流程为context.beginPath()→ 调用你的drawer.draw(data)→ 若particle.shapeClose则closePath()→ 若fill则context.fill()→ 若stroke则context.stroke()。这解释了为什么模板注释要求只画路径、颜色已处理填充色、描边色、透明度与变换全部由引擎统一完成你的draw只需要用moveTo、lineTo、quadraticCurveTo、arc等 API 勾勒出路径。addShape 注册机制形状注册最终落在PluginManager.addShape见 engine/src/Core/Utils/PluginManager.ts它会以形状名为 key把初始化器存入initializers.shapes映射。当某个容器首次需要绘制时getShapeDrawersPluginManager.ts通过getItemMapFromInitializerengine/src/Utils/Utils.ts惰性地为每个容器实例化各自的绘制器表并按容器缓存。也就是说addShape是全局注册、影响所有后续实例而绘制器实例是按容器懒创建的。参考实现heart 形状插件的真实写法仓库 shapes/heart 是官方形状中结构最贴近模板的参考实现。它的加载函数展示了标准注册范式shapes/heart/src/index.tsexport async function loadHeartShape(engine: Engine): Promisevoid { engine.checkVersion(__VERSION__); await engine.pluginManager.register(e { e.pluginManager.addShape([heart], () Promise.resolve(new HeartDrawer())); }); }对比可见正式插件通过pluginManager.register注册回调用addShape([heart], () Promise.resolve(new HeartDrawer()))显式传入类型名数组与返回绘制器的初始化器这正是引擎 API 的真实签名模板中的一行式写法是其最简示意。绘制器本体shapes/heart/src/HeartDrawer.ts只实现了draw真正的路径绘制被抽到工具函数drawHeartshapes/heart/src/Utils.ts里——它用 6 段quadraticCurveTo贝塞尔曲线在-radius到radius的局部坐标系中画出心形路径context已经居中因此所有坐标都相对(0, 0)。把drawHeart的函数体替换成你自己的路径代码就是一个可用的自定义形状。从模板到正式插件自定义形状的完整开发路径基于上述源码依据把模板改造成正式形状插件只需四步命名把ShapeDrawer类名与validTypes中的#template#换成你的形状名如StarDrawer/star绘制在draw(data)中解构出context、drawRadius等字段用 Canvas 路径 API 以(0,0)为中心、-drawRadius ~ drawRadius为边界绘制路径需要动画就读取delta按时间驱动注册按 heart 的标准写法pluginManager.registeraddShape([类型名], () Promise.resolve(new Drawer()))或用懒加载版index.lazy.ts拆分代码使用await loadYourShape(tsParticles)之后在配置里把particles.shape.type设为你的类型名。如果不想手工拷贝模板仓库提供了 CLI 脚手架在 cli/README.md 的 Create 一节可以看到shape子命令npx tsparticles/cli-create shape folder # 或全局安装后 tsparticles-create shape folder该命令的实现在 cli/commands/create-shape/src/shape.ts通过交互式提问收集项目信息名称、描述、仓库地址等再用createProjectTemplate({ kind: shape, ... })生成cli/commands/create/files/create-shape这套模板。CLI 的命令编排见 cli/commands/create/src/create.tsshapeCreateCommand与 app、preset、plugin 等子命令一起挂载在tsparticles-create下。脚手架生成的包遵循tsparticles-shape-name的命名规则这在 CLI 的测试用例中有明确断言见 cli/commands/create/tests/create-shape.test.ts 与 cli/commands/create/tests/create-shape.test.ts例如tsparticles-shape-foo、tsparticles-shape-bar。总结模板 Shape 文档虽短却覆盖了自定义形状从加载到使用的全部接入姿势CDN 场景用tsparticles.shape.template.min.js暴露的全局loadTemplateShape模块化场景用npm installimport/require注入tsparticles/engine的单例最终在particles.shape.type中启用形状。结合引擎源码可以看到这一切背后是IShapeDrawer生命周期接口、以-radius ~ radius局部坐标系为核心的draw约定、RenderManager的固定渲染管线以及PluginManager.addShape的全局注册 容器级懒实例化机制。以 shapes/heart 为范本替换类型名、实现路径绘制、按标准范式注册即可将模板快速升级为你的专属形状插件。【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表