Paper.js 实现动态Voronoi图交互效果技术解析
前言
Voronoi图(沃罗诺伊图)是计算几何中的一个重要概念,它将平面划分为多个区域,每个区域包含一个种子点,区域内任意一点到该种子点的距离都小于到其他种子点的距离。在Paper.js中,我们可以利用其强大的矢量图形处理能力,结合Voronoi算法库,创建出精美的交互式Voronoi图效果。
核心实现原理
1. 初始化设置
首先需要引入Voronoi算法库和Paper.js库。代码中创建了Voronoi实例,并初始化了一些关键变量:
var voronoi = new Voronoi();
var sites = generateBeeHivePoints(view.size / 200, true);
var bbox, diagram;
var oldSize = view.size;
var spotColor = new Color('red');
var mousePos = view.center;
var selected = false;
2. 蜂巢点生成算法
generateBeeHivePoints
函数生成初始的种子点分布,采用蜂巢状排列方式:
function generateBeeHivePoints(size, loose) {
var points = [];
var col = view.size / size;
for (var i = -1; i < size.width + 1; i++) {
for (var j = -1; j < size.height + 1; j++) {
var point = new Point(i, j) / new Point(size) * view.size + col / 2;
if (j % 2)
point += new Point(col.width / 2, 0);
if (loose)
point += (col / 4) * Point.random() - col / 4;
points.push(point);
}
}
return points;
}
这个算法特点:
- 创建规则的网格点
- 奇数行偏移半个单位,形成蜂巢结构
- 可选的随机扰动使分布更自然
3. Voronoi图渲染流程
核心渲染函数renderDiagram
完成以下工作:
- 清空画布
- 计算Voronoi图
- 遍历每个种子点的Voronoi单元
- 为每个单元创建路径
function renderDiagram() {
project.activeLayer.removeChildren();
var diagram = voronoi.compute(sites, bbox);
if (diagram) {
for (var i = 0, l = sites.length; i < l; i++) {
var cell = diagram.cells[sites[i].voronoiId];
if (cell) {
var halfedges = cell.halfedges,
length = halfedges.length;
if (length > 2) {
var points = [];
for (var j = 0; j < length; j++) {
v = halfedges[j].getEndpoint();
points.push(new Point(v));
}
createPath(points, sites[i]);
}
}
}
}
}
4. 路径创建与优化
createPath
函数负责将Voronoi单元的顶点转换为平滑的Paper.js路径:
function createPath(points, center) {
var path = new Path();
path.fillColor = selected ? null : spotColor;
path.fullySelected = selected;
path.closed = true;
for (var i = 0, l = points.length; i < l; i++) {
var point = points[i];
var next = points[(i + 1) == points.length ? 0 : i + 1];
var vector = (next - point) / 2;
path.add({
point: point + vector,
handleIn: -vector,
handleOut: vector
});
}
path.scale(0.95);
removeSmallBits(path);
return path;
}
关键技术点:
- 使用贝塞尔曲线处理顶点,使边缘更平滑
- 整体缩放95%产生间隙效果
removeSmallBits
函数移除过小的线段保持图形整洁
交互功能实现
1. 鼠标交互
function onMouseDown(event) {
sites.push(event.point);
renderDiagram();
}
function onMouseMove(event) {
mousePos = event.point;
if (event.count == 0)
sites.push(event.point);
sites[sites.length - 1] = event.point;
renderDiagram();
}
- 点击添加新种子点
- 移动鼠标动态更新最后一个种子点位置
2. 视图响应
function onResize() {
var margin = 20;
bbox = {
xl: margin,
xr: view.bounds.width - margin,
yt: margin,
yb: view.bounds.height - margin
};
for (var i = 0, l = sites.length; i < l; i++) {
sites[i] = sites[i] * view.size / oldSize;
}
oldSize = view.size;
renderDiagram();
}
- 自适应窗口大小变化
- 保持种子点相对位置不变
3. 键盘交互
function onKeyDown(event) {
if (event.key == 'space') {
selected = !selected;
renderDiagram();
}
}
- 空格键切换显示模式(填充色/描边)
应用场景与扩展
这种动态Voronoi图实现可以应用于:
- 艺术创作:生成有机形态的艺术图案
- 游戏开发:地图区域划分、势力范围可视化
- 数据可视化:空间数据分区展示
- 交互设计:创新的用户界面元素
扩展思路:
- 添加动画效果,如种子点缓动
- 实现种子点的拖拽交互
- 结合物理引擎模拟细胞分裂效果
- 使用图像数据驱动种子点分布
总结
通过Paper.js实现Voronoi图展示了矢量图形库与计算几何算法的完美结合。这种技术组合不仅能够创建美观的视觉效果,还为各种创意应用提供了坚实的基础。理解这个示例的实现原理,可以帮助开发者掌握Paper.js的高级用法,并启发更多创新的可视化解决方案。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考