Skip to content

Commit bd9bc69

Browse files
authored
Move autoSkip related functions to separate file (#8691)
1 parent 1460477 commit bd9bc69

File tree

2 files changed

+173
-163
lines changed

2 files changed

+173
-163
lines changed

src/core/core.scale.autoskip.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import {isNullOrUndef, valueOrDefault} from '../helpers/helpers.core';
2+
import {_factorize} from '../helpers/helpers.math';
3+
4+
5+
/**
6+
* @typedef { import("./core.controller").default } Chart
7+
* @typedef {{value:number | string, label?:string, major?:boolean, $context?:any}} Tick
8+
*/
9+
10+
/**
11+
* Returns a subset of ticks to be plotted to avoid overlapping labels.
12+
* @param {import('./core.scale').default} scale
13+
* @param {Tick[]} ticks
14+
* @return {Tick[]}
15+
* @private
16+
*/
17+
export function autoSkip(scale, ticks) {
18+
const tickOpts = scale.options.ticks;
19+
const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale);
20+
const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
21+
const numMajorIndices = majorIndices.length;
22+
const first = majorIndices[0];
23+
const last = majorIndices[numMajorIndices - 1];
24+
const newTicks = [];
25+
26+
// If there are too many major ticks to display them all
27+
if (numMajorIndices > ticksLimit) {
28+
skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
29+
return newTicks;
30+
}
31+
32+
const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
33+
34+
if (numMajorIndices > 0) {
35+
let i, ilen;
36+
const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
37+
skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
38+
for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
39+
skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
40+
}
41+
skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
42+
return newTicks;
43+
}
44+
skip(ticks, newTicks, spacing);
45+
return newTicks;
46+
}
47+
48+
function determineMaxTicks(scale) {
49+
const offset = scale.options.offset;
50+
const tickLength = scale._tickSize();
51+
const maxScale = scale._length / tickLength + (offset ? 0 : 1);
52+
const maxChart = scale._maxLength / tickLength;
53+
return Math.floor(Math.min(maxScale, maxChart));
54+
}
55+
56+
/**
57+
* @param {number[]} majorIndices
58+
* @param {Tick[]} ticks
59+
* @param {number} ticksLimit
60+
*/
61+
function calculateSpacing(majorIndices, ticks, ticksLimit) {
62+
const evenMajorSpacing = getEvenSpacing(majorIndices);
63+
const spacing = ticks.length / ticksLimit;
64+
65+
// If the major ticks are evenly spaced apart, place the minor ticks
66+
// so that they divide the major ticks into even chunks
67+
if (!evenMajorSpacing) {
68+
return Math.max(spacing, 1);
69+
}
70+
71+
const factors = _factorize(evenMajorSpacing);
72+
for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {
73+
const factor = factors[i];
74+
if (factor > spacing) {
75+
return factor;
76+
}
77+
}
78+
return Math.max(spacing, 1);
79+
}
80+
81+
/**
82+
* @param {Tick[]} ticks
83+
*/
84+
function getMajorIndices(ticks) {
85+
const result = [];
86+
let i, ilen;
87+
for (i = 0, ilen = ticks.length; i < ilen; i++) {
88+
if (ticks[i].major) {
89+
result.push(i);
90+
}
91+
}
92+
return result;
93+
}
94+
95+
/**
96+
* @param {Tick[]} ticks
97+
* @param {Tick[]} newTicks
98+
* @param {number[]} majorIndices
99+
* @param {number} spacing
100+
*/
101+
function skipMajors(ticks, newTicks, majorIndices, spacing) {
102+
let count = 0;
103+
let next = majorIndices[0];
104+
let i;
105+
106+
spacing = Math.ceil(spacing);
107+
for (i = 0; i < ticks.length; i++) {
108+
if (i === next) {
109+
newTicks.push(ticks[i]);
110+
count++;
111+
next = majorIndices[count * spacing];
112+
}
113+
}
114+
}
115+
116+
/**
117+
* @param {Tick[]} ticks
118+
* @param {Tick[]} newTicks
119+
* @param {number} spacing
120+
* @param {number} [majorStart]
121+
* @param {number} [majorEnd]
122+
*/
123+
function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
124+
const start = valueOrDefault(majorStart, 0);
125+
const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
126+
let count = 0;
127+
let length, i, next;
128+
129+
spacing = Math.ceil(spacing);
130+
if (majorEnd) {
131+
length = majorEnd - majorStart;
132+
spacing = length / Math.floor(length / spacing);
133+
}
134+
135+
next = start;
136+
137+
while (next < 0) {
138+
count++;
139+
next = Math.round(start + count * spacing);
140+
}
141+
142+
for (i = Math.max(start, 0); i < end; i++) {
143+
if (i === next) {
144+
newTicks.push(ticks[i]);
145+
count++;
146+
next = Math.round(start + count * spacing);
147+
}
148+
}
149+
}
150+
151+
152+
/**
153+
* @param {number[]} arr
154+
*/
155+
function getEvenSpacing(arr) {
156+
const len = arr.length;
157+
let i, diff;
158+
159+
if (len < 2) {
160+
return false;
161+
}
162+
163+
for (diff = arr[0], i = 1; i < len; ++i) {
164+
if (arr[i] - arr[i - 1] !== diff) {
165+
return false;
166+
}
167+
}
168+
return diff;
169+
}

