util.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { __assign } from "tslib";
  2. import { get, isArray, isNumber } from '@antv/util';
  3. import { regressionExp, regressionLinear, regressionLoess, regressionLog, regressionPoly, regressionPow, regressionQuad, } from 'd3-regression';
  4. import { getSplinePath } from '../../utils';
  5. var REGRESSION_MAP = {
  6. exp: regressionExp,
  7. linear: regressionLinear,
  8. loess: regressionLoess,
  9. log: regressionLog,
  10. poly: regressionPoly,
  11. pow: regressionPow,
  12. quad: regressionQuad,
  13. };
  14. /**
  15. * 获取四象限默认配置
  16. * @param {number} xBaseline
  17. * @param {number} yBaseline
  18. */
  19. export function getQuadrantDefaultConfig(xBaseline, yBaseline) {
  20. // 文本便宜距离
  21. var textOffset = 10;
  22. // 四象限默认样式
  23. var defaultConfig = {
  24. regionStyle: [
  25. {
  26. position: {
  27. start: [xBaseline, 'max'],
  28. end: ['max', yBaseline],
  29. },
  30. style: {
  31. fill: '#d8d0c0',
  32. opacity: 0.4,
  33. },
  34. },
  35. {
  36. position: {
  37. start: ['min', 'max'],
  38. end: [xBaseline, yBaseline],
  39. },
  40. style: {
  41. fill: '#a3dda1',
  42. opacity: 0.4,
  43. },
  44. },
  45. {
  46. position: {
  47. start: ['min', yBaseline],
  48. end: [xBaseline, 'min'],
  49. },
  50. style: {
  51. fill: '#d8d0c0',
  52. opacity: 0.4,
  53. },
  54. },
  55. {
  56. position: {
  57. start: [xBaseline, yBaseline],
  58. end: ['max', 'min'],
  59. },
  60. style: {
  61. fill: '#a3dda1',
  62. opacity: 0.4,
  63. },
  64. },
  65. ],
  66. lineStyle: {
  67. stroke: '#9ba29a',
  68. lineWidth: 1,
  69. },
  70. labelStyle: [
  71. {
  72. position: ['max', yBaseline],
  73. offsetX: -textOffset,
  74. offsetY: -textOffset,
  75. style: {
  76. textAlign: 'right',
  77. textBaseline: 'bottom',
  78. fontSize: 14,
  79. fill: '#ccc',
  80. },
  81. },
  82. {
  83. position: ['min', yBaseline],
  84. offsetX: textOffset,
  85. offsetY: -textOffset,
  86. style: {
  87. textAlign: 'left',
  88. textBaseline: 'bottom',
  89. fontSize: 14,
  90. fill: '#ccc',
  91. },
  92. },
  93. {
  94. position: ['min', yBaseline],
  95. offsetX: textOffset,
  96. offsetY: textOffset,
  97. style: {
  98. textAlign: 'left',
  99. textBaseline: 'top',
  100. fontSize: 14,
  101. fill: '#ccc',
  102. },
  103. },
  104. {
  105. position: ['max', yBaseline],
  106. offsetX: -textOffset,
  107. offsetY: textOffset,
  108. style: {
  109. textAlign: 'right',
  110. textBaseline: 'top',
  111. fontSize: 14,
  112. fill: '#ccc',
  113. },
  114. },
  115. ],
  116. };
  117. return defaultConfig;
  118. }
  119. var splinePath = function (data, config) {
  120. var view = config.view, _a = config.options, xField = _a.xField, yField = _a.yField;
  121. var xScaleView = view.getScaleByField(xField);
  122. var yScaleView = view.getScaleByField(yField);
  123. var pathData = data.map(function (d) {
  124. return view.getCoordinate().convert({ x: xScaleView.scale(d[0]), y: yScaleView.scale(d[1]) });
  125. });
  126. return getSplinePath(pathData, false);
  127. };
  128. export var getPath = function (config) {
  129. var options = config.options;
  130. var xField = options.xField, yField = options.yField, data = options.data, regressionLine = options.regressionLine;
  131. var _a = regressionLine.type, type = _a === void 0 ? 'linear' : _a, algorithm = regressionLine.algorithm, customEquation = regressionLine.equation;
  132. var pathData;
  133. var equation = null;
  134. if (algorithm) {
  135. pathData = isArray(algorithm) ? algorithm : algorithm(data);
  136. equation = customEquation;
  137. }
  138. else {
  139. var reg = REGRESSION_MAP[type]()
  140. .x(function (d) { return d[xField]; })
  141. .y(function (d) { return d[yField]; });
  142. pathData = reg(data);
  143. equation = getRegressionEquation(type, pathData);
  144. }
  145. return [splinePath(pathData, config), equation];
  146. };
  147. /**
  148. * 调整散点图 meta: { min, max } ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等
  149. * @param options
  150. * @returns
  151. */
  152. export var getMeta = function (options) {
  153. var _a;
  154. var _b = options.meta, meta = _b === void 0 ? {} : _b, xField = options.xField, yField = options.yField, data = options.data;
  155. var xFieldValue = data[0][xField];
  156. var yFieldValue = data[0][yField];
  157. var xIsPositiveNumber = xFieldValue > 0;
  158. var yIsPositiveNumber = yFieldValue > 0;
  159. /**
  160. * 获得对应字段的 min max scale 配置
  161. */
  162. function getMetaMinMax(field, axis) {
  163. var fieldMeta = get(meta, [field]);
  164. function getCustomValue(type) {
  165. return get(fieldMeta, type);
  166. }
  167. var range = {};
  168. if (axis === 'x') {
  169. if (isNumber(xFieldValue)) {
  170. if (!isNumber(getCustomValue('min'))) {
  171. range['min'] = xIsPositiveNumber ? 0 : xFieldValue * 2;
  172. }
  173. if (!isNumber(getCustomValue('max'))) {
  174. range['max'] = xIsPositiveNumber ? xFieldValue * 2 : 0;
  175. }
  176. }
  177. return range;
  178. }
  179. if (isNumber(yFieldValue)) {
  180. if (!isNumber(getCustomValue('min'))) {
  181. range['min'] = yIsPositiveNumber ? 0 : yFieldValue * 2;
  182. }
  183. if (!isNumber(getCustomValue('max'))) {
  184. range['max'] = yIsPositiveNumber ? yFieldValue * 2 : 0;
  185. }
  186. }
  187. return range;
  188. }
  189. return __assign(__assign({}, meta), (_a = {}, _a[xField] = __assign(__assign({}, meta[xField]), getMetaMinMax(xField, 'x')), _a[yField] = __assign(__assign({}, meta[yField]), getMetaMinMax(yField, 'y')), _a));
  190. };
  191. /**
  192. * 获取回归函数表达式
  193. * @param {string} type - 回归函数类型
  194. * @param {D3RegressionResult} res - 回归计算结果集
  195. * @return {string}
  196. */
  197. export function getRegressionEquation(type, res) {
  198. var _a, _b, _c;
  199. var roundByPrecision = function (n, p) {
  200. if (p === void 0) { p = 4; }
  201. return Math.round(n * Math.pow(10, p)) / Math.pow(10, p);
  202. };
  203. var safeFormat = function (value) { return (Number.isFinite(value) ? roundByPrecision(value) : '?'); };
  204. switch (type) {
  205. case 'linear':
  206. // y = ax + b
  207. return "y = ".concat(safeFormat(res.a), "x + ").concat(safeFormat(res.b), ", R^2 = ").concat(safeFormat(res.rSquared));
  208. case 'exp':
  209. // y = ae^(bx)
  210. return "y = ".concat(safeFormat(res.a), "e^(").concat(safeFormat(res.b), "x), R^2 = ").concat(safeFormat(res.rSquared));
  211. case 'log':
  212. // y = a · ln(x) + b
  213. return "y = ".concat(safeFormat(res.a), "ln(x) + ").concat(safeFormat(res.b), ", R^2 = ").concat(safeFormat(res.rSquared));
  214. case 'quad':
  215. // y = ax^2 + bx + c
  216. return "y = ".concat(safeFormat(res.a), "x^2 + ").concat(safeFormat(res.b), "x + ").concat(safeFormat(res.c), ", R^2 = ").concat(safeFormat(res.rSquared));
  217. case 'poly':
  218. // y = anx^n + ... + a1x + a0
  219. // eslint-disable-next-line no-case-declarations
  220. var temp = "y = ".concat(safeFormat((_a = res.coefficients) === null || _a === void 0 ? void 0 : _a[0]), " + ").concat(safeFormat((_b = res.coefficients) === null || _b === void 0 ? void 0 : _b[1]), "x + ").concat(safeFormat((_c = res.coefficients) === null || _c === void 0 ? void 0 : _c[2]), "x^2");
  221. for (var i = 3; i < res.coefficients.length; ++i) {
  222. temp += " + ".concat(safeFormat(res.coefficients[i]), "x^").concat(i);
  223. }
  224. return "".concat(temp, ", R^2 = ").concat(safeFormat(res.rSquared));
  225. case 'pow':
  226. // y = ax^b
  227. return "y = ".concat(safeFormat(res.a), "x^").concat(safeFormat(res.b), ", R^2 = ").concat(safeFormat(res.rSquared));
  228. }
  229. return null;
  230. }
  231. //# sourceMappingURL=util.js.map