欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

wordcloud2.js

程序员文章站 2022-07-02 16:59:18
https://blogs.msdn.microsoft.com/dotnet/2019/01/10/announcing-ml-net-0-9-machine-learning-for-net/ https://marketplace.visualstudio.com/items?itemName ......

https://blogs.msdn.microsoft.com/dotnet/2019/01/10/announcing-ml-net-0-9-machine-learning-for-net/

https://marketplace.visualstudio.com/items?itemname=mlnet.07

https://dotnet.microsoft.com/learn/machinelearning-ai/ml-dotnet-get-started-tutorial

https://docs.microsoft.com/en-us/dotnet/machine-learning/

https://github.com/dotnet/machinelearning

wordcloud2.js:

/*!
 * wordcloud2.js
 * http://timdream.org/wordcloud2.js/
 *https://github.com/timdream/wordcloud2.js/ 
 * copyright 2011 - 2013 tim chien
 * released under the mit license
 */

'use strict';

// setimmediate
if (!window.setimmediate) {
  window.setimmediate = (function setupsetimmediate() {
    return window.mssetimmediate ||
    window.webkitsetimmediate ||
    window.mozsetimmediate ||
    window.osetimmediate ||
    (function setupsetzerotimeout() {
      if (!window.postmessage || !window.addeventlistener) {
        return null;
      }

      var callbacks = [undefined];
      var message = 'zero-timeout-message';

      // like settimeout, but only takes a function argument.  there's
      // no time argument (always zero) and no arguments (you have to
      // use a closure).
      var setzerotimeout = function setzerotimeout(callback) {
        var id = callbacks.length;
        callbacks.push(callback);
        window.postmessage(message + id.tostring(36), '*');

        return id;
      };

      window.addeventlistener('message', function setzerotimeoutmessage(evt) {
        // skipping checking event source, retarded ie confused this window
        // object with another in the presence of iframe
        if (typeof evt.data !== 'string' ||
            evt.data.substr(0, message.length) !== message/* ||
            evt.source !== window */) {
          return;
        }

        evt.stopimmediatepropagation();

        var id = parseint(evt.data.substr(message.length), 36);
        if (!callbacks[id]) {
          return;
        }

        callbacks[id]();
        callbacks[id] = undefined;
      }, true);

      /* specify clearimmediate() here since we need the scope */
      window.clearimmediate = function clearzerotimeout(id) {
        if (!callbacks[id]) {
          return;
        }

        callbacks[id] = undefined;
      };

      return setzerotimeout;
    })() ||
    // fallback
    function setimmediatefallback(fn) {
      window.settimeout(fn, 0);
    };
  })();
}

if (!window.clearimmediate) {
  window.clearimmediate = (function setupclearimmediate() {
    return window.msclearimmediate ||
    window.webkitclearimmediate ||
    window.mozclearimmediate ||
    window.oclearimmediate ||
    // "clearzerotimeout" is implement on the previous block ||
    // fallback
    function clearimmediatefallback(timer) {
      window.cleartimeout(timer);
    };
  })();
}

