最近业余时间在做一个云标签相关的信息展现. 大体做成的情况能像微博关键字一样形成这样的图形:
在做的过程傍边,查阅了一些资料, 发现自己有点out了,在国外已经在这样的网站.
也有一个叫做信息视觉化(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可用的话,基本都是按这样的索引结构存储.
点击图片的rgba信息并将body background显示为该色
load 外部图权限需要提升
4.碰撞
碰撞的算法斗劲简单,可是如何能提高碰撞检测的效率是关键之处.
这里用的体例是通过基于绘制文本的x,y为基础点去做判断.复杂度为循环要绘制文本的像素点:
O(((y – 1) * (width * 4)) + ((x – 1) * 4));
近似等于O( (Math.max(width, height)^2) ).
/**
* collusion 检测碰撞
* @param {CanvasPixelArray} imageData 画布的imageData
* @param {CanvasPixelArray} wordImageData 文字的imageData
* @param {Number} x 绘制文字在画布的x坐标
* @param {Number} y 绘制文字在画布的y坐标
* @return {Boolean} 返回是否碰撞
*/
function collision(imageData, wordImageData, x, y) {
var wdata, fdata, wy, widx, widxend, fidx, wv, fv;
wdata = wordImageData.data;
fdata = imageData.data;
for (wy = wordImageData.height – 1; wy >= 0; –wy) {
//逐行扫描
widx = wy * wordimg.width * 4;//当前行rgba起始值
widxend = widx + (wordimg.width * 4);//当前行末rgba结束值
fidx = ((y + wy) * imageData.width + x) * 4;//大画布中当前行的像素起始值
for (; widx < widxend; widx += 4, fidx += 4) {//根据wordimg+y坐标定位到行,开始逐列扫描,并进行斗劲
//因为rgba的rgb任意像素都可能为空,所以只用判断opacity
wv = wdata[widx + 3];
fv = fdata[fidx + 3];
//需要放置的文字在某个坐标透明度不为零
//及在已存在画布上坐标上透明度也不为零,即为碰撞
if (wv && fv) return true;
}
}
return false;
}
一些资料
CanvasPixelArray参考MDC
/En/HTML/Canvas/Pixel_manipulation_with_canvas
的作者写的一些资料:
/bv_ch03.pdf
信息可视化wiki:
/wiki/Information_visualization
stackoverflow上的一些信息:
/questions/342687/algorithm-to-implement-a-word-cloud-like-wordle
来源:/space-uid-11298.html