1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.wilkinsonExtended = exports.ALL_Q = exports.DEFAULT_Q = void 0;
|
4 | const util_1 = require("@antv/util");
|
5 | const pretty_number_1 = require("../utils/pretty-number");
|
6 | exports.DEFAULT_Q = [1, 5, 2, 2.5, 4, 3];
|
7 | exports.ALL_Q = [1, 5, 2, 2.5, 4, 3, 1.5, 7, 6, 8, 9];
|
8 | const eps = Number.EPSILON * 100;
|
9 | function mod(n, m) {
|
10 | return ((n % m) + m) % m;
|
11 | }
|
12 | function round(n) {
|
13 | return Math.round(n * 1e12) / 1e12;
|
14 | }
|
15 | function simplicity(q, Q, j, lmin, lmax, lstep) {
|
16 | const n = (0, util_1.size)(Q);
|
17 | const i = (0, util_1.indexOf)(Q, q);
|
18 | let v = 0;
|
19 | const m = mod(lmin, lstep);
|
20 | if ((m < eps || lstep - m < eps) && lmin <= 0 && lmax >= 0) {
|
21 | v = 1;
|
22 | }
|
23 | return 1 - i / (n - 1) - j + v;
|
24 | }
|
25 | function simplicityMax(q, Q, j) {
|
26 | const n = (0, util_1.size)(Q);
|
27 | const i = (0, util_1.indexOf)(Q, q);
|
28 | const v = 1;
|
29 | return 1 - i / (n - 1) - j + v;
|
30 | }
|
31 | function density(k, m, dMin, dMax, lMin, lMax) {
|
32 | const r = (k - 1) / (lMax - lMin);
|
33 | const rt = (m - 1) / (Math.max(lMax, dMax) - Math.min(dMin, lMin));
|
34 | return 2 - Math.max(r / rt, rt / r);
|
35 | }
|
36 | function densityMax(k, m) {
|
37 | if (k >= m) {
|
38 | return 2 - (k - 1) / (m - 1);
|
39 | }
|
40 | return 1;
|
41 | }
|
42 | function coverage(dMin, dMax, lMin, lMax) {
|
43 | const range = dMax - dMin;
|
44 | return 1 - (0.5 * ((dMax - lMax) ** 2 + (dMin - lMin) ** 2)) / (0.1 * range) ** 2;
|
45 | }
|
46 | function coverageMax(dMin, dMax, span) {
|
47 | const range = dMax - dMin;
|
48 | if (span > range) {
|
49 | const half = (span - range) / 2;
|
50 | return 1 - half ** 2 / (0.1 * range) ** 2;
|
51 | }
|
52 | return 1;
|
53 | }
|
54 | function legibility() {
|
55 | return 1;
|
56 | }
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | const wilkinsonExtended = (dMin, dMax, n = 5, onlyLoose = true, Q = exports.DEFAULT_Q, w = [0.25, 0.2, 0.5, 0.05]) => {
|
68 | const m = n < 0 ? 0 : Math.round(n);
|
69 |
|
70 | if (Number.isNaN(dMin) || Number.isNaN(dMax) || typeof dMin !== 'number' || typeof dMax !== 'number' || !m) {
|
71 | return [];
|
72 | }
|
73 |
|
74 | if (dMax - dMin < 1e-15 || m === 1) {
|
75 | return [dMin];
|
76 | }
|
77 | const best = {
|
78 | score: -2,
|
79 | lmin: 0,
|
80 | lmax: 0,
|
81 | lstep: 0,
|
82 | };
|
83 | let j = 1;
|
84 | while (j < Infinity) {
|
85 |
|
86 | for (let i = 0; i < Q.length; i += 1) {
|
87 | const q = Q[i];
|
88 | const sm = simplicityMax(q, Q, j);
|
89 | if (w[0] * sm + w[1] + w[2] + w[3] < best.score) {
|
90 | j = Infinity;
|
91 | break;
|
92 | }
|
93 | let k = 2;
|
94 | while (k < Infinity) {
|
95 | const dm = densityMax(k, m);
|
96 | if (w[0] * sm + w[1] + w[2] * dm + w[3] < best.score) {
|
97 | break;
|
98 | }
|
99 | const delta = (dMax - dMin) / (k + 1) / j / q;
|
100 | let z = Math.ceil(Math.log10(delta));
|
101 | while (z < Infinity) {
|
102 | const step = j * q * 10 ** z;
|
103 | const cm = coverageMax(dMin, dMax, step * (k - 1));
|
104 | if (w[0] * sm + w[1] * cm + w[2] * dm + w[3] < best.score) {
|
105 | break;
|
106 | }
|
107 | const minStart = Math.floor(dMax / step) * j - (k - 1) * j;
|
108 | const maxStart = Math.ceil(dMin / step) * j;
|
109 | if (minStart <= maxStart) {
|
110 | const count = maxStart - minStart;
|
111 | for (let i = 0; i <= count; i += 1) {
|
112 | const start = minStart + i;
|
113 | const lMin = start * (step / j);
|
114 | const lMax = lMin + step * (k - 1);
|
115 | const lStep = step;
|
116 | const s = simplicity(q, Q, j, lMin, lMax, lStep);
|
117 | const c = coverage(dMin, dMax, lMin, lMax);
|
118 | const g = density(k, m, dMin, dMax, lMin, lMax);
|
119 | const l = legibility();
|
120 | const score = w[0] * s + w[1] * c + w[2] * g + w[3] * l;
|
121 | if (score > best.score && (!onlyLoose || (lMin <= dMin && lMax >= dMax))) {
|
122 | best.lmin = lMin;
|
123 | best.lmax = lMax;
|
124 | best.lstep = lStep;
|
125 | best.score = score;
|
126 | }
|
127 | }
|
128 | }
|
129 | z += 1;
|
130 | }
|
131 | k += 1;
|
132 | }
|
133 | }
|
134 | j += 1;
|
135 | }
|
136 |
|
137 | const lmax = (0, pretty_number_1.prettyNumber)(best.lmax);
|
138 | const lmin = (0, pretty_number_1.prettyNumber)(best.lmin);
|
139 | const lstep = (0, pretty_number_1.prettyNumber)(best.lstep);
|
140 |
|
141 |
|
142 | const tickCount = Math.floor(round((lmax - lmin) / lstep)) + 1;
|
143 | const ticks = new Array(tickCount);
|
144 |
|
145 | ticks[0] = (0, pretty_number_1.prettyNumber)(lmin);
|
146 | for (let i = 1; i < tickCount; i += 1) {
|
147 | ticks[i] = (0, pretty_number_1.prettyNumber)(ticks[i - 1] + lstep);
|
148 | }
|
149 | return ticks;
|
150 | };
|
151 | exports.wilkinsonExtended = wilkinsonExtended;
|
152 |
|
\ | No newline at end of file |