UNPKG

5.49 kBJavaScriptView Raw
1import { head, indexOf, size, last } from '@antv/util';
2export var DEFAULT_Q = [1, 5, 2, 2.5, 4, 3];
3export var ALL_Q = [1, 5, 2, 2.5, 4, 3, 1.5, 7, 6, 8, 9];
4var eps = Number.EPSILON * 100;
5function mod(n, m) {
6 return ((n % m) + m) % m;
7}
8function simplicity(q, Q, j, lmin, lmax, lstep) {
9 var n = size(Q);
10 var i = indexOf(Q, q);
11 var v = 0;
12 var m = mod(lmin, lstep);
13 if ((m < eps || lstep - m < eps) && lmin <= 0 && lmax >= 0) {
14 v = 1;
15 }
16 return 1 - i / (n - 1) - j + v;
17}
18function simplicityMax(q, Q, j) {
19 var n = size(Q);
20 var i = indexOf(Q, q);
21 var v = 1;
22 return 1 - i / (n - 1) - j + v;
23}
24function density(k, m, dMin, dMax, lMin, lMax) {
25 var r = (k - 1) / (lMax - lMin);
26 var rt = (m - 1) / (Math.max(lMax, dMax) - Math.min(dMin, lMin));
27 return 2 - Math.max(r / rt, rt / r);
28}
29function densityMax(k, m) {
30 if (k >= m) {
31 return 2 - (k - 1) / (m - 1);
32 }
33 return 1;
34}
35function coverage(dMin, dMax, lMin, lMax) {
36 var range = dMax - dMin;
37 return 1 - (0.5 * (Math.pow((dMax - lMax), 2) + Math.pow((dMin - lMin), 2))) / Math.pow((0.1 * range), 2);
38}
39function coverageMax(dMin, dMax, span) {
40 var range = dMax - dMin;
41 if (span > range) {
42 var half = (span - range) / 2;
43 return 1 - Math.pow(half, 2) / Math.pow((0.1 * range), 2);
44 }
45 return 1;
46}
47function legibility() {
48 return 1;
49}
50// 解决 js 计算精度问题
51function prettyNumber(n) {
52 return n < 1e-15 ? n : parseFloat(n.toFixed(15));
53}
54/**
55 * An Extension of Wilkinson's Algorithm for Position Tick Labels on Axes
56 * https://www.yuque.com/preview/yuque/0/2019/pdf/185317/1546999150858-45c3b9c2-4e86-4223-bf1a-8a732e8195ed.pdf
57 * @param dMin 最小值
58 * @param dMax 最大值
59 * @param m tick个数
60 * @param onlyLoose 是否允许扩展min、max,不绝对强制,例如[3, 97]
61 * @param Q nice numbers集合
62 * @param w 四个优化组件的权重
63 */
64export default function extended(dMin, dMax, m, onlyLoose, Q, w) {
65 if (m === void 0) { m = 5; }
66 if (onlyLoose === void 0) { onlyLoose = true; }
67 if (Q === void 0) { Q = DEFAULT_Q; }
68 if (w === void 0) { w = [0.25, 0.2, 0.5, 0.05]; }
69 // nan 也会导致异常
70 if (Number.isNaN(dMin) || Number.isNaN(dMax) || typeof dMin !== 'number' || typeof dMax !== 'number' || !m) {
71 return {
72 min: 0,
73 max: 0,
74 ticks: [],
75 };
76 }
77 // js 极大值极小值问题,差值小于 1e-15 会导致计算出错
78 if (dMax - dMin < 1e-15 || m === 1) {
79 return {
80 min: dMin,
81 max: dMax,
82 ticks: [dMin],
83 };
84 }
85 var best = {
86 score: -2,
87 lmin: 0,
88 lmax: 0,
89 lstep: 0,
90 };
91 var j = 1;
92 while (j < Infinity) {
93 for (var i = 0; i < Q.length; i += 1) {
94 var q = Q[i];
95 var sm = simplicityMax(q, Q, j);
96 if (w[0] * sm + w[1] + w[2] + w[3] < best.score) {
97 j = Infinity;
98 break;
99 }
100 var k = 2;
101 while (k < Infinity) {
102 var dm = densityMax(k, m);
103 if (w[0] * sm + w[1] + w[2] * dm + w[3] < best.score) {
104 break;
105 }
106 var delta = (dMax - dMin) / (k + 1) / j / q;
107 var z = Math.ceil(Math.log10(delta));
108 while (z < Infinity) {
109 var step = j * q * Math.pow(10, z);
110 var cm = coverageMax(dMin, dMax, step * (k - 1));
111 if (w[0] * sm + w[1] * cm + w[2] * dm + w[3] < best.score) {
112 break;
113 }
114 var minStart = Math.floor(dMax / step) * j - (k - 1) * j;
115 var maxStart = Math.ceil(dMin / step) * j;
116 if (minStart <= maxStart) {
117 var count = maxStart - minStart;
118 for (var i_1 = 0; i_1 <= count; i_1 += 1) {
119 var start = minStart + i_1;
120 var lMin = start * (step / j);
121 var lMax = lMin + step * (k - 1);
122 var lStep = step;
123 var s = simplicity(q, Q, j, lMin, lMax, lStep);
124 var c = coverage(dMin, dMax, lMin, lMax);
125 var g = density(k, m, dMin, dMax, lMin, lMax);
126 var l = legibility();
127 var score = w[0] * s + w[1] * c + w[2] * g + w[3] * l;
128 if (score > best.score && (!onlyLoose || (lMin <= dMin && lMax >= dMax))) {
129 best.lmin = lMin;
130 best.lmax = lMax;
131 best.lstep = lStep;
132 best.score = score;
133 }
134 }
135 }
136 z += 1;
137 }
138 k += 1;
139 }
140 }
141 j += 1;
142 }
143 var lmax = best.lmax, lmin = best.lmin, lstep = best.lstep;
144 var tickCount = Math.floor((lmax - lmin) / lstep) + 1;
145 var ticks = new Array(tickCount);
146 for (var i = 0; i < tickCount; i++) {
147 ticks[i] = prettyNumber(lmin + i * lstep);
148 }
149 return {
150 min: Math.min(dMin, head(ticks)),
151 max: Math.max(dMax, last(ticks)),
152 ticks: ticks,
153 };
154}
155//# sourceMappingURL=extended.js.map
\No newline at end of file