Skip to content

Commit 9f2e427

Browse files
authored
feat(scales): add LinearBinary scale type (#1389)
1 parent 6517523 commit 9f2e427

14 files changed

Lines changed: 262 additions & 8 deletions

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ module.exports = {
8989
'jsx-a11y/no-static-element-interactions': 1,
9090
'jsx-a11y/mouse-events-have-key-events': 1,
9191
'jsx-a11y/click-events-have-key-events': 1,
92-
'@typescript-eslint/member-ordering': 1,
92+
'@typescript-eslint/member-ordering': 0,
9393
eqeqeq: 2,
9494

9595
/*

NOTICE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,27 @@ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
4141
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
4242
THIS SOFTWARE.
4343

44+
---
45+
46+
This product includes code that is adapted from d3-array@3.0.4 and d3-scale@4.0.2,
47+
which are both available under a "ISC" license.
48+
49+
ISC License
50+
51+
Copyright 2010-2021 Mike Bostock
52+
53+
Permission to use, copy, modify, and/or distribute this software for any purpose
54+
with or without fee is hereby granted, provided that the above copyright notice
55+
and this permission notice appear in all copies.
56+
57+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
58+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
59+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
60+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
61+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
62+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
63+
THIS SOFTWARE.
64+
4465
---
4566
This product includes code that is adapted from https://github.com/Myndex/SAPC-APCA
4667
which is available under a "W3C SOFTWARE NOTICE AND LICENSE" license.
Loading
Loading
26.5 KB
Loading

integration/tests/scales_stories.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ describe('Scales stories', () => {
3838
);
3939
});
4040
});
41+
it('should render linear binary with nicing', async () => {
42+
await common.expectChartAtUrlToMatchScreenshot(
43+
`http://localhost:9001/?path=/story/scales--linear-binary&globals=theme:light&knob-Data type=Base 2&knob-yScaleType=linear_binary&knob-Nice y ticks=true`,
44+
);
45+
});
4146
});

packages/charts/api/charts.api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1701,7 +1701,7 @@ export type Rotation = 0 | 90 | -90 | 180;
17011701
export type ScaleBandType = ScaleOrdinalType;
17021702

17031703
// @public (undocumented)
1704-
export type ScaleContinuousType = typeof ScaleType.Linear | typeof ScaleType.Time | typeof ScaleType.Log | typeof ScaleType.Sqrt;
1704+
export type ScaleContinuousType = typeof ScaleType.LinearBinary | typeof ScaleType.Linear | typeof ScaleType.Time | typeof ScaleType.Log | typeof ScaleType.Sqrt;
17051705

17061706
// @public (undocumented)
17071707
export type ScaleOrdinalType = typeof ScaleType.Ordinal;
@@ -1714,6 +1714,7 @@ export interface ScalesConfig {
17141714

17151715
// @public
17161716
export const ScaleType: Readonly<{
1717+
LinearBinary: "linear_binary";
17171718
Linear: "linear";
17181719
Ordinal: "ordinal";
17191720
Log: "log";

packages/charts/src/chart_types/xy_chart/utils/fill_series.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export function fillSeries(
6464

6565
function isXFillNotRequired(spec: BasicSeriesSpec, groupScaleType: ScaleType, isStacked: boolean) {
6666
const onlyNoFitAreaLine = (isAreaSeriesSpec(spec) || isLineSeriesSpec(spec)) && !spec.fit;
67-
const onlyContinuous = groupScaleType === ScaleType.Linear || groupScaleType === ScaleType.Time;
67+
const onlyContinuous =
68+
groupScaleType === ScaleType.Linear ||
69+
groupScaleType === ScaleType.LinearBinary ||
70+
groupScaleType === ScaleType.Time;
6871
return onlyNoFitAreaLine && onlyContinuous && !isStacked;
6972
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* eslint-disable header/header, no-param-reassign */
2+
3+
/**
4+
* @notice
5+
* This product includes code that is adapted from d3-array@3.0.4 and d3-scale@4.0.2,
6+
* which are both available under a "ISC" license.
7+
*
8+
* ISC License
9+
*
10+
* Copyright 2010-2021 Mike Bostock
11+
* Permission to use, copy, modify, and/or distribute this software for any purpose
12+
* with or without fee is hereby granted, provided that the above copyright notice
13+
* and this permission notice appear in all copies.
14+
15+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
16+
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17+
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
18+
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19+
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20+
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
21+
* THIS SOFTWARE.
22+
*/
23+
24+
import { ScaleContinuousNumeric } from 'd3-scale';
25+
26+
import { PrimitiveValue } from '../../partition_chart/layout/utils/group_by_rollup';
27+
28+
const e10 = Math.sqrt(50);
29+
const e5 = Math.sqrt(10);
30+
const e2 = Math.sqrt(2);
31+
32+
/** @internal */
33+
export function getLinearTicks(start: number, stop: number, count: number, base: number = 2) {
34+
let reverse,
35+
i = -1,
36+
n,
37+
ticks,
38+
step;
39+
40+
stop = +stop;
41+
start = +start;
42+
count = +count;
43+
if (start === stop && count > 0) return [start];
44+
if ((reverse = stop < start)) {
45+
n = start;
46+
start = stop;
47+
stop = n;
48+
}
49+
if ((step = tickIncrement(start, stop, count, base)) === 0 || !isFinite(step)) return [];
50+
51+
if (step > 0) {
52+
let r0 = Math.round(start / step),
53+
r1 = Math.round(stop / step);
54+
if (r0 * step < start) ++r0;
55+
if (r1 * step > stop) --r1;
56+
ticks = new Array((n = r1 - r0 + 1));
57+
while (++i < n) ticks[i] = (r0 + i) * step;
58+
} else {
59+
step = -step;
60+
let r0 = Math.round(start * step),
61+
r1 = Math.round(stop * step);
62+
if (r0 / step < start) ++r0;
63+
if (r1 / step > stop) --r1;
64+
ticks = new Array((n = r1 - r0 + 1));
65+
while (++i < n) ticks[i] = (r0 + i) / step;
66+
}
67+
68+
if (reverse) ticks.reverse();
69+
70+
return ticks;
71+
}
72+
73+
function tickIncrement(start: number, stop: number, count: number, base: number = 10) {
74+
const step = (stop - start) / Math.max(0, count);
75+
const power = Math.floor(Math.log(step) / Math.log(base) + Number.EPSILON);
76+
const error = step / Math.pow(base, power);
77+
return power >= 0
78+
? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(base, power)
79+
: -Math.pow(base, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
80+
}
81+
82+
/** @internal */
83+
export function getNiceLinearTicks(
84+
scale: ScaleContinuousNumeric<PrimitiveValue, number>,
85+
count: number = 10,
86+
base = 10,
87+
) {
88+
const d = scale.domain();
89+
let i0 = 0;
90+
let i1 = d.length - 1;
91+
let start = d[i0];
92+
let stop = d[i1];
93+
let prestep;
94+
let step;
95+
let maxIter = 10;
96+
97+
if (stop < start) {
98+
step = start;
99+
start = stop;
100+
stop = step;
101+
102+
step = i0;
103+
i0 = i1;
104+
i1 = step;
105+
}
106+
107+
while (maxIter-- > 0) {
108+
step = tickIncrement(start, stop, count, base);
109+
if (step === prestep) {
110+
d[i0] = start;
111+
d[i1] = stop;
112+
return scale.domain(d);
113+
} else if (step > 0) {
114+
start = Math.floor(start / step) * step;
115+
stop = Math.ceil(stop / step) * step;
116+
} else if (step < 0) {
117+
start = Math.ceil(start * step) / step;
118+
stop = Math.floor(stop * step) / step;
119+
} else {
120+
break;
121+
}
122+
prestep = step;
123+
}
124+
125+
return scale;
126+
}
127+
128+
/* eslint-enable header/header, no-param-reassign */

packages/charts/src/scales/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import { $Values } from 'utility-types';
1313
* @public
1414
*/
1515
export const ScaleType = Object.freeze({
16+
/**
17+
* Treated as linear scale with ticks in base 2
18+
*/
19+
LinearBinary: 'linear_binary' as const,
1620
Linear: 'linear' as const,
1721
Ordinal: 'ordinal' as const,
1822
Log: 'log' as const,

0 commit comments

Comments
 (0)