src/core/core.scale.js

Lines changed: 4 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import defaults from './core.defaults';
22
import Element from './core.element';
33
import {_alignPixel, _measureText, renderText, clipArea, unclipArea} from '../helpers/helpers.canvas';
4-
import {callback as call, each, finiteOrDefault, isArray, isFinite, isNullOrUndef, isObject, valueOrDefault} from '../helpers/helpers.core';
5-
import {_factorize, toDegrees, toRadians, _int16Range, _limitValue, HALF_PI} from '../helpers/helpers.math';
4+
import {callback as call, each, finiteOrDefault, isArray, isFinite, isNullOrUndef, isObject} from '../helpers/helpers.core';
5+
import {toDegrees, toRadians, _int16Range, _limitValue, HALF_PI} from '../helpers/helpers.math';
66
import {_alignStartEnd, _toLeftRightCenter} from '../helpers/helpers.extras';
77
import {toFont, toPadding} from '../helpers/helpers.options';
88
import Ticks from './core.ticks';
9+
import {autoSkip} from './core.scale.autoskip';
910

1011
const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align;
1112
const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
@@ -192,128 +193,6 @@ function getTitleHeight(options, fallback) {
192193
return (lines * font.lineHeight) + padding.height;
193194
}
194195

195-
function determineMaxTicks(scale) {
196-
const offset = scale.options.offset;
197-
const tickLength = scale._tickSize();
198-
const maxScale = scale._length / tickLength + (offset ? 0 : 1);
199-
const maxChart = scale._maxLength / tickLength;
200-
return Math.floor(Math.min(maxScale, maxChart));
201-
}
202-
203-
/**
204-
* @param {number[]} arr
205-
*/
206-
function getEvenSpacing(arr) {
207-
const len = arr.length;
208-
let i, diff;
209-
210-
if (len < 2) {
211-
return false;
212-
}
213-
214-
for (diff = arr[0], i = 1; i < len; ++i) {
215-
if (arr[i] - arr[i - 1] !== diff) {
216-
return false;
217-
}
218-
}
219-
return diff;
220-
}
221-
222-
/**
223-
* @param {number[]} majorIndices
224-
* @param {Tick[]} ticks
225-
* @param {number} ticksLimit
226-
*/
227-
function calculateSpacing(majorIndices, ticks, ticksLimit) {
228-
const evenMajorSpacing = getEvenSpacing(majorIndices);
229-
const spacing = ticks.length / ticksLimit;
230-
231-
// If the major ticks are evenly spaced apart, place the minor ticks
232-
// so that they divide the major ticks into even chunks
233-
if (!evenMajorSpacing) {
234-
return Math.max(spacing, 1);
235-
}
236-
237-
const factors = _factorize(evenMajorSpacing);
238-
for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {
239-
const factor = factors[i];
240-
if (factor > spacing) {
241-
return factor;
242-
}
243-
}
244-
return Math.max(spacing, 1);
245-
}
246-
247-
/**
248-
* @param {Tick[]} ticks
249-
*/
250-
function getMajorIndices(ticks) {
251-
const result = [];
252-
let i, ilen;
253-
for (i = 0, ilen = ticks.length; i < ilen; i++) {
254-
if (ticks[i].major) {
255-
result.push(i);
256-
}
257-
}
258-
return result;
259-
}
260-
261-
/**
262-
* @param {Tick[]} ticks
263-
* @param {Tick[]} newTicks
264-
* @param {number[]} majorIndices
265-
* @param {number} spacing
266-
*/
267-
function skipMajors(ticks, newTicks, majorIndices, spacing) {
268-
let count = 0;
269-
let next = majorIndices[0];
270-
let i;
271-
272-
spacing = Math.ceil(spacing);
273-
for (i = 0; i < ticks.length; i++) {
274-
if (i === next) {
275-
newTicks.push(ticks[i]);
276-
count++;
277-
next = majorIndices[count * spacing];
278-
}
279-
}
280-
}
281-
282-
/**
283-
* @param {Tick[]} ticks
284-
* @param {Tick[]} newTicks
285-
* @param {number} spacing
286-
* @param {number} [majorStart]
287-
* @param {number} [majorEnd]
288-
*/
289-
function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
290-
const start = valueOrDefault(majorStart, 0);
291-
const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
292-
let count = 0;
293-
let length, i, next;
294-
295-
spacing = Math.ceil(spacing);
296-
if (majorEnd) {
297-
length = majorEnd - majorStart;
298-
spacing = length / Math.floor(length / spacing);
299-
}
300-
301-
next = start;
302-
303-
while (next < 0) {
304-
count++;
305-
next = Math.round(start + count * spacing);
306-
}
307-
308-
for (i = Math.max(start, 0); i < end; i++) {
309-
if (i === next) {
310-
newTicks.push(ticks[i]);
311-
count++;
312-
next = Math.round(start + count * spacing);
313-
}
314-
}
315-
}
316-
317196
function createScaleContext(parent, scale) {
318197
return Object.assign(Object.create(parent), {
319198
scale,
@@ -635,7 +514,7 @@ export default class Scale extends Element {
635514

636515
// Auto-skip
637516
if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
638-
me.ticks = me._autoSkip(me.ticks);
517+
me.ticks = autoSkip(me, me.ticks);
639518
me._labelSizes = null;
640519
}
641520

@@ -1149,44 +1028,6 @@ export default class Scale extends Element {
11491028
(me.$context = createScaleContext(me.chart.getContext(), me));
11501029
}
11511030

1152-
/**
1153-
* Returns a subset of ticks to be plotted to avoid overlapping labels.
1154-
* @param {Tick[]} ticks
1155-
* @return {Tick[]}
1156-
* @private
1157-
*/
1158-
_autoSkip(ticks) {
1159-
const me = this;
1160-
const tickOpts = me.options.ticks;
1161-
const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(me);
1162-
const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
1163-
const numMajorIndices = majorIndices.length;
1164-
const first = majorIndices[0];
1165-
const last = majorIndices[numMajorIndices - 1];
1166-
const newTicks = [];
1167-
1168-
// If there are too many major ticks to display them all
1169-
if (numMajorIndices > ticksLimit) {
1170-
skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
1171-
return newTicks;
1172-
}
1173-
1174-
const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
1175-
1176-
if (numMajorIndices > 0) {
1177-
let i, ilen;
1178-
const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
1179-
skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
1180-
for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
1181-
skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
1182-
}
1183-
skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
1184-
return newTicks;
1185-
}
1186-
skip(ticks, newTicks, spacing);
1187-
return newTicks;
1188-
}
1189-
11901031
/**
11911032
* @return {number}
11921033
* @private

0 commit comments

Comments
 (0)