utils.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getSingleKeyValues = exports.getFontSizeMapping = exports.processImageMask = exports.getSize = exports.transform = void 0;
  4. var tslib_1 = require("tslib");
  5. var util_1 = require("@antv/util");
  6. var utils_1 = require("../../utils");
  7. var padding_1 = require("../../utils/padding");
  8. var word_cloud_1 = require("../../utils/transform/word-cloud");
  9. /**
  10. * 用 DataSet 转换词云图数据
  11. * @param params
  12. */
  13. function transform(params) {
  14. var rawOptions = params.options, chart = params.chart;
  15. var _a = chart, width = _a.width, height = _a.height, chartPadding = _a.padding, appendPadding = _a.appendPadding, ele = _a.ele;
  16. var data = rawOptions.data, imageMask = rawOptions.imageMask, wordField = rawOptions.wordField, weightField = rawOptions.weightField, colorField = rawOptions.colorField, wordStyle = rawOptions.wordStyle, timeInterval = rawOptions.timeInterval, random = rawOptions.random, spiral = rawOptions.spiral, _b = rawOptions.autoFit, autoFit = _b === void 0 ? true : _b, placementStrategy = rawOptions.placementStrategy;
  17. if (!data || !data.length) {
  18. return [];
  19. }
  20. var fontFamily = wordStyle.fontFamily, fontWeight = wordStyle.fontWeight, padding = wordStyle.padding, fontSize = wordStyle.fontSize;
  21. var arr = getSingleKeyValues(data, weightField);
  22. var range = [min(arr), max(arr)];
  23. // 变换出 text 和 value 字段
  24. var words = data.map(function (datum) { return ({
  25. text: datum[wordField],
  26. value: datum[weightField],
  27. color: datum[colorField],
  28. datum: datum,
  29. }); });
  30. var options = {
  31. imageMask: imageMask,
  32. font: fontFamily,
  33. fontSize: getFontSizeMapping(fontSize, range),
  34. fontWeight: fontWeight,
  35. // 图表宽高减去 padding 之后的宽高
  36. size: getSize({
  37. width: width,
  38. height: height,
  39. padding: chartPadding,
  40. appendPadding: appendPadding,
  41. autoFit: autoFit,
  42. container: ele,
  43. }),
  44. padding: padding,
  45. timeInterval: timeInterval,
  46. random: random,
  47. spiral: spiral,
  48. rotate: getRotate(rawOptions),
  49. };
  50. // 自定义布局函数
  51. if ((0, util_1.isFunction)(placementStrategy)) {
  52. var result = words.map(function (word, index, words) { return (tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, word), { hasText: !!word.text, font: (0, word_cloud_1.functor)(options.font)(word, index, words), weight: (0, word_cloud_1.functor)(options.fontWeight)(word, index, words), rotate: (0, word_cloud_1.functor)(options.rotate)(word, index, words), size: (0, word_cloud_1.functor)(options.fontSize)(word, index, words), style: 'normal' }), placementStrategy.call(chart, word, index, words))); });
  53. // 添加两个参照数据,分别表示左上角和右下角
  54. result.push({
  55. text: '',
  56. value: 0,
  57. x: 0,
  58. y: 0,
  59. opacity: 0,
  60. });
  61. result.push({
  62. text: '',
  63. value: 0,
  64. x: options.size[0],
  65. y: options.size[1],
  66. opacity: 0,
  67. });
  68. return result;
  69. }
  70. // 数据准备在外部做,wordCloud 单纯就是做布局
  71. return (0, word_cloud_1.wordCloud)(words, options);
  72. }
  73. exports.transform = transform;
  74. /**
  75. * 获取最终的实际绘图尺寸:[width, height]
  76. * @param chart
  77. */
  78. function getSize(options) {
  79. var width = options.width, height = options.height;
  80. var container = options.container, autoFit = options.autoFit, padding = options.padding, appendPadding = options.appendPadding;
  81. // 由于词云图每个词语的坐标都是先通过 DataSet 根据图表宽高计算出来的,
  82. // 也就是说,如果一开始提供给 DataSet 的宽高信息和最终显示的宽高不相同,
  83. // 那么就会出现布局错乱的情况,所以这里处理的目的就是让一开始提供给 DataSet 的
  84. // 宽高信息与最终显示的宽高信息相同,避免显示错乱。
  85. if (autoFit) {
  86. var containerSize = (0, utils_1.getContainerSize)(container);
  87. width = containerSize.width;
  88. height = containerSize.height;
  89. }
  90. // 宽高不能为 0,否则会造成死循环
  91. width = width || 400;
  92. height = height || 400;
  93. var _a = resolvePadding({ padding: padding, appendPadding: appendPadding }), top = _a[0], right = _a[1], bottom = _a[2], left = _a[3];
  94. var result = [width - (left + right), height - (top + bottom)];
  95. return result;
  96. }
  97. exports.getSize = getSize;
  98. /**
  99. * 根据图表的 padding 和 appendPadding 计算出图表的最终 padding
  100. * @param chart
  101. */
  102. function resolvePadding(options) {
  103. var padding = (0, padding_1.normalPadding)(options.padding);
  104. var appendPadding = (0, padding_1.normalPadding)(options.appendPadding);
  105. var top = padding[0] + appendPadding[0];
  106. var right = padding[1] + appendPadding[1];
  107. var bottom = padding[2] + appendPadding[2];
  108. var left = padding[3] + appendPadding[3];
  109. return [top, right, bottom, left];
  110. }
  111. /**
  112. * 处理 imageMask 可能为 url 字符串的情况
  113. * @param {HTMLImageElement | string} img
  114. * @return {Promise}
  115. */
  116. function processImageMask(img) {
  117. return new Promise(function (res, rej) {
  118. if (img instanceof HTMLImageElement) {
  119. res(img);
  120. return;
  121. }
  122. if ((0, util_1.isString)(img)) {
  123. var image_1 = new Image();
  124. image_1.crossOrigin = 'anonymous';
  125. image_1.src = img;
  126. image_1.onload = function () {
  127. res(image_1);
  128. };
  129. image_1.onerror = function () {
  130. (0, utils_1.log)(utils_1.LEVEL.ERROR, false, 'image %s load failed !!!', img);
  131. rej();
  132. };
  133. return;
  134. }
  135. (0, utils_1.log)(utils_1.LEVEL.WARN, img === undefined, 'The type of imageMask option must be String or HTMLImageElement.');
  136. rej();
  137. });
  138. }
  139. exports.processImageMask = processImageMask;
  140. /**
  141. * 把用户提供的 fontSize 值转换成符合 DataSet 要求的值
  142. * @param options
  143. * @param range
  144. */
  145. function getFontSizeMapping(fontSize, range) {
  146. if ((0, util_1.isFunction)(fontSize)) {
  147. return fontSize;
  148. }
  149. if ((0, util_1.isArray)(fontSize)) {
  150. var fMin_1 = fontSize[0], fMax_1 = fontSize[1];
  151. if (!range) {
  152. return function () { return (fMax_1 + fMin_1) / 2; };
  153. }
  154. var min_1 = range[0], max_1 = range[1];
  155. if (max_1 === min_1) {
  156. return function () { return (fMax_1 + fMin_1) / 2; };
  157. }
  158. return function fontSize(_a) {
  159. var value = _a.value;
  160. return ((fMax_1 - fMin_1) / (max_1 - min_1)) * (value - min_1) + fMin_1;
  161. };
  162. }
  163. return function () { return fontSize; };
  164. }
  165. exports.getFontSizeMapping = getFontSizeMapping;
  166. function getSingleKeyValues(data, key) {
  167. return data
  168. .map(function (v) { return v[key]; })
  169. .filter(function (v) {
  170. // 过滤非 number
  171. if (typeof v === 'number' && !isNaN(v))
  172. return true;
  173. return false;
  174. });
  175. }
  176. exports.getSingleKeyValues = getSingleKeyValues;
  177. /**
  178. * 把用户提供的关于旋转角度的字段值转换成符合 DataSet 要求的值
  179. * @param options
  180. */
  181. function getRotate(options) {
  182. var _a = resolveRotate(options), rotation = _a.rotation, rotationSteps = _a.rotationSteps;
  183. if (!(0, util_1.isArray)(rotation))
  184. return rotation;
  185. var min = rotation[0];
  186. var max = rotation[1];
  187. // 等于 1 时不旋转,所以把每份大小设为 0
  188. var perSize = rotationSteps === 1 ? 0 : (max - min) / (rotationSteps - 1);
  189. return function rotate() {
  190. if (max === min)
  191. return max;
  192. return Math.floor(Math.random() * rotationSteps) * perSize;
  193. };
  194. }
  195. /**
  196. * 确保值在要求范围内
  197. * @param options
  198. */
  199. function resolveRotate(options) {
  200. var rotationSteps = options.wordStyle.rotationSteps;
  201. if (rotationSteps < 1) {
  202. (0, utils_1.log)(utils_1.LEVEL.WARN, false, 'The rotationSteps option must be greater than or equal to 1.');
  203. rotationSteps = 1;
  204. }
  205. return {
  206. rotation: options.wordStyle.rotation,
  207. rotationSteps: rotationSteps,
  208. };
  209. }
  210. /**
  211. * 传入一个元素为数字的数组,
  212. * 返回该数组中值最小的数字。
  213. * @param numbers
  214. */
  215. function min(numbers) {
  216. return Math.min.apply(Math, numbers);
  217. }
  218. /**
  219. * 传入一个元素为数字的数组,
  220. * 返回该数组中值最大的数字。
  221. * @param numbers
  222. */
  223. function max(numbers) {
  224. return Math.max.apply(Math, numbers);
  225. }
  226. //# sourceMappingURL=utils.js.map