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