(function(global) {

  // check if wordcloud can run on this browser
  var issupported = (function issupported() {
    var canvas = document.createelement('canvas');
    if (!canvas || !canvas.getcontext) {
      return false;
    }

    var ctx = canvas.getcontext('2d');
    if (!ctx.getimagedata) {
      return false;
    }
    if (!ctx.filltext) {
      return false;
    }

    if (!array.prototype.some) {
      return false;
    }
    if (!array.prototype.push) {
      return false;
    }

    return true;
  }());

  // find out if the browser impose minium font size by
  // drawing small texts on a canvas and measure it's width.
  var miniumfontsize = (function getminiumfontsize() {
    if (!issupported) {
      return;
    }

    var ctx = document.createelement('canvas').getcontext('2d');

    // start from 20
    var size = 20;

    // two sizes to measure
    var hanwidth, mwidth;

    while (size) {
      ctx.font = size.tostring(10) + 'px sans-serif';
      if ((ctx.measuretext('\uff37').width === hanwidth) &&
          (ctx.measuretext('m').width) === mwidth) {
        return (size + 1);
      }

      hanwidth = ctx.measuretext('\uff37').width;
      mwidth = ctx.measuretext('m').width;

      size--;
    }

    return 0;
  })();

  // based on http://jsfromhell.com/array/shuffle
  var shufflearray = function shufflearray(arr) {
    for (var j, x, i = arr.length; i;
      j = math.floor(math.random() * i),
      x = arr[--i], arr[i] = arr[j],
      arr[j] = x) {}
    return arr;
  };

  var wordcloud = function wordcloud(elements, options) {
    if (!issupported) {
      return;
    }

    if (!array.isarray(elements)) {
      elements = [elements];
    }

    elements.foreach(function(el, i) {
      if (typeof el === 'string') {
        elements[i] = document.getelementbyid(el);
        if (!elements[i]) {
          throw 'the element id specified is not found.';
        }
      } else if (!el.tagname && !el.appendchild) {
        throw 'you must pass valid html elements, or id of the element.';
      }
    });

    /* default values to be overwritten by options object */
    var settings = {
      list: [],
      fontfamily: '"trebuchet ms", "heiti tc", "å¾®è»ÿ正黑體", ' +
                  '"arial unicode ms", "droid fallback sans", sans-serif',
      fontweight: 'normal',
      color: 'random-dark',
      minsize: 0, // 0 to disable
      weightfactor: 1,
      clearcanvas: true,
      backgroundcolor: '#fff',  // opaque white = rgba(255, 255, 255, 1)

      gridsize: 8,
      origin: null,

      drawmask: false,
      maskcolor: 'rgba(255,0,0,0.3)',
      maskgapwidth: 0.3,

      wait: 0,
      abortthreshold: 0, // disabled
      abort: function noop() {},

      minrotation: - math.pi / 2,
      maxrotation: math.pi / 2,

      shuffle: true,
      rotateratio: 0.1,

      shape: 'circle',
      ellipticity: 0.65,

      hover: null,
      click: null
    };

    if (options) {
      for (var key in options) {
        if (key in settings) {
          settings[key] = options[key];
        }
      }
    }

    /* convert weightfactor into a function */
    if (typeof settings.weightfactor !== 'function') {
      var factor = settings.weightfactor;
      settings.weightfactor = function weightfactor(pt) {
        return pt * factor; //in px
      };
    }

    /* convert shape into a function */
    if (typeof settings.shape !== 'function') {
      switch (settings.shape) {
        case 'circle':
        /* falls through */
        default:
          // 'circle' is the default and a shortcut in the code loop.
          settings.shape = 'circle';
          break;

        case 'cardioid':
          settings.shape = function shapecardioid(theta) {
            return 1 - math.sin(theta);
          };
          break;

        /*

        to work out an x-gon, one has to calculate "m",
        where 1/(cos(2*pi/x)+m*sin(2*pi/x)) = 1/(cos(0)+m*sin(0))
        http://www.wolframalpha.com/input/?i=1%2f%28cos%282*pi%2fx%29%2bm*sin%28
        2*pi%2fx%29%29+%3d+1%2f%28cos%280%29%2bm*sin%280%29%29

        copy the solution into polar equation r = 1/(cos(t') + m*sin(t'))
        where t' equals to mod(t, 2pi/x);

        */

        case 'diamond':
        case 'square':
          // http://www.wolframalpha.com/input/?i=plot+r+%3d+1%2f%28cos%28mod+
          // %28t%2c+pi%2f2%29%29%2bsin%28mod+%28t%2c+pi%2f2%29%29%29%2c+t+%3d
          // +0+..+2*pi
          settings.shape = function shapesquare(theta) {
            var thetaprime = theta % (2 * math.pi / 4);
            return 1 / (math.cos(thetaprime) + math.sin(thetaprime));
          };
          break;

        case 'triangle-forward':
          // http://www.wolframalpha.com/input/?i=plot+r+%3d+1%2f%28cos%28mod+
          // %28t%2c+2*pi%2f3%29%29%2bsqrt%283%29sin%28mod+%28t%2c+2*pi%2f3%29
          // %29%29%2c+t+%3d+0+..+2*pi
          settings.shape = function shapetriangle(theta) {
            var thetaprime = theta % (2 * math.pi / 3);
            return 1 / (math.cos(thetaprime) +
                        math.sqrt(3) * math.sin(thetaprime));
          };
          break;

        case 'triangle':
        case 'triangle-upright':
          settings.shape = function shapetriangle(theta) {
            var thetaprime = (theta + math.pi * 3 / 2) % (2 * math.pi / 3);
            return 1 / (math.cos(thetaprime) +
                        math.sqrt(3) * math.sin(thetaprime));
          };
          break;

        case 'pentagon':
          settings.shape = function shapepentagon(theta) {
            var thetaprime = (theta + 0.955) % (2 * math.pi / 5);
            return 1 / (math.cos(thetaprime) +
                        0.726543 * math.sin(thetaprime));
          };
          break;

        case 'star':
          settings.shape = function shapestar(theta) {
            var thetaprime = (theta + 0.955) % (2 * math.pi / 10);
            if ((theta + 0.955) % (2 * math.pi / 5) - (2 * math.pi / 10) >= 0) {
              return 1 / (math.cos((2 * math.pi / 10) - thetaprime) +
                          3.07768 * math.sin((2 * math.pi / 10) - thetaprime));
            } else {
              return 1 / (math.cos(thetaprime) +
                          3.07768 * math.sin(thetaprime));
            }
          };
          break;
      }
    }

    /* make sure gridsize is a whole number and is not smaller than 4px */
    settings.gridsize = math.max(math.floor(settings.gridsize), 4);

    /* shorthand */
    var g = settings.gridsize;
    var maskrectwidth = g - settings.maskgapwidth;

    /* normalize rotation settings */
    var rotationrange = math.abs(settings.maxrotation - settings.minrotation);
    var minrotation = math.min(settings.maxrotation, settings.minrotation);

    /* information/object available to all functions, set when start() */
    var grid, // 2d array containing filling information
      ngx, ngy, // width and height of the grid
      center, // position of the center of the cloud
      maxradius;

    /* timestamp for measuring each putword() action */
    var escapetime;

    /* function for getting the color of the text */
    var gettextcolor;
    switch (settings.color) {
      case 'random-dark':
        gettextcolor = function getrandomdarkcolor() {
          return 'rgb(' +
            math.floor(math.random() * 128).tostring(10) + ',' +
            math.floor(math.random() * 128).tostring(10) + ',' +
            math.floor(math.random() * 128).tostring(10) + ')';
        };
        break;

      case 'random-light':
        gettextcolor = function getrandomlightcolor() {
          return 'rgb(' +
            math.floor(math.random() * 128 + 128).tostring(10) + ',' +
            math.floor(math.random() * 128 + 128).tostring(10) + ',' +
            math.floor(math.random() * 128 + 128).tostring(10) + ')';
        };
        break;

      default:
        if (typeof settings.color === 'function') {
          gettextcolor = settings.color;
        }
        break;
    }

    /* interactive */
    var interactive = false;
    var infogrid = [];
    var hovered;

    var getinfogridfrommouseevent = function getinfogridfrommouseevent(evt) {
      var canvas = evt.currenttarget;
      var rect = canvas.getboundingclientrect();
      var eventx = evt.clientx - rect.left;
      var eventy = evt.clienty - rect.top;

      var x = math.floor(eventx * ((canvas.width / rect.width) || 1) / g);
      var y = math.floor(eventy * ((canvas.height / rect.height) || 1) / g);

      return infogrid[x][y];
    };

    var wordcloudhover = function wordcloudhover(evt) {
      var info = getinfogridfrommouseevent(evt);

      if (hovered === info) {
        return;
      }

      hovered = info;
      if (!info) {
        settings.hover(undefined, undefined, evt);

        return;
      }

      settings.hover(info.item, info.dimension, evt);

    };

    var wordcloudclick = function wordcloudclick(evt) {
      var info = getinfogridfrommouseevent(evt);
      if (!info) {
        return;
      }

      settings.click(info.item, info.dimension, evt);
    };

    /* get points on the grid for a given radius away from the center */
    var pointsatradius = [];
    var getpointsatradius = function getpointsatradius(radius) {
      if (pointsatradius[radius]) {
        return pointsatradius[radius];
      }

      // look for these number of points on each radius
      var t = radius * 8;

      // getting all the points at this radius
      var t = t;
      var points = [];

      if (radius === 0) {
        points.push([center[0], center[1], 0]);
      }

      while (t--) {
        // distort the radius to put the cloud in shape
        var rx = 1;
        if (settings.shape !== 'circle') {
          rx = settings.shape(t / t * 2 * math.pi); // 0 to 1
        }

        // push [x, y, t]; t is used solely for gettextcolor()
        points.push([
          center[0] + radius * rx * math.cos(-t / t * 2 * math.pi),
          center[1] + radius * rx * math.sin(-t / t * 2 * math.pi) *
            settings.ellipticity,
          t / t * 2 * math.pi]);
      }

      pointsatradius[radius] = points;
      return points;
    };

    /* return true if we had spent too much time */
    var exceedtime = function exceedtime() {
      return ((settings.abortthreshold > 0) &&
        ((new date()).gettime() - escapetime > settings.abortthreshold));
    };

    /* get the deg of rotation according to settings, and luck. */
    var getrotatedeg = function getrotatedeg() {
      if (settings.rotateratio === 0) {
        return 0;
      }

      if (math.random() > settings.rotateratio) {
        return 0;
      }

      if (rotationrange === 0) {
        return minrotation;
      }

      return minrotation + math.random() * rotationrange;
    };

    var gettextinfo = function gettextinfo(word, weight, rotatedeg) {
      // calculate the acutal font size
      // fontsize === 0 means weightfactor function wants the text skipped,
      // and size < minsize means we cannot draw the text.
      var debug = false;
      var fontsize = settings.weightfactor(weight);
      if (fontsize <= settings.minsize) {
        return false;
      }

      // scale factor here is to make sure filltext is not limited by
      // the minium font size set by browser.
      // it will always be 1 or 2n.
      var mu = 1;
      if (fontsize < miniumfontsize) {
        mu = (function calculatescalefactor() {
          var mu = 2;
          while (mu * fontsize < miniumfontsize) {
            mu += 2;
          }
          return mu;
        })();
      }

      var fcanvas = document.createelement('canvas');
      var fctx = fcanvas.getcontext('2d', { willreadfrequently: true });

      fctx.font = settings.fontweight + ' ' +
        (fontsize * mu).tostring(10) + 'px ' + settings.fontfamily;

      // estimate the dimension of the text with measuretext().
      var fw = fctx.measuretext(word).width / mu;
      var fh = math.max(fontsize * mu,
                        fctx.measuretext('m').width,
                        fctx.measuretext('\uff37').width) / mu;

      // create a boundary box that is larger than our estimates,
      // so text don't get cut of (it sill might)
      var boxwidth = fw + fh * 2;
      var boxheight = fh * 3;
      var fgw = math.ceil(boxwidth / g);
      var fgh = math.ceil(boxheight / g);
      boxwidth = fgw * g;
      boxheight = fgh * g;

      // calculate the proper offsets to make the text centered at
      // the preferred position.

      // this is simply half of the width.
      var filltextoffsetx = - fw / 2;
      // instead of moving the box to the exact middle of the preferred
      // position, for y-offset we move 0.4 instead, so latin alphabets look
      // vertical centered.
      var filltextoffsety = - fh * 0.4;

      // calculate the actual dimension of the canvas, considering the rotation.
      var cgh = math.ceil((boxwidth * math.abs(math.sin(rotatedeg)) +
                           boxheight * math.abs(math.cos(rotatedeg))) / g);
      var cgw = math.ceil((boxwidth * math.abs(math.cos(rotatedeg)) +
                           boxheight * math.abs(math.sin(rotatedeg))) / g);
      var width = cgw * g;
      var height = cgh * g;

      fcanvas.setattribute('width', width);
      fcanvas.setattribute('height', height);

      if (debug) {
        // attach fcanvas to the dom
        document.body.appendchild(fcanvas);
        // save it's state so that we could restore and draw the grid correctly.
        fctx.save();
      }

      // scale the canvas with |mu|.
      fctx.scale(1 / mu, 1 / mu);
      fctx.translate(width * mu / 2, height * mu / 2);
      fctx.rotate(- rotatedeg);

      // once the width/height is set, ctx info will be reset.
      // set it again here.
      fctx.font = settings.fontweight + ' ' +
        (fontsize * mu).tostring(10) + 'px ' + settings.fontfamily;

      // fill the text into the fcanvas.
      // xxx: we cannot because textbaseline = 'top' here because
      // firefox and chrome uses different default line-height for canvas.
      // please read https://bugzil.la/737852#c6.
      // here, we use textbaseline = 'middle' and draw the text at exactly
      // 0.5 * fontsize lower.
      fctx.fillstyle = '#000';
      fctx.textbaseline = 'middle';
      fctx.filltext(word, filltextoffsetx * mu,
                    (filltextoffsety + fontsize * 0.5) * mu);

      // get the pixels of the text
      var imagedata = fctx.getimagedata(0, 0, width, height).data;

      if (exceedtime()) {
        return false;
      }

      if (debug) {
        // draw the box of the original estimation
        fctx.strokerect(filltextoffsetx * mu,
                        filltextoffsety, fw * mu, fh * mu);
        fctx.restore();
      }

      // read the pixels and save the information to the occupied array
      var occupied = [];
      var gx = cgw, gy, x, y;
      var bounds = [cgh / 2, cgw / 2, cgh / 2, cgw / 2];
      while (gx--) {
        gy = cgh;
        while (gy--) {
          y = g;
          singlegridloop: {
            while (y--) {
              x = g;
              while (x--) {
                if (imagedata[((gy * g + y) * width +
                               (gx * g + x)) * 4 + 3]) {
                  occupied.push([gx, gy]);

                  if (gx < bounds[3]) {
                    bounds[3] = gx;
                  }
                  if (gx > bounds[1]) {
                    bounds[1] = gx;
                  }
                  if (gy < bounds[0]) {
                    bounds[0] = gy;
                  }
                  if (gy > bounds[2]) {
                    bounds[2] = gy;
                  }

                  if (debug) {
                    fctx.fillstyle = 'rgba(255, 0, 0, 0.5)';
                    fctx.fillrect(gx * g, gy * g, g - 0.5, g - 0.5);
                  }
                  break singlegridloop;
                }
              }
            }
            if (debug) {
              fctx.fillstyle = 'rgba(0, 0, 255, 0.5)';
              fctx.fillrect(gx * g, gy * g, g - 0.5, g - 0.5);
            }
          }
        }
      }

      if (debug) {
        fctx.fillstyle = 'rgba(0, 255, 0, 0.5)';
        fctx.fillrect(bounds[3] * g,
                      bounds[0] * g,
                      (bounds[1] - bounds[3] + 1) * g,
                      (bounds[2] - bounds[0] + 1) * g);
      }

      // return information needed to create the text on the real canvas
      return {
        mu: mu,
        occupied: occupied,
        bounds: bounds,
        gw: cgw,
        gh: cgh,
        filltextoffsetx: filltextoffsetx,
        filltextoffsety: filltextoffsety,
        filltextwidth: fw,
        filltextheight: fh,
        fontsize: fontsize
      };
    };

    /* determine if there is room available in the given dimension */
    var canfittext = function canfittext(gx, gy, gw, gh, occupied) {
      // go through the occupied points,
      // return false if the space is not available.
      var i = occupied.length;
      while (i--) {
        var px = gx + occupied[i][0];
        var py = gy + occupied[i][1];

        if (px >= ngx || py >= ngy || px < 0 || py < 0 || !grid[px][py]) {
          return false;
        }
      }
      return true;
    };

    /* actually draw the text on the grid */
    var drawtext = function drawtext(gx, gy, info, word, weight,
                                     distance, theta, rotatedeg, attributes) {

      var fontsize = info.fontsize;
      var color;
      if (gettextcolor) {
        color = gettextcolor(word, weight, fontsize, distance, theta);
      } else {
        color = settings.color;
      }

      var dimension;
      var bounds = info.bounds;
      dimension = {
        x: (gx + bounds[3]) * g,
        y: (gy + bounds[0]) * g,
        w: (bounds[1] - bounds[3] + 1) * g,
        h: (bounds[2] - bounds[0] + 1) * g
      };

      elements.foreach(function(el) {
        if (el.getcontext) {
          var ctx = el.getcontext('2d');
          var mu = info.mu;

          // save the current state before messing it
          ctx.save();
          ctx.scale(1 / mu, 1 / mu);

          ctx.font = settings.fontweight + ' ' +
                     (fontsize * mu).tostring(10) + 'px ' + settings.fontfamily;
          ctx.fillstyle = color;

          // translate the canvas position to the origin coordinate of where
          // the text should be put.
          ctx.translate((gx + info.gw / 2) * g * mu,
                        (gy + info.gh / 2) * g * mu);

          if (rotatedeg !== 0) {
            ctx.rotate(- rotatedeg);
          }

          // finally, fill the text.

          // xxx: we cannot because textbaseline = 'top' here because
          // firefox and chrome uses different default line-height for canvas.
          // please read https://bugzil.la/737852#c6.
          // here, we use textbaseline = 'middle' and draw the text at exactly
          // 0.5 * fontsize lower.
          ctx.textbaseline = 'middle';
          ctx.filltext(word, info.filltextoffsetx * mu,
                             (info.filltextoffsety + fontsize * 0.5) * mu);

          // the below box is always matches how <span>s are positioned
          /* ctx.strokerect(info.filltextoffsetx, info.filltextoffsety,
            info.filltextwidth, info.filltextheight); */

          // restore the state.
          ctx.restore();
        } else {
          // drawtext on div element
          var span = document.createelement('span');
          var transformrule = '';
          transformrule = 'rotate(' + (- rotatedeg / math.pi * 180) + 'deg) ';
          if (info.mu !== 1) {
            transformrule +=
              'translatex(-' + (info.filltextwidth / 4) + 'px) ' +
              'scale(' + (1 / info.mu) + ')';
          }
          var stylerules = {
            'position': 'absolute',
            'display': 'block',
            'font': settings.fontweight + ' ' +
                    (fontsize * info.mu) + 'px ' + settings.fontfamily,
            'left': ((gx + info.gw / 2) * g + info.filltextoffsetx) + 'px',
            'top': ((gy + info.gh / 2) * g + info.filltextoffsety) + 'px',
            'width': info.filltextwidth + 'px',
            'height': info.filltextheight + 'px',
            'color': color,
            'lineheight': fontsize + 'px',
            'whitespace': 'nowrap',
            'transform': transformrule,
            'webkittransform': transformrule,
            'mstransform': transformrule,
            'transformorigin': '50% 40%',
            'webkittransformorigin': '50% 40%',
            'mstransformorigin': '50% 40%'
          };
          span.textcontent = word;
          for (var cssprop in stylerules) {
            span.style[cssprop] = stylerules[cssprop];
          }
          if (attributes) {
            for (var attribute in attributes) {
              span.setattribute(attribute, attributes[attribute]);
            }
          }
          el.appendchild(span);
        }
      });
    };

    /* help function to updategrid */
    var fillgridat = function fillgridat(x, y, drawmask, dimension, item) {
      if (x >= ngx || y >= ngy || x < 0 || y < 0) {
        return;
      }

      grid[x][y] = false;

      if (drawmask) {
        var ctx = elements[0].getcontext('2d');
        ctx.fillrect(x * g, y * g, maskrectwidth, maskrectwidth);
      }

      if (interactive) {
        infogrid[x][y] = { item: item, dimension: dimension };
      }
    };

    /* update the filling information of the given space with occupied points.
       draw the mask on the canvas if necessary. */
    var updategrid = function updategrid(gx, gy, gw, gh, info, item) {
      var occupied = info.occupied;
      var drawmask = settings.drawmask;
      var ctx;
      if (drawmask) {
        ctx = elements[0].getcontext('2d');
        ctx.save();
        ctx.fillstyle = settings.maskcolor;
      }

      var dimension;
      if (interactive) {
        var bounds = info.bounds;
        dimension = {
          x: (gx + bounds[3]) * g,
          y: (gy + bounds[0]) * g,
          w: (bounds[1] - bounds[3] + 1) * g,
          h: (bounds[2] - bounds[0] + 1) * g
        };
      }

      var i = occupied.length;
      while (i--) {
        fillgridat(gx + occupied[i][0], gy + occupied[i][1],
                   drawmask, dimension, item);
      }

      if (drawmask) {
        ctx.restore();
      }
    };

    /* putword() processes each item on the list,
       calculate it's size and determine it's position, and actually
       put it on the canvas. */
    var putword = function putword(item) {
      var word, weight, attributes;
      if (array.isarray(item)) {
        word = item[0];
        weight = item[1];
      } else {
        word = item.word;
        weight = item.weight;
        attributes = item.attributes;
      }
      var rotatedeg = getrotatedeg();

      // get info needed to put the text onto the canvas
      var info = gettextinfo(word, weight, rotatedeg);

      // not getting the info means we shouldn't be drawing this one.
      if (!info) {
        return false;
      }

      if (exceedtime()) {
        return false;
      }

      // skip the loop if we have already know the bounding box of
      // word is larger than the canvas.
      var bounds = info.bounds;
      if ((bounds[1] - bounds[3] + 1) > ngx ||
        (bounds[2] - bounds[0] + 1) > ngy) {
        return false;
      }

      // determine the position to put the text by
      // start looking for the nearest points
      var r = maxradius + 1;

      var trytoputwordatpoint = function(gxy) {
        var gx = math.floor(gxy[0] - info.gw / 2);
        var gy = math.floor(gxy[1] - info.gh / 2);
        var gw = info.gw;
        var gh = info.gh;

        // if we cannot fit the text at this position, return false
        // and go to the next position.
        if (!canfittext(gx, gy, gw, gh, info.occupied)) {
          return false;
        }

        // actually put the text on the canvas
        drawtext(gx, gy, info, word, weight,
                 (maxradius - r), gxy[2], rotatedeg, attributes);

        // mark the spaces on the grid as filled
        updategrid(gx, gy, gw, gh, info, item);

        // return true so some() will stop and also return true.
        return true;
      };

      while (r--) {
        var points = getpointsatradius(maxradius - r);

        if (settings.shuffle) {
          points = [].concat(points);
          shufflearray(points);
        }

        // try to fit the words by looking at each point.
        // array.some() will stop and return true
        // when putwordatpoint() returns true.
        // if all the points returns false, array.some() returns false.
        var drawn = points.some(trytoputwordatpoint);

        if (drawn) {
          // leave putword() and return true
          return true;
        }
      }
      // we tried all distances but text won't fit, return false
      return false;
    };

    /* send dom event to all elements. will stop sending event and return
       if the previous one is canceled (for cancelable events). */
    var sendevent = function sendevent(type, cancelable, detail) {
      if (cancelable) {
        return !elements.some(function(el) {
          var evt = document.createevent('customevent');
          evt.initcustomevent(type, true, cancelable, detail || {});
          return !el.dispatchevent(evt);
        }, this);
      } else {
        elements.foreach(function(el) {
          var evt = document.createevent('customevent');
          evt.initcustomevent(type, true, cancelable, detail || {});
          el.dispatchevent(evt);
        }, this);
      }
    };

    /* start drawing on a canvas */
    var start = function start() {
      // for dimensions, clearcanvas etc.,
      // we only care about the first element.
      var canvas = elements[0];

      if (canvas.getcontext) {
        ngx = math.floor(canvas.width / g);
        ngy = math.floor(canvas.height / g);
      } else {
        var rect = canvas.getboundingclientrect();
        ngx = math.floor(rect.width / g);
        ngy = math.floor(rect.height / g);
      }

      // sending a wordcloudstart event which cause the previous loop to stop.
      // do nothing if the event is canceled.
      if (!sendevent('wordcloudstart', true)) {
        return;
      }

      // determine the center of the word cloud
      center = (settings.origin) ?
        [settings.origin[0]/g, settings.origin[1]/g] :
        [ngx / 2, ngy / 2];

      // maxium radius to look for space
      maxradius = math.floor(math.sqrt(ngx * ngx + ngy * ngy));

      /* clear the canvas only if the clearcanvas is set,
         if not, update the grid to the current canvas state */
      grid = [];

      var gx, gy, i;
      if (!canvas.getcontext || settings.clearcanvas) {
        elements.foreach(function(el) {
          if (el.getcontext) {
            var ctx = el.getcontext('2d');
            ctx.fillstyle = settings.backgroundcolor;
            ctx.clearrect(0, 0, ngx * (g + 1), ngy * (g + 1));
            ctx.fillrect(0, 0, ngx * (g + 1), ngy * (g + 1));
          } else {
            el.textcontent = '';
            el.style.backgroundcolor = settings.backgroundcolor;
          }
        });

        /* fill the grid with empty state */
        gx = ngx;
        while (gx--) {
          grid[gx] = [];
          gy = ngy;
          while (gy--) {
            grid[gx][gy] = true;
          }
        }
      } else {
        /* determine bgpixel by creating
           another canvas and fill the specified background color. */
        var bctx = document.createelement('canvas').getcontext('2d');

        bctx.fillstyle = settings.backgroundcolor;
        bctx.fillrect(0, 0, 1, 1);
        var bgpixel = bctx.getimagedata(0, 0, 1, 1).data;

        /* read back the pixels of the canvas we got to tell which part of the
           canvas is empty.
           (no clearcanvas only works with a canvas, not divs) */
        var imagedata =
          canvas.getcontext('2d').getimagedata(0, 0, ngx * g, ngy * g).data;

        gx = ngx;
        var x, y;
        while (gx--) {
          grid[gx] = [];
          gy = ngy;
          while (gy--) {
            y = g;
            singlegridloop: while (y--) {
              x = g;
              while (x--) {
                i = 4;
                while (i--) {
                  if (imagedata[((gy * g + y) * ngx * g +
                                 (gx * g + x)) * 4 + i] !== bgpixel[i]) {
                    grid[gx][gy] = false;
                    break singlegridloop;
                  }
                }
              }
            }
            if (grid[gx][gy] !== false) {
              grid[gx][gy] = true;
            }
          }
        }

        imagedata = bctx = bgpixel = undefined;
      }

      // fill the infogrid with empty state if we need it
      if (settings.hover || settings.click) {

        interactive = true;

        /* fill the grid with empty state */
        gx = ngx + 1;
        while (gx--) {
          infogrid[gx] = [];
        }

        if (settings.hover) {
          canvas.addeventlistener('mousemove', wordcloudhover);
        }

        if (settings.click) {
          canvas.addeventlistener('click', wordcloudclick);
        }

        canvas.addeventlistener('wordcloudstart', function stopinteraction() {
          canvas.removeeventlistener('wordcloudstart', stopinteraction);

          canvas.removeeventlistener('mousemove', wordcloudhover);
          canvas.removeeventlistener('click', wordcloudclick);
          hovered = undefined;
        });
      }

      i = 0;
      var loopingfunction, stoppingfunction;
      if (settings.wait !== 0) {
        loopingfunction = window.settimeout;
        stoppingfunction = window.cleartimeout;
      } else {
        loopingfunction = window.setimmediate;
        stoppingfunction = window.clearimmediate;
      }

      var addeventlistener = function addeventlistener(type, listener) {
        elements.foreach(function(el) {
          el.addeventlistener(type, listener);
        }, this);
      };

      var removeeventlistener = function removeeventlistener(type, listener) {
        elements.foreach(function(el) {
          el.removeeventlistener(type, listener);
        }, this);
      };

      var anotherwordcloudstart = function anotherwordcloudstart() {
        removeeventlistener('wordcloudstart', anotherwordcloudstart);
        stoppingfunction(timer);
      };

      addeventlistener('wordcloudstart', anotherwordcloudstart);

      var timer = loopingfunction(function loop() {
        if (i >= settings.list.length) {
          stoppingfunction(timer);
          sendevent('wordcloudstop', false);
          removeeventlistener('wordcloudstart', anotherwordcloudstart);

          return;
        }
        escapetime = (new date()).gettime();
        var drawn = putword(settings.list[i]);
        var canceled = !sendevent('wordclouddrawn', true, {
          item: settings.list[i], drawn: drawn });
        if (exceedtime() || canceled) {
          stoppingfunction(timer);
          settings.abort();
          sendevent('wordcloudabort', false);
          sendevent('wordcloudstop', false);
          removeeventlistener('wordcloudstart', anotherwordcloudstart);
          return;
        }
        i++;
        timer = loopingfunction(loop, settings.wait);
      }, settings.wait);
    };

    // all set, start the drawing
    start();
  };

  wordcloud.issupported = issupported;
  wordcloud.miniumfontsize = miniumfontsize;

  // expose the library as an amd module
  if (typeof global.define === 'function' && global.define.amd) {
    global.define('wordcloud', [], function() { return wordcloud; });
  } else {
    global.wordcloud = wordcloud;
  }

})(window);

  

