最近业余时间在做一个云标签相关的信息展现. 大概做成的情况能像微博关键字一样形成这样的图形:
在做的过程当中,查阅了一些资料, 发现自己有点out了,在国外已经在wordle.net这样的网站.
也有一个叫做信息视觉化(Information Visualization)的概念.于是顺着这个概念再googling了一些相关的知识.把一些知识点做一下笔记.
Information Visualization
漂亮,惊艳.与传统的云标签的表现力对比,原来的太普通了.给人全新的一种视觉感受.
而后我的想法则是为什么这么有表现力的技术不能用在我们现在的项目上?所以我有了去尝试做这种排版的想法.
现在把一些过程记录,给自己的一种笔记,给其他后来者留下一些资料.
而云标签只是信息视觉化的其中一个很小的应用.有兴趣的同学可以参考wiki或我文后给出的链接查看详情.
这里不展开描述,不是本文的重点。
过程
以上图为例,一句话简单的描述起来就是,不停的尝试把当前的文字放到能够放到的位置,直到没有文字为止.
稍微画个流程图的话,大致如下:
这里面需要特别说明的几点, 各位可以先试想一下这几个问题:
1.如何进行字符碰撞检测?
2.如果是在脚本里去做的话,如何能拿到文字显示到画布上的像素点?
3.文字大小如何设定?
4.文字是垂直还是水平如何设定?
5.如果我要显示特殊图形如何扩展?
---------分隔线--------
1.碰撞检测是很耗CPU的.最笨的方法是每个像素点都去遍历尝试,直到能放到区域内为止.也可以用空间换时间,例如使用hash cache降低放在canvas中的io操作.再进一步可以把目前所有文字的范围最小x,y坐标,最大的x,y坐标记录下来,以便于下次检测碰撞可以直接限制坐标范围.
2.canvas目前高版本里可以用canvas.getContext('2d').measureText(word).width(注:目前也仅支持这一个属性,其他属性还不支持)
3.文字大小设置最大值, 设: 最大值==出现最多字的count,那么比例ratio=MaxFontsize/maxWordcount,随之过滤掉过小的fontsize字.
4.文字和水平对于排版影响不大,可在随机,也可以通过一个函数是做符合设定规则的转换,如查用随机显示文字是垂直还是水平简单一句:isVertical = Math.random > 0.3;
5.特殊图形==图形显示范围.我个人理解应该至少有两种方案,一种是用函数计算出来,另一种方案是先手工把边界制定出来,而后再填充.(本质上是一样去约束范围)
关键代码
1.文字count
如果是中文的话,需要处理分词,分好词后再count. 关于中文分词已经算是一个单独领域了, 我不专业,就此跳过. 而英文的话很好办.
words = text.split(/\\b/);
直接通过边界分,然后转成map,count后用filter过滤即可.
比较简单,代码略过.
2.范围
如何能让文字随机显示在界面上呢?
function normalInt(min, max, iter) {
var arr = []; for(var i=0; i
return Math.floor(arr.reduce(function (i, j) {return i + j}, 0) / iter * (max - min)) + min;
}
iter值越大,得出的结果越接近于min, max的中间值.以Math.random()随机范围在(0~1),如果随机次数趋向正无穷,那么理论上随机的平均值是趋向于0.5.
例: normalInt(0,100,10000),结果接近于50,有可能出现的结果是49.12334
所以,如果代码是
var x = normalInt(0, canvas.width, 100),
y = normalInt(0, canvas.height, 100);
理论上,将正态分布在画布的中心周围.3.如何能得到显示文字边缘
canvas里面能获得imagedata, 获取CanvasPixelArray接口为canvas.getContext('2d').getImageData(x, y, width, height);
数据类型为CanvasPixelArray. 它是像素矩阵的扁平表示方法:
CanvasPixelArray包括 宽*高*4 个字节的数据, 索引范围从0到 (高*宽*4)-1.
要取得图片里一个[x,y]坐标的red颜色信息可以用以下方法
var redValueForPixel = ((y - 1) * (width * 4)) + ((x - 1) * 4);
另:在处理图像的时候,如果有API可用的话,基本都是按这样的索引结构存储.