背景
本文简析词云(wordcloud)的源码。
布局算法
- 初始化:设置画布大小、背景色、网格大小等。
- 词处理:每个词根据其重要性(频率、权重等)被赋予一个大小。
- 位置选择:算法在画布上为每个词寻找合适的位置。这通常通过在画布中心开始,并向外螺旋(或其他形状,如圆形、星形等)搜索空间来实现。
- 碰撞检测:在放置每个词时,算法会检查该位置是否会与已放置的词重叠。这通常通过一个网格来实现,网格记录了画布上的哪些区域是空的,哪些已被占用。
- 绘制:一旦找到空间,词就会在画布上绘制出来,并更新网格状态。
- 迭代:重复上述过程,直到所有词都被尝试放置。
核心方法
weightFactor
和shape
函数用于计算词的大小和布局形状。getPointsAtRadius
函数计算给定半径上的点,这些点可能是词云中词的候选放置位置。getTextInfo
函数计算单个词的布局信息,如大小和旋转。canFitText
检查一个词是否可以放在特定位置而不覆盖已有的词。drawText
将文本实际绘制到canvas上。updateGrid
更新网格状态,标记已被占用的区域。
算法细节
位置选择
- 优先从画布中心开始绘制文字。
- 基于不同的布局图形、在每个半径上生成一系列的坐标点用于尝试绘制图形。
例如:
圆形:
1
2
3
4
5
6
7// theta 可以理解为 基于弧度均分的坐标点。
points.push([
center[0] + radius * rx * Math.cos(theta * 2 * Math.PI),
center[1] +
radius * rx * Math.sin(theta* 2 * Math.PI) * settings.ellipticity,
theta * 2 * Math.PI
]);矩形:
1
2
3
4
5
6settings.shape = function shapeSquare(theta) {
return Math.min(
1 / Math.abs(Math.cos(theta)),
1 / Math.abs(Math.sin(theta))
);
};
碰撞检测
在绘制文字之前,获取文字的信息,查看文字需要详细占用哪些网格,与整体canvas
的网格做比对,如果没有重叠则绘制、如果有重叠则尝试下一个坐标点。
每次在绘制文字之后更新了网格。将文字已占用的网格在整体canvas
的网格上标记。
附录:
核心代码
1 | // 主循环 用于绘制词云 |
1 | // 绘制单个词 |
1 | // 获取当前半径上可尝试绘制文字的坐标点 |
1 | var canFitText = function canFitText(gx, gy, gw, gh, occupied) { |