wordbox.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. (function(window, $) {
  2. 'use strict';
  3. function WordBox(wrapper, options) {
  4. var defaults = {
  5. isLead: false, // 是否包含“全部”分类,该lead分类会始终显示在第一个位置上
  6. leadWord: null,
  7. words: null,
  8. colors: ['#cc5b34', '#c27c4d'],
  9. isFixedWidth: true,
  10. width: 1000,
  11. height: 200
  12. };
  13. this.options = $.extend(false, defaults, options);
  14. this.$wrapper = $(wrapper);
  15. if (!this.$wrapper || this.options.words.length < 1) {
  16. return false;
  17. }
  18. this._create();
  19. this._bindListener();
  20. return this;
  21. };
  22. WordBox.prototype = {
  23. words: [],
  24. colors: [],
  25. colorPos: 0,
  26. _create: function() {
  27. if (this.options.isLead && this.options.leadWord) {
  28. this.words = [this.options.leadWord].concat(this._randArray(this.options.words));
  29. } else {
  30. this.words = this._randArray(this.options.words);
  31. }
  32. //容器宽高初始化
  33. if (this.options.isFixedWidth) {
  34. this.$wrapper.width(this.options.width);
  35. this.$wrapper.height(this.options.height);
  36. } else {
  37. // 容器宽高根据父级元素自适应
  38. this.$wrapper.width(this.$wrapper.parent().width());
  39. this.$wrapper.height(this.$wrapper.parent().height());
  40. }
  41. this.fillRect(this.$wrapper,
  42. 0,
  43. 0,
  44. this.$wrapper.width(),
  45. this.$wrapper.height(),
  46. this.words);
  47. },
  48. /*
  49. * 递归创建box
  50. */
  51. fillRect: function(wrapper, left, top, width, height, words) {
  52. var wordLen = words.length,
  53. ratio = width / height,
  54. dot = this._randRange(1, 2, 0.5),
  55. wordLen1 = Math.round(wordLen * dot[0]),
  56. wordLen2 = wordLen - wordLen1;
  57. if (wordLen == 1) {
  58. this._createBox(wrapper,
  59. left,
  60. top,
  61. width,
  62. height,
  63. words[0],
  64. this._getNextColor());
  65. return;
  66. }
  67. if (wordLen1 == 0) {
  68. wordLen1 = 1;
  69. wordLen2--;
  70. } else if (wordLen2 == 0) {
  71. wordLen2 = 1;
  72. wordLen1--;
  73. }
  74. if (ratio >= 2.5) {
  75. // 左右分割
  76. var leftW = Math.round(width * dot[0]),
  77. rightW = width - leftW;
  78. this.fillRect(wrapper,
  79. left,
  80. top,
  81. leftW,
  82. height,
  83. words.slice(0, wordLen1));
  84. this.fillRect(wrapper,
  85. left+leftW,
  86. top,
  87. rightW,
  88. height,
  89. words.slice(wordLen1));
  90. } else {
  91. // 上下分割
  92. var topH = Math.round(height * dot[0]),
  93. bottomH = height - topH;
  94. this.fillRect(wrapper,
  95. left,
  96. top,
  97. width,
  98. topH,
  99. words.slice(0, wordLen1));
  100. this.fillRect(wrapper,
  101. left,
  102. top+topH,
  103. width,
  104. height-topH,
  105. words.slice(wordLen1));
  106. }
  107. },
  108. /*
  109. * 创建box
  110. * @param left、right为box相对于 wrapper 绝对定位的偏移量
  111. */
  112. _createBox: function(wrapper, left, top, width, height, word, color) {
  113. var lineHeight = height,
  114. paddingTop = 0,
  115. wordW = this._getWordsWidth(word.title);
  116. // 如果box中文字的宽度超出box本身的宽度,则需要分多行显示
  117. if (wordW > width) {
  118. var line = Math.ceil(wordW / width);
  119. // 注意设置 line-height 属性和 padding-top 属性
  120. lineHeight = parseInt(this.$wrapper.css('font-size'));
  121. paddingTop = Math.max(0, (height - line * lineHeight) / 2);
  122. height -= paddingTop;
  123. }
  124. var html = '<div class="wordbox-box" style="width:' + width + 'px;' +
  125. 'height:' + height + 'px;' +
  126. 'line-height:'+ lineHeight + 'px;' +
  127. 'top:' + top + 'px;' +
  128. 'left:' + left + 'px;' +
  129. 'background-color:' + color + ';' +
  130. (paddingTop ? ('padding-top:' + paddingTop + 'px;') : '') +
  131. '">' + '<span href="' + word.url + '" >' + word.title + '</span></div>';
  132. $(wrapper).append(html);
  133. },
  134. /* 将base随机分成num份
  135. * @param base: 被分割的数
  136. * @param num: 分割的份数
  137. * @param round: base被分割之后两部分的最大差,为了避免每部分太大或太小
  138. * @param 返回值: 包含num个分界点的数组
  139. */
  140. _randRange: function(base, num, round) {
  141. var center = base / num,
  142. min = center * (1 - round),
  143. max = center * (1 + round),
  144. rand = Math.random() * (max - min) + min;
  145. if (num == 1) {
  146. return [base];
  147. }
  148. return [rand].concat(this._randRange(base - rand, num - 1, round));
  149. },
  150. /*
  151. * 每次绘制box时获取color列表中下一个颜色值
  152. */
  153. _getNextColor: function() {
  154. var color = this.options.colors[this.colorPos % this.options.colors.length];
  155. this.colorPos++;
  156. return color;
  157. },
  158. /*
  159. * 获取指定字体大小的word的宽度,根据该宽度和 box 宽度判断是否分行
  160. */
  161. _getWordsWidth: function(word) {
  162. if ($('#get_ww').size() < 1) {
  163. $('<div id="get_ww" style="display:block;visibility:hidden;font-size:'+this.$wrapper.css('font-size')+'px"><span></span></div>').appendTo('body');
  164. }
  165. $('#get_ww span').html(word);
  166. return $('#get_ww span').width();
  167. },
  168. /*
  169. * 随机排列数组元素
  170. */
  171. _randArray: function(array) {
  172. var clone = array.slice(),
  173. ret = [],
  174. rand;
  175. for(var i = 0, len = array.length; i < len; i++) {
  176. rand = Math.floor(Math.random() * clone.length);
  177. var tmp = clone[0];
  178. clone[0] = clone[rand];
  179. clone[rand] = tmp;
  180. ret.push(clone[0]);
  181. clone = clone.slice(1);
  182. }
  183. return ret;
  184. },
  185. /*
  186. * 绑定窗口大小改变事件
  187. */
  188. _bindListener: function() {
  189. if (!this.options.isFixedWidth) {
  190. var _this = this,
  191. timer = null;
  192. $(window).bind('resize', function() {
  193. if (timer) {
  194. clearTimeout(window.timer);
  195. timer = null;
  196. }
  197. timer = setTimeout(function() {
  198. // 响应式 wordbox 根据父级元素宽度和高度的变化来改变自身的宽度和高度,重新绘制
  199. if (_this.$wrapper.width() != _this.$wrapper.parent().width() ||
  200. _this.$wrapper.height() != _this.$wrapper.parent().height()) {
  201. _this.$wrapper.width(_this.$wrapper.parent().width());
  202. _this.$wrapper.height(_this.$wrapper.parent().height());
  203. // 清除之前绘制的wordbox
  204. _this.$wrapper.empty();
  205. // 重新绘制wordbox
  206. _this.fillRect(_this.$wrapper,
  207. 0,
  208. 0,
  209. _this.$wrapper.width(),
  210. _this.$wrapper.height(),
  211. _this.words);
  212. }
  213. }, 800);
  214. });
  215. }
  216. }
  217. };
  218. window.WordBox = WordBox;
  219. $.fn.wordbox = function(options) {
  220. var instance = new WordBox(this, options);
  221. if (!instance) {
  222. console.log("创建失败");
  223. return null;
  224. }
  225. // 返回jquery对象
  226. // this指的是应用插件的元素,而不是instance
  227. return $(this);
  228. };
  229. })(window, jQuery);