詞雲wordcloud的實現


TOC

什么是雲詞

詞雲,也稱為文本雲或標簽雲。在詞雲圖片制作中,一般我們規定特定文本詞在文本數據源中出現的次數越多,說明該詞越重要,其在詞雲中所占區域也就越大。詞雲可以利用常見的幾何圖形,或者其他不規則的圖片素材形狀來作為界限。詞雲不僅可以應用在企業數據分析上,還可以應用到媒體營銷或者平面設計當中。
大概長這樣:

快速實現

要實現詞雲,首先肯定是要獲取詞組和權重,然后再根據數據進行可視化的展示。

分詞

手動輸入比較麻煩,一般根據句子進行分詞,然后按照詞語出現的次數計算權重。
這里推薦用【訊飛關鍵詞提取API】,有免費的額度,類似的雲平台基本上都有這類API。
https://www.xfyun.cn/doc/nlp/keyword-extraction/API.html
如果不想用雲API,也可以用開源分詞庫,這里推薦jieba
https://github.com/fxsjy/jieba

可視化

直接用輪子:
https://github.com/timdream/wordcloud2.js

如果是基於echart,可以以擴展形式引入:
https://github.com/ecomfe/echarts-wordcloud

實現原理

這里主要分析wordcloud2.js的源碼,簡要說明。
假設我們要將一個不帶旋轉的詞放入canvas中,如下圖所示:

注:canvas坐標系Y軸是向下的。
1、canvas其實被切成了許多小方塊(如例圖所示),默認方塊大小為16px,不小於4px,方格越大,間距越大。
2、初始化grid = [];用來判斷方塊中能否放置元素。
3、getTextInfo方法中,創建了一個新的fcanvas,通過measureText測量出詞組寬度,為了防止文字被切,實際的fcanvas是大於測量的寬度的,如例圖中黃色方框與綠色方框的關系。
fctx.fillText(word, fillTextOffsetX * mu, (fillTextOffsetY + fontSize * 0.5) * mu);
注意:這里為什么fillTextOffsetY要加上fontSize?
默認情況下fillText的字體是左下角在坐標點的,所以需要加上fontSize使其滿足canvas坐標系。例如:

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");


ctx.font="20px Georgia";
ctx.fillText("Hello World!",50,50);


ctx.fillRect(50,50,20,20)


可以看到文字是整個高出了方塊的。
4、fcanvas填充完文字之后,通過getImageData獲取圖片像素信息,然后循環遍歷每隔格子的每個像素,判斷像素alpha是否有值,有則判斷文字bounds邊界(例圖綠色方框),繼續循環下一個格子。
其中,bounds的值為【小y,大x,大y,小x】,通過這4個值,就可以得出邊界坐標和寬高。
左上:【小x,小y】
右上:【大x,小y】
左下:【小x,大y】
右下:【大x,大y】
寬:大x-小x
高:大y-小y
注意:imageData[((gy * g + y) * width + (gx * g + x)) * 4 + 3]

getImageData() 方法返回 ImageData 對象,該對象拷貝了畫布指定矩形的像素數據。
對於 ImageData 對象中的每個像素,都存在着四方面的信息,即 RGBA 值:
R - 紅色 (0-255)
G - 綠色 (0-255)
B - 藍色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)
color/alpha 以數組形式存在,並存儲於 ImageData 對象的 data 屬性中。

這里乘以4是因為每個像素占4個下標,加3是為了獲取alpha值。
5、從中心點位置到半徑范圍內遍歷,結合計算出的文字信息判斷格子是否被占用,沒被占用則填充文字,更新格子的值,直到放不下或放完為止。

紅色部分即為被“占領”的方格。
6、圖案遮罩如何實現的?
我們可以通過上傳圖片,實現圖片遮罩,白色部分將會被忽略,文字將被填充到黑色部分。


還記得grid[]嗎?其實我們在上傳圖片之后,通過getImageData獲取圖片數據,將白色的部分都標記成了已被占用的狀態,所以后續的遍歷,只會找到黑色的部分進行填充。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM