如何在Pixi.JS中实现网络图所需的可动效虚线(点线)贝塞尔曲线边
实现思路
- 路径采样法:贝塞尔曲线为参数曲线,可按固定步长对t∈[0,1]区间采样得到离散点集,累计路径总长度后按照「实线段长度、空白段长度」的虚线规则逐段绘制线段,无需复杂图形学知识,新手友好,适合边数量在1000条以内的场景。
- 自定义着色器法:如果需要同时渲染数千条边,可自定义PIXI.Graphics的着色器,传入贝塞尔控制点、虚线参数、动画偏移量,在片元着色器内直接计算当前像素是否落在贝塞尔曲线的实线段区间,性能比采样法高3~5倍,但需要基础的GLSL知识。
- 纹理映射法:提前生成固定样式的虚线长条纹理,将纹理沿贝塞尔曲线路径映射,动画效果直接通过偏移纹理UV实现,适合虚线样式固定、无需动态调整参数的场景。
可运行示例
以下示例均基于PixiJS v7+版本运行。
示例1:路径采样实现带动画的二次贝塞尔虚线
import * as PIXI from 'pixi.js'; // 初始化Pixi应用 const app = new PIXI.Application({ width: 800, height: 600, backgroundColor: 0x1a1a1a, antialias: true }); document.body.appendChild(app.view); // 二次贝塞尔曲线采样函数 function sampleQuadraticBezier(p0, p1, p2, t) { const mt = 1 - t; return { x: mt * mt * p0.x + 2 * mt * t * p1.x + t * t * p2.x, y: mt * mt * p0.y + 2 * mt * t * p1.y + t * t * p2.y }; } // 绘制虚线贝塞尔曲线函数 function drawDashedBezier(graphics, p0, p1, p2, dashPattern = [10, 5], offset = 0, color = 0x00ff00, width = 2) { graphics.clear(); graphics.lineStyle(width, color); const sampleStep = 0.005; // 采样步长,越小越平滑 let currentDist = -offset; let draw = true; let dashIndex = 0; let prevPoint = sampleQuadraticBezier(p0, p1, p2, 0); for (let t = sampleStep; t <= 1; t += sampleStep) { const currPoint = sampleQuadraticBezier(p0, p1, p2, t); const dx = currPoint.x - prevPoint.x; const dy = currPoint.y - prevPoint.y; const dist = Math.sqrt(dx * dx + dy * dy); currentDist += dist; while (currentDist > dashPattern[dashIndex]) { currentDist -= dashPattern[dashIndex]; dashIndex = (dashIndex + 1) % dashPattern.length; draw = !draw; const splitT = t - (sampleStep * currentDist / dist); const splitPoint = sampleQuadraticBezier(p0, p1, p2, splitT); if (draw) { prevPoint = splitPoint; } else { graphics.moveTo(prevPoint.x, prevPoint.y); graphics.lineTo(splitPoint.x, splitPoint.y); prevPoint = splitPoint; } } if (draw) { graphics.moveTo(prevPoint.x, prevPoint.y); graphics.lineTo(currPoint.x, currPoint.y); } prevPoint = currPoint; } } // 定义贝塞尔控制点 const p0 = {x: 100, y: 300}; const p1 = {x: 400, y: 100}; const p2 = {x: 700, y: 300}; const lineGraphic = new PIXI.Graphics(); app.stage.addChild(lineGraphic); let animOffset = 0; // 动画循环 app.ticker.add(() => { animOffset += 0.5; // 控制动画速度 drawDashedBezier(lineGraphic, p0, p1, p2, [15, 8], animOffset, 0x00ff88, 2); });
该示例默认实现绿色虚线二次贝塞尔曲线,虚线流动效果通过逐帧调整偏移量实现,可自行修改dashPattern参数调整虚线的实空长度比例,修改animOffset的累加值调整动画速度。
示例2:三次贝塞尔虚线实现(路径采样版)
只需要替换采样函数即可适配三次贝塞尔场景:
// 三次贝塞尔曲线采样函数 function sampleCubicBezier(p0, p1, p2, p3, t) { const mt = 1 - t; return { x: mt*mt*mt*p0.x + 3*mt*mt*t*p1.x + 3*mt*t*t*p2.x + t*t*t*p3.x, y: mt*mt*mt*p0.y + 3*mt*mt*t*p1.y + 3*mt*t*t*p2.y + t*t*t*p3.y }; }
将drawDashedBezier函数内的采样逻辑替换为上述三次采样函数,传入四个控制点即可实现三次贝塞尔虚线效果。
内容的提问来源于stack exchange,提问作者foxtrotuniform6969
相关产品推荐
相关产品推荐

