实现一个简单的文字云

分析需求

首先我们要实现的文字云效果如下:

实现一个简单的文字云_第1张图片

由图可知,该文字云的效果是,一个大标签文字在区域中心,其它小标签文字围绕这个大标签文字。
其中,这些文字有随机的颜色。
除了大标签文字,其它标签文字大小也随机。
然后,围绕这个效果呢,想象一下火影忍者的轮回眼
实现一个简单的文字云_第2张图片
其实就像一颗小石头扔向湖面,泛起阵阵涟漪(圆圈)向外扩散。

之后,文字之间不能交叉,也就是说不能碰撞,那就是说不能重叠。
好了,让我们撸起袖子

撸函数

由以上的分析,需要撸一个获取随机颜色的值函数。

function getRandomColor(){
  var arr = [0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'];
  var color = "#";
  for(i=0;i<6;i++){
    var c = parseInt(Math.random()*16);
    c = arr[c];
    color = color + c;
  }
  return color;
}

再撸一个获取随机的文字大小函数。

function getRandomFontSize(){
  var arr = [28,30,34,40];
  var res = [];
  for (var i = 0, len = arr.length; i < len; i++) {
    var j = Math.floor(Math.random() * arr.length);
    res[i] = arr[j];
    arr.splice(j, 1);
  }
  return res[0];
}

以上两个函数代码简单粗暴,不再说明。
既然最大的标签文字待在区域中心,那么获取区域的中心点坐标函数必不可少。

function getCenterPoint(DOMElement){
  var rect = DOMElement.getBoundingClientRect();
  var rectTop = rect.top;
  var rectLeft = rect.left;
  var ngx = Math.ceil(rect.width);
  var ngy = Math.ceil(rect.height);
  var center = [(ngx / 2) + rectLeft, (ngy / 2) + rectTop];

  return center;
}

一句话讲清,长宽取各一半再加上区域自己的坐标即可。
接下来就是围绕这个效果对应的函数,

function getPointsAtRadius(radius, center ,offsetY, multiple){
  var T = radius * 8;
  var t = T;
  var points = [];
  var offsetY = offsetY || 1;
  var multiple = multiple || 30;

  if (radius === 0) {
    points.push([center[0], center[1]]);
  }
  while (t) {
    points.push(
      [
        center[0] + (radius*multiple) * Math.cos( (t * 2 * Math.PI )/ T ),
        center[1] + (radius*multiple) * Math.sin( (t * 2 * Math.PI )/ T ) * offsetY,
      ]
    );
    t = t - 1;
  }

  return points;
}

初中学的三角函数派上用场,它用来获取圆上点的横坐标和纵坐标。
这里除了半径(radius)和圆中心坐标(center)两个必要参数,还加上了Y轴偏移(offsetY),和单位距离(multiple)参数。
其中Y轴偏移(offsetY)可用来缩小或扩大选取的Y坐标,从而改变生成的文字云形状。
单位距离(multiple)参数,是确定以多少像素作为一个半径单位。
这年代,屏幕分辨率都很大,不可能以单个像素进行画圈圈吧。
然后我们也没必要拿到圆上的每个点的坐标。
那我们拿圆上多少个坐标比较合适?
文字标签是矩形,一个矩形可被八个矩形直接包围。间接包围n8个矩形。
故取n
8个坐标即可。

接下来是判断两个矩形是否相交

function isCorssRect(array1, array2){
  var Xa1 = array1[0][0];
  var Ya1 = array1[0][1];
  var Xa2 = array1[1][0];
  var Ya2 = array1[1][1];

  var Xb1 = array2[0][0];
  var Yb1 = array2[0][1];
  var Xb2 = array2[1][0];
  var Yb2 = array2[1][1];

  var Xc1 = Math.max(Xa1,Xb1);
  var Yc1 = Math.max(Ya1,Yb1);
  var Xc2 = Math.min(Xa2,Xb2);
  var Yc2 = Math.min(Ya2,Yb2);

  return (Xc1 <= Xc2 && Yc1 <= Yc2);
}

首先一个矩形可由左上角坐标和右下角坐标来定义。
那么两个矩形相交,则表明两个矩形的左上角坐标最大值 要小于等于 两个矩形的右下角坐标最小值。
请看图想象。
实现一个简单的文字云_第3张图片

撸业务

有了以上几个函数,我们就可以开始构思业务逻辑。
假设输入的数据是一个数组,比如["紅樓夢","賈寶玉","林黛玉","薛寶釵","王熙鳳","李紈","賈元春","賈迎春","賈探春","賈惜春","秦可卿","賈巧姐","史湘雲","妙玉","賈政","賈赦","賈璉","賈珍","賈環","賈母","王夫人","薛姨媽","尤氏","平兒","鴛鴦","襲人","晴雯","香菱","紫鵑","麝月","小紅","金釧","甄士隱","賈雨村"]

  1. 我们要依次取出一个词,并且计算这个词的宽高。
  2. 通过围绕函数获取将要放置的坐标。
  3. 通过词的宽高 和 将要放置的坐标,可以得到这个词的左上角坐标和右下角坐标信息。
  4. 然后跟已画上去的词云左上角坐标,右下角坐标进行比较,看两个矩形是否相交
  5. 不相交,则画上去,并把它的左上角坐标,右下角坐标信息进行存储。
  6. 相交,则回到第2步,获取下一个将要放置的坐标。

具体代码如下:




    
    草珊瑚的文字云
    


    

本文实现思路和实验数据参考了wordcloud2,
并重写其百分之九十的代码。
意在理解其思路。

你可能感兴趣的:(实现一个简单的文字云)