html5:

<!doctype html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset='utf-8'>
    <title>wordcloud2</title>
    <style>
        #cloud { border-radius:3px;border:1px solid #d0d0d0; }
        #cloud span { cursor: pointer; }
    </style>
</head>
<body>
    <div id='cloud' style="width:640px;height:450px;position:relative;"></div>
    <div id="details" style="width:640px;text-align:center;line-height:2em;margin-top:0.5em"></div>
    <script src='wordcloud2.js'></script>
    <script>
//https://github.com/timdream/wordcloud2.js/
        var tags = [
         ["c#", 601251],
         ["java", 585413],
         ["javascript", 557407],
         ["php", 534590],
         ["android", 466436],
         ["jquery", 438303],
         ["python", 274216],
         ["c++", 269570],
         ["html", 259946],
         ["mysql", 226906],
         ["ios", 216765],
         ["asp.net", 209653],
         ["css", 199932],
         ["sql", 192739],
         ["iphone", 190382],
         [".net", 179522],
         ["objective-c", 172609],
         ["ruby-on-rails", 152860],
         ["c", 129998],
         ["ruby", 97414],
         ["sql-server", 91050],
         ["ajax", 85036],
         ["xml", 84295],
         ["regex", 81991],
         ["arrays", 80728],
         ["wpf", 80062],
         ["asp.net-mvc", 79697],
         ["database", 70777],
         ["linux", 70772],
         ["json", 70396],
         ["django", 68893],
         ["vb.net", 63061],
         ["windows", 62042],
         ["xcode", 60950],
         ["eclipse", 60512],
         ["string", 54249],
         ["facebook", 53745],
         ["html5", 51015],
         ["ruby-on-rails-3", 50109],
         ["r", 49842],
         ["multithreading", 49806],
         ["winforms", 46643],
         ["wordpress", 46632],
         ["image", 45910],
         ["forms", 41984],
         ["performance", 40607],
         ["osx", 40401],
         ["visual-studio-2010", 40228],
         ["spring", 40207],
         ["node.js", 40041],
         ["excel", 39973],
         ["algorithm", 38661],
         ["oracle", 38565],
         ["swing", 38255],
         ["git", 37842],
         ["linq", 37489],
         ["asp.net-mvc-3", 36902],
         ["apache", 35533],
         ["web-services", 35385],
         ["wcf", 35242],
         ["perl", 35138],
         ["entity-framework", 34139],
         ["sql-server-2008", 33827],
         ["visual-studio", 33664],
         ["bash", 33139],
         ["hibernate", 32263],
         ["actionscript-3", 31760],
         ["ipad", 29476],
         ["matlab", 29210],
         ["qt", 28918],
         ["cocoa-touch", 28753],
         ["list", 28556],
         ["cocoa", 28385],
         ["file", 28200],
         ["sqlite", 28114],
         [".htaccess", 28006],
         ["flash", 27908],
         ["api", 27480],
         ["angularjs", 27042],
         ["jquery-ui", 26906],
         ["function", 26485],
         ["codeigniter", 26426],
         ["mongodb", 26223],
         ["class", 25925],
         ["silverlight", 25878],
         ["tsql", 25706],
         ["css3", 25535],
         ["delphi", 25421],
         ["security", 25325],
         ["google-maps", 24919],
         ["vba", 24301],
         ["internet-explorer", 24270],
         ["postgresql", 24236],
         ["jsp", 24224],
         ["shell", 24184],
         ["google-app-engine", 23892],
         ["oop", 23634],
         ["sockets", 23464],
         ["validation", 23429],
         ["unit-testing", 23249]
        ];
        
        wordcloud(document.getelementbyid('cloud'), {
          list : tags.map(function(word) { return [word[0], math.round(word[1]/5500)]; })
        });
        
        var clicked = function(ev) {
          if (ev.target.nodename === "span") {
            var tag = ev.target.textcontent;
            var tagelem;
            if (tags.some(function(el) { if (el[0] === tag) {tagelem = el; return true;} return false; })) {
            document.getelementbyid("details").innerhtml = "there were " + tagelem[1] + " <a href='http://www.dusystem.com/query?tag=" + tag + "&sum=" + tagelem[1] + "'>stack overflow questions tagged '" + tag + "'</a>"; //innertext 
            }
          } else {
            document.getelementbyid("details").innerhtml = "";
          }
        }
        document.getelementbyid("cloud").addeventlistener("click", clicked)

    </script>
</body>
</html>

  

随机样式效果:

wordcloud2.js