ggaction 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/README.md +5 -4
- package/knowledge/action-card.schema.json +1 -0
- package/knowledge/action-cards.json +1 -10941
- package/knowledge/action-cards.schema.json +1 -0
- package/knowledge/extension-authoring.md +248 -0
- package/knowledge/intent-taxonomy.json +1 -183
- package/knowledge/intent-taxonomy.schema.json +1 -0
- package/knowledge/mcp-resources.json +1 -95
- package/knowledge/mcp-resources.schema.json +1 -0
- package/knowledge/task-packet.schema.json +1 -159
- package/knowledge/task-resolver.js +1 -1230
- package/package.json +19 -2
- package/src/actions/boxPlots/edit.js +45 -298
- package/src/actions/boxPlots/options.js +46 -77
- package/src/actions/boxPlots/resolve.js +1 -1
- package/src/actions/charts/bar.js +3 -0
- package/src/actions/charts/heatmap.js +73 -83
- package/src/actions/charts/index.js +1 -1
- package/src/actions/charts/parallel.js +35 -1
- package/src/actions/charts/shared.js +20 -0
- package/src/actions/composition/actions.js +46 -49
- package/src/actions/data/bin2d.js +105 -2
- package/src/actions/data/box.js +17 -17
- package/src/actions/data/density.js +42 -78
- package/src/actions/data/gradientProfile.js +22 -52
- package/src/actions/data/horizon.js +16 -41
- package/src/actions/data/index.js +10 -10
- package/src/actions/data/interval.js +16 -38
- package/src/actions/data/intervalEdit.js +55 -0
- package/src/actions/data/regression.js +7 -17
- package/src/actions/data/shared.js +47 -0
- package/src/actions/data/timeUnit.js +14 -38
- package/src/actions/data/window.js +14 -38
- package/src/actions/distributions/revision.js +154 -34
- package/src/actions/encodings/angle.js +9 -10
- package/src/actions/encodings/appearance.js +17 -51
- package/src/actions/encodings/density/resolve.js +3 -1
- package/src/actions/encodings/density.js +1 -15
- package/src/actions/encodings/horizon/resolve.js +13 -3
- package/src/actions/encodings/horizon.js +8 -7
- package/src/actions/encodings/index.js +9 -9
- package/src/actions/encodings/offset.js +8 -24
- package/src/actions/encodings/parallel.js +9 -10
- package/src/actions/encodings/pathOrder.js +6 -13
- package/src/actions/encodings/position/policies/index.js +4 -4
- package/src/actions/encodings/position/policies/line.js +47 -17
- package/src/actions/encodings/position/resolve.js +24 -5
- package/src/actions/encodings/ranged.js +18 -23
- package/src/actions/encodings/remove.js +15 -25
- package/src/actions/encodings/ruleAppearance.js +9 -24
- package/src/actions/encodings/shared.js +37 -0
- package/src/actions/encodings/strokeDash.js +8 -23
- package/src/actions/encodings/text.js +9 -10
- package/src/actions/errorBands/create.js +105 -39
- package/src/actions/errorBands/edit.js +89 -93
- package/src/actions/errorBands/index.js +1 -2
- package/src/actions/errorBars/create.js +78 -27
- package/src/actions/errorBars/edit.js +81 -48
- package/src/actions/errorBars/index.js +1 -2
- package/src/actions/facets/actions.js +45 -69
- package/src/actions/facets/derive.js +38 -53
- package/src/actions/facets/replay.js +0 -1
- package/src/actions/gradientPlots/components.js +59 -48
- package/src/actions/gradientPlots/edit.js +35 -216
- package/src/actions/gradientPlots/index.js +11 -10
- package/src/actions/gradientPlots/materialize.js +21 -35
- package/src/actions/gradientPlots/options.js +5 -7
- package/src/actions/gradientPlots/paint.js +9 -6
- package/src/actions/gradientPlots/resolve.js +1 -1
- package/src/actions/guides/axes/index.js +3 -3
- package/src/actions/guides/axes/labels.js +68 -26
- package/src/actions/guides/axes/lines.js +22 -2
- package/src/actions/guides/axes/policy.js +28 -8
- package/src/actions/guides/axes/ticks.js +27 -9
- package/src/actions/guides/axes/titles.js +113 -65
- package/src/actions/guides/grids/resolve.js +14 -0
- package/src/actions/guides/guides.js +2 -4
- package/src/actions/guides/index.js +2 -2
- package/src/actions/guides/legends/categorical/actions.js +44 -68
- package/src/actions/guides/legends/categorical/components.js +6 -1
- package/src/actions/guides/legends/categorical/index.js +2 -2
- package/src/actions/guides/legends/categorical/layout.js +148 -175
- package/src/actions/guides/legends/categorical/recipes.js +5 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -1
- package/src/actions/guides/legends/continuous/common.js +117 -66
- package/src/actions/guides/legends/continuous/gradient.js +38 -37
- package/src/actions/guides/legends/continuous/interval.js +97 -76
- package/src/actions/guides/legends/continuous/opacity.js +28 -38
- package/src/actions/guides/legends/edit.js +14 -1
- package/src/actions/guides/legends/index.js +1 -1
- package/src/actions/guides/legends/lane.js +2 -1
- package/src/actions/guides/legends/remove.js +8 -0
- package/src/actions/guides/legends/size.js +36 -43
- package/src/actions/guides/legends/strokeWidth.js +20 -26
- package/src/actions/guides/polar/axes/labels.js +17 -1
- package/src/actions/guides/polar/axes/shared.js +7 -1
- package/src/actions/guides/polar/axes/titles.js +19 -2
- package/src/actions/guides/polar/grids.js +4 -0
- package/src/actions/guides/polar/resolve.js +6 -0
- package/src/actions/index.js +13 -13
- package/src/actions/intervals/resolve.js +87 -117
- package/src/actions/marks/arc/actions.js +31 -36
- package/src/actions/marks/area/actions.js +23 -31
- package/src/actions/marks/index.js +6 -6
- package/src/actions/marks/line/actions.js +33 -52
- package/src/actions/marks/line/materialize.js +7 -5
- package/src/actions/marks/point/materialize.js +5 -3
- package/src/actions/marks/remove.js +21 -0
- package/src/actions/marks/rule/actions.js +53 -53
- package/src/actions/marks/shared.js +8 -4
- package/src/actions/marks/text/actions.js +14 -6
- package/src/actions/marks/text/layout.js +21 -45
- package/src/actions/marks/tick/actions.js +22 -21
- package/src/actions/primitives/createGraphics.js +4 -0
- package/src/actions/primitives/editGraphics.js +4 -0
- package/src/actions/primitives/index.js +3 -3
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +2 -2
- package/src/actions/primitives/semanticValidation/layer.js +1 -1
- package/src/actions/regression/edit.js +3 -43
- package/src/actions/scales/consumers/families.js +24 -4
- package/src/actions/scales/consumers/index.js +1 -1
- package/src/actions/scales/consumers/seriesLayout.js +17 -0
- package/src/actions/scales/definitions.js +100 -103
- package/src/actions/scales/materialize.js +5 -0
- package/src/actions/selection/actions.js +79 -121
- package/src/actions/titles/actions.js +48 -94
- package/src/actions/titles/resolve.js +14 -27
- package/src/actions/violinPlots/create.js +37 -44
- package/src/core/action.js +20 -5
- package/src/core/extensionRegistry.js +104 -0
- package/src/core/textMetrics.js +74 -37
- package/src/core/validation.js +18 -0
- package/src/extension.js +8 -1
- package/src/grammar/aggregate.js +48 -28
- package/src/grammar/arcs.js +58 -11
- package/src/grammar/areaSeries.js +14 -16
- package/src/grammar/bin2d.js +37 -23
- package/src/grammar/boxPlot.js +14 -13
- package/src/grammar/categoricalDensity.js +14 -14
- package/src/grammar/categoryOrder.js +8 -14
- package/src/grammar/curveCommands.js +87 -20
- package/src/grammar/density.js +162 -141
- package/src/grammar/facets/index.js +14 -0
- package/src/grammar/facets/scales.js +7 -4
- package/src/grammar/gradientProfile.js +12 -15
- package/src/grammar/histogram.js +145 -83
- package/src/grammar/horizon.js +60 -23
- package/src/grammar/interval.js +14 -13
- package/src/grammar/lineSeries.js +91 -61
- package/src/grammar/numeric.js +290 -0
- package/src/grammar/paint.js +3 -4
- package/src/grammar/palettes.js +21 -32
- package/src/grammar/pathCommands.js +6 -0
- package/src/grammar/polarPaths.js +5 -5
- package/src/grammar/regression/derive.js +48 -9
- package/src/grammar/regression/models.js +248 -69
- package/src/grammar/regression/parameters.js +8 -0
- package/src/grammar/scales/color.js +35 -26
- package/src/grammar/scales/continuous.js +71 -24
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/discretized.js +42 -12
- package/src/grammar/scales/fields.js +21 -4
- package/src/grammar/scales/ordinal.js +117 -61
- package/src/grammar/scales/temporal.js +40 -11
- package/src/grammar/scales/transformed.js +199 -52
- package/src/grammar/schemas/graphicBounds.js +270 -79
- package/src/grammar/seriesLayout.js +50 -18
- package/src/grammar/ticks.js +123 -53
- package/src/grammar/timeUnit.js +18 -8
- package/src/grammar/transforms.js +4 -1
- package/src/grammar/window.js +70 -57
- package/src/index.js +1 -1
- package/src/layout/canvas.js +4 -8
- package/src/layout/composition.js +39 -40
- package/src/layout/facets.js +10 -14
- package/src/layout/labels.js +91 -15
- package/src/layout/legend.js +22 -20
- package/src/layout/legendLane.js +54 -40
- package/src/layout/title.js +7 -7
- package/src/materialization/bars/aggregate.js +14 -40
- package/src/materialization/bars/grouped.js +7 -18
- package/src/materialization/bars/histogram.js +2 -19
- package/src/materialization/bars/ranged.js +20 -15
- package/src/materialization/bars/resolve.js +21 -0
- package/src/materialization/facetGuides/legacyCategorical.js +2 -1
- package/src/materialization/facetGuides/placement.js +34 -19
- package/src/materialization/facetGuides/preparation.js +9 -5
- package/src/materialization/facets.js +39 -27
- package/src/materialization/guides/resources.js +2 -1
- package/src/materialization/marks/capabilities.js +5 -2
- package/src/materialization/marks/index.js +24 -4
- package/src/materialization/scales/policies/bar.js +61 -59
- package/src/materialization/scales/policies/binnedPosition.js +34 -0
- package/src/materialization/scales/policies/series.js +13 -7
- package/src/materialization/scales/resolve.js +4 -5
- package/src/materialization/selection/items/arc.js +16 -2
- package/src/materialization/selection/items/bar.js +4 -2
- package/src/materialization/selection/items/common.js +21 -1
- package/src/materialization/selection/items/path.js +19 -2
- package/src/materialization/selection/items/point.js +4 -16
- package/src/materialization/selection/items/tick.js +13 -21
- package/src/materialization/selection/point.js +11 -4
- package/src/materialization/selection/styles.js +19 -27
- package/src/materialization/text.js +4 -1
- package/src/mcp/adapter.js +8 -3
- package/src/renderers/canvas/fill.js +2 -2
- package/src/renderers/canvas/index.js +35 -2
- package/src/renderers/canvas/native.js +160 -0
- package/src/renderers/pdf.js +14 -0
- package/src/renderers/svg.js +37 -4
- package/types/extension.d.ts +19 -0
- package/types/index.d.ts +3 -0
- package/types/program.d.ts +509 -131
- package/types/svg.d.ts +1 -0
- package/src/actions/errorBands/components.js +0 -81
- package/src/actions/errorBands/options.js +0 -39
- package/src/actions/errorBands/resolve.js +0 -28
- package/src/actions/errorBars/components.js +0 -62
- package/src/actions/errorBars/options.js +0 -58
- package/src/actions/errorBars/resolve.js +0 -25
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cloneAndFreeze } from "../../core/immutable.js";
|
|
2
|
+
import { utcTimestamp, validTimestamp } from "../timeUnit.js";
|
|
2
3
|
|
|
3
4
|
const TIME_UNITS = [
|
|
4
5
|
{ span: 2 * 365 * 24 * 60 * 60 * 1000, unit: "year" },
|
|
@@ -9,22 +10,47 @@ const TIME_UNITS = [
|
|
|
9
10
|
{ span: 0, unit: "second" }
|
|
10
11
|
];
|
|
11
12
|
|
|
13
|
+
function requireTimeDomain(domain) {
|
|
14
|
+
if (
|
|
15
|
+
!Array.isArray(domain) ||
|
|
16
|
+
domain.length !== 2 ||
|
|
17
|
+
!domain.every(validTimestamp)
|
|
18
|
+
) {
|
|
19
|
+
throw new TypeError(
|
|
20
|
+
"Nice time domain must contain two timestamps representing valid dates."
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return domain;
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
function floorUtc(timestamp, unit) {
|
|
13
27
|
const date = new Date(timestamp);
|
|
14
|
-
if (unit === "year") return
|
|
15
|
-
if (unit === "month")
|
|
28
|
+
if (unit === "year") return utcTimestamp(date.getUTCFullYear());
|
|
29
|
+
if (unit === "month") {
|
|
30
|
+
return utcTimestamp(date.getUTCFullYear(), date.getUTCMonth());
|
|
31
|
+
}
|
|
16
32
|
if (unit === "day") {
|
|
17
|
-
return
|
|
33
|
+
return utcTimestamp(
|
|
34
|
+
date.getUTCFullYear(),
|
|
35
|
+
date.getUTCMonth(),
|
|
36
|
+
date.getUTCDate()
|
|
37
|
+
);
|
|
18
38
|
}
|
|
19
39
|
if (unit === "hour") {
|
|
20
|
-
return
|
|
21
|
-
date.getUTCFullYear(),
|
|
40
|
+
return utcTimestamp(
|
|
41
|
+
date.getUTCFullYear(),
|
|
42
|
+
date.getUTCMonth(),
|
|
43
|
+
date.getUTCDate(),
|
|
44
|
+
date.getUTCHours()
|
|
22
45
|
);
|
|
23
46
|
}
|
|
24
47
|
if (unit === "minute") {
|
|
25
|
-
return
|
|
26
|
-
date.getUTCFullYear(),
|
|
27
|
-
date.
|
|
48
|
+
return utcTimestamp(
|
|
49
|
+
date.getUTCFullYear(),
|
|
50
|
+
date.getUTCMonth(),
|
|
51
|
+
date.getUTCDate(),
|
|
52
|
+
date.getUTCHours(),
|
|
53
|
+
date.getUTCMinutes()
|
|
28
54
|
);
|
|
29
55
|
}
|
|
30
56
|
return Math.floor(timestamp / 1000) * 1000;
|
|
@@ -32,9 +58,9 @@ function floorUtc(timestamp, unit) {
|
|
|
32
58
|
|
|
33
59
|
function offsetUtc(timestamp, unit) {
|
|
34
60
|
const date = new Date(timestamp);
|
|
35
|
-
if (unit === "year") return
|
|
61
|
+
if (unit === "year") return utcTimestamp(date.getUTCFullYear() + 1);
|
|
36
62
|
if (unit === "month") {
|
|
37
|
-
return
|
|
63
|
+
return utcTimestamp(date.getUTCFullYear(), date.getUTCMonth() + 1);
|
|
38
64
|
}
|
|
39
65
|
if (unit === "day") return timestamp + 24 * 60 * 60 * 1000;
|
|
40
66
|
if (unit === "hour") return timestamp + 60 * 60 * 1000;
|
|
@@ -43,11 +69,14 @@ function offsetUtc(timestamp, unit) {
|
|
|
43
69
|
}
|
|
44
70
|
|
|
45
71
|
export function niceTimeDomain(domain) {
|
|
46
|
-
const [minimum, maximum] = domain;
|
|
72
|
+
const [minimum, maximum] = requireTimeDomain(domain);
|
|
47
73
|
if (minimum === maximum) return domain;
|
|
48
74
|
const unit = TIME_UNITS.find(item => maximum - minimum >= item.span).unit;
|
|
49
75
|
const start = floorUtc(minimum, unit);
|
|
50
76
|
const endFloor = floorUtc(maximum, unit);
|
|
51
77
|
const end = endFloor === maximum ? maximum : offsetUtc(endFloor, unit);
|
|
78
|
+
if (![start, end].every(validTimestamp)) {
|
|
79
|
+
throw new RangeError("Nice time domain exceeds the supported date range.");
|
|
80
|
+
}
|
|
52
81
|
return cloneAndFreeze([start, end]);
|
|
53
82
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { cloneAndFreeze, isPlainObject } from "../../core/immutable.js";
|
|
2
|
+
import { MAX_GENERATED_ITEMS } from "../../core/validation.js";
|
|
3
|
+
import { interpolateNumber, inverseLerp, numericExtent } from "../numeric.js";
|
|
2
4
|
import { niceTicks } from "../ticks.js";
|
|
3
5
|
import { niceLinearDomain } from "./continuous.js";
|
|
4
6
|
import {
|
|
@@ -51,22 +53,89 @@ export function normalizeTransformParameters(type, options = {}) {
|
|
|
51
53
|
return cloneAndFreeze({});
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
function signedTransformProportion(value, start, end, transform) {
|
|
57
|
+
const transformed = [start, end, value].map(item =>
|
|
58
|
+
Math.sign(item) * transform(Math.abs(item))
|
|
59
|
+
);
|
|
60
|
+
return transformed[0] !== transformed[1] &&
|
|
61
|
+
transformed.every(Number.isFinite)
|
|
62
|
+
? inverseLerp(transformed[2], transformed[0], transformed[1])
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function powerProportion(value, domain, exponent) {
|
|
67
|
+
const [start, end] = domain;
|
|
68
|
+
const direct = signedTransformProportion(
|
|
69
|
+
value, start, end, magnitude => magnitude ** exponent
|
|
70
|
+
);
|
|
71
|
+
if (direct !== undefined) return direct;
|
|
72
|
+
const scale = Math.max(Math.abs(start), Math.abs(end));
|
|
73
|
+
const normalized = signedTransformProportion(
|
|
74
|
+
value,
|
|
75
|
+
start,
|
|
76
|
+
end,
|
|
77
|
+
magnitude => magnitude === 0 ? 0 : Math.exp(exponent * (
|
|
78
|
+
Math.log(magnitude) - Math.log(scale)
|
|
79
|
+
))
|
|
80
|
+
);
|
|
81
|
+
if (normalized !== undefined) return normalized;
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
start !== 0 &&
|
|
85
|
+
end !== 0 &&
|
|
86
|
+
value !== 0 &&
|
|
87
|
+
Math.sign(start) === Math.sign(end)
|
|
88
|
+
) {
|
|
89
|
+
const endLogRatio = Math.log(Math.abs(end)) - Math.log(Math.abs(start));
|
|
90
|
+
const valueLogRatio = Math.log(Math.abs(value)) - Math.log(Math.abs(start));
|
|
91
|
+
if (Math.abs(exponent * endLogRatio) < 1e-8) {
|
|
92
|
+
return valueLogRatio / endLogRatio;
|
|
93
|
+
}
|
|
94
|
+
const proportion = Math.expm1(exponent * valueLogRatio) /
|
|
95
|
+
Math.expm1(exponent * endLogRatio);
|
|
96
|
+
if (Number.isFinite(proportion)) return proportion;
|
|
59
97
|
}
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
|
|
99
|
+
return inverseLerp(value, start, end);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function logOnePlusRatio(value, constant) {
|
|
103
|
+
if (value === 0) return 0;
|
|
104
|
+
const ratio = Math.abs(value) / constant;
|
|
105
|
+
if (Number.isFinite(ratio)) return Math.sign(value) * Math.log1p(ratio);
|
|
106
|
+
const logRatio = Math.log(Math.abs(value)) - Math.log(constant);
|
|
107
|
+
return Math.sign(value) * (
|
|
108
|
+
Math.max(0, logRatio) + Math.log1p(Math.exp(-Math.abs(logRatio)))
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function transformedProportion(value, domain, type, parameters) {
|
|
113
|
+
const [start, end] = domain;
|
|
114
|
+
if (type === "linear") return inverseLerp(value, start, end);
|
|
115
|
+
if (type === "log") {
|
|
116
|
+
const logarithm = Math.log10(parameters.base);
|
|
117
|
+
const direct = signedTransformProportion(
|
|
118
|
+
value, start, end, magnitude => Math.log10(magnitude) / logarithm
|
|
119
|
+
);
|
|
120
|
+
return direct ?? signedTransformProportion(
|
|
121
|
+
value, start, end, Math.log
|
|
122
|
+
) ?? inverseLerp(value, start, end);
|
|
62
123
|
}
|
|
63
|
-
const exponent = type === "sqrt" ? 0.5 : parameters.exponent;
|
|
64
124
|
if (type === "pow" || type === "sqrt") {
|
|
65
|
-
return
|
|
125
|
+
return powerProportion(value, domain, parameters.exponent);
|
|
66
126
|
}
|
|
67
|
-
|
|
68
|
-
|
|
127
|
+
|
|
128
|
+
const transformedStart = logOnePlusRatio(start, parameters.constant);
|
|
129
|
+
const transformedEnd = logOnePlusRatio(end, parameters.constant);
|
|
130
|
+
if (transformedStart === transformedEnd) {
|
|
131
|
+
return inverseLerp(value, start, end);
|
|
132
|
+
}
|
|
133
|
+
const proportion = inverseLerp(
|
|
134
|
+
logOnePlusRatio(value, parameters.constant),
|
|
135
|
+
transformedStart,
|
|
136
|
+
transformedEnd
|
|
69
137
|
);
|
|
138
|
+
return Number.isFinite(proportion) ? proportion : inverseLerp(value, start, end);
|
|
70
139
|
}
|
|
71
140
|
|
|
72
141
|
export function validateTransformedDomain(type, domain, options = {}) {
|
|
@@ -87,25 +156,81 @@ export function validateTransformedDomain(type, domain, options = {}) {
|
|
|
87
156
|
return validated;
|
|
88
157
|
}
|
|
89
158
|
|
|
90
|
-
function
|
|
91
|
-
const
|
|
159
|
+
function radixPower(radix, exponent, logarithm) {
|
|
160
|
+
const direct = Number.isFinite(radix) ? radix ** exponent : Number.NaN;
|
|
161
|
+
if (Number.isFinite(direct) && direct > 0) return direct;
|
|
162
|
+
const transformed = exponent * logarithm;
|
|
163
|
+
if (transformed > Math.log(Number.MAX_VALUE)) return Number.POSITIVE_INFINITY;
|
|
164
|
+
if (transformed < Math.log(Number.MIN_VALUE)) return 0;
|
|
165
|
+
return Math.exp(transformed);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function logDomainInfo(domain, base) {
|
|
92
169
|
const low = Math.min(...domain);
|
|
93
170
|
const high = Math.max(...domain);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
171
|
+
const negative = high < 0;
|
|
172
|
+
return [
|
|
173
|
+
base < 1 ? -Math.log(base) : Math.log(base),
|
|
174
|
+
base < 1 ? 1 / base : base,
|
|
175
|
+
domain[0] > domain[1],
|
|
176
|
+
negative,
|
|
177
|
+
negative ? Math.abs(high) : low,
|
|
178
|
+
negative ? Math.abs(low) : high
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function niceLogDomain(domain, base) {
|
|
183
|
+
const [logarithm, radix, reversed, negative, minimum, maximum] =
|
|
184
|
+
logDomainInfo(domain, base);
|
|
185
|
+
let lower = radixPower(
|
|
186
|
+
radix,
|
|
187
|
+
Math.floor(Math.log(minimum) / logarithm),
|
|
188
|
+
logarithm
|
|
189
|
+
);
|
|
190
|
+
let upper = radixPower(
|
|
191
|
+
radix,
|
|
192
|
+
Math.ceil(Math.log(maximum) / logarithm),
|
|
193
|
+
logarithm
|
|
194
|
+
);
|
|
195
|
+
if (!Number.isFinite(lower) || lower <= 0 || lower > minimum) lower = minimum;
|
|
196
|
+
if (!Number.isFinite(upper) || upper < maximum) upper = maximum;
|
|
197
|
+
const result = negative ? [-upper, -lower] : [lower, upper];
|
|
106
198
|
return cloneAndFreeze(reversed ? result.reverse() : result);
|
|
107
199
|
}
|
|
108
200
|
|
|
201
|
+
function padAutomaticTransformedDomain(type, value, options) {
|
|
202
|
+
const parameters = normalizeTransformParameters(type, options);
|
|
203
|
+
if (value === 0) {
|
|
204
|
+
if (type === "log") {
|
|
205
|
+
throw new RangeError(
|
|
206
|
+
"Log scale domain must be strictly positive or strictly negative."
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
return [-1, 1];
|
|
210
|
+
}
|
|
211
|
+
const magnitude = Math.abs(value);
|
|
212
|
+
let lower = magnitude / 2;
|
|
213
|
+
let upper = magnitude * 2;
|
|
214
|
+
if (type === "pow" || type === "sqrt") {
|
|
215
|
+
upper = magnitude * (2 - 2 ** -parameters.exponent) **
|
|
216
|
+
(1 / parameters.exponent);
|
|
217
|
+
} else if (type === "symlog") {
|
|
218
|
+
const center = Math.abs(logOnePlusRatio(value, parameters.constant));
|
|
219
|
+
if (center === 0) return [-1, 1];
|
|
220
|
+
upper = parameters.constant * Math.expm1(
|
|
221
|
+
2 * center - logOnePlusRatio(lower, parameters.constant)
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (!(lower < magnitude && upper > magnitude && Number.isFinite(upper))) {
|
|
225
|
+
lower = magnitude / 2;
|
|
226
|
+
upper = Number.isFinite(magnitude * 2) ? magnitude * 2 : magnitude;
|
|
227
|
+
}
|
|
228
|
+
if (type === "log" && lower === 0) lower = magnitude;
|
|
229
|
+
return value > 0
|
|
230
|
+
? [lower, upper]
|
|
231
|
+
: [-upper, lower === 0 ? 0 : -lower];
|
|
232
|
+
}
|
|
233
|
+
|
|
109
234
|
export function resolveTransformedDomain({
|
|
110
235
|
type,
|
|
111
236
|
domain = "auto",
|
|
@@ -129,11 +254,11 @@ export function resolveTransformedDomain({
|
|
|
129
254
|
if (values.length === 0) {
|
|
130
255
|
throw new Error("Cannot infer an automatic scale domain from no values.");
|
|
131
256
|
}
|
|
132
|
-
let resolved =
|
|
257
|
+
let resolved = numericExtent(values);
|
|
258
|
+
if (zero) resolved = [Math.min(0, resolved[0]), Math.max(0, resolved[1])];
|
|
133
259
|
if (resolved[0] === resolved[1]) {
|
|
134
|
-
|
|
260
|
+
resolved = padAutomaticTransformedDomain(type, resolved[0], options);
|
|
135
261
|
}
|
|
136
|
-
if (zero) resolved = [Math.min(0, resolved[0]), Math.max(0, resolved[1])];
|
|
137
262
|
validateTransformedDomain(type, resolved, options);
|
|
138
263
|
if (nice) {
|
|
139
264
|
resolved = type === "log"
|
|
@@ -166,30 +291,34 @@ export function mapTransformedValues(
|
|
|
166
291
|
throw new TypeError("Scale clamp must be a boolean.");
|
|
167
292
|
}
|
|
168
293
|
const hasUnknown = Object.hasOwn(options, "unknown");
|
|
169
|
-
const transformOptions =
|
|
170
|
-
Object.entries(options).filter(([key]) => key !== "unknown")
|
|
171
|
-
);
|
|
294
|
+
const { unknown, ...transformOptions } = options;
|
|
172
295
|
const parameters = normalizeTransformParameters(type, transformOptions);
|
|
173
|
-
const
|
|
174
|
-
const validatedDomain = validateTransformedDomain(type, domain, domainOptions);
|
|
296
|
+
const validatedDomain = validateTransformedDomain(type, domain, transformOptions);
|
|
175
297
|
const resolvedRange = resolveMappingRange(range, { reverse });
|
|
176
|
-
const
|
|
177
|
-
transformValue(value, type, parameters)
|
|
178
|
-
);
|
|
179
|
-
const span = transformedDomain[1] - transformedDomain[0];
|
|
180
|
-
|
|
298
|
+
const span = resolvedRange[1] - resolvedRange[0];
|
|
181
299
|
return cloneAndFreeze(values.map(value => {
|
|
182
300
|
const valid = Number.isFinite(value) && !(type === "log" && (
|
|
183
301
|
value === 0 || Math.sign(value) !== Math.sign(validatedDomain[0])
|
|
184
302
|
));
|
|
185
303
|
if (!valid) {
|
|
186
|
-
if (hasUnknown) return
|
|
304
|
+
if (hasUnknown) return unknown;
|
|
187
305
|
throw new TypeError(`Scale type "${type}" received an invalid value.`);
|
|
188
306
|
}
|
|
189
|
-
|
|
190
|
-
|
|
307
|
+
let proportion = transformedProportion(
|
|
308
|
+
value,
|
|
309
|
+
validatedDomain,
|
|
310
|
+
type,
|
|
311
|
+
parameters
|
|
312
|
+
);
|
|
191
313
|
if (clamp) proportion = Math.max(0, Math.min(1, proportion));
|
|
192
|
-
|
|
314
|
+
const direct = resolvedRange[0] + proportion * span;
|
|
315
|
+
return Number.isFinite(span) && Number.isFinite(direct) && (
|
|
316
|
+
proportion !== 1 ||
|
|
317
|
+
Math.abs(direct - resolvedRange[1]) <=
|
|
318
|
+
Number.EPSILON * Math.abs(resolvedRange[1])
|
|
319
|
+
)
|
|
320
|
+
? direct
|
|
321
|
+
: interpolateNumber(resolvedRange[0], resolvedRange[1], proportion);
|
|
193
322
|
}));
|
|
194
323
|
}
|
|
195
324
|
|
|
@@ -200,21 +329,39 @@ export function transformedTicks(type, domain, count, options = {}) {
|
|
|
200
329
|
}
|
|
201
330
|
if (type !== "log") return niceTicks(validated, count);
|
|
202
331
|
const { base } = normalizeTransformParameters(type, options);
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
332
|
+
const [
|
|
333
|
+
logarithm,
|
|
334
|
+
radix,
|
|
335
|
+
reversed,
|
|
336
|
+
negative,
|
|
337
|
+
minimumMagnitude,
|
|
338
|
+
maximumMagnitude
|
|
339
|
+
] = logDomainInfo(validated, base);
|
|
209
340
|
const start = Math.ceil(
|
|
210
|
-
Math.log(minimumMagnitude) /
|
|
341
|
+
Math.log(minimumMagnitude) / logarithm - 1e-12
|
|
211
342
|
);
|
|
212
343
|
const end = Math.floor(
|
|
213
|
-
Math.log(maximumMagnitude) /
|
|
344
|
+
Math.log(maximumMagnitude) / logarithm + 1e-12
|
|
214
345
|
);
|
|
346
|
+
const available = end - start + 1;
|
|
347
|
+
const tickCount = available <= MAX_GENERATED_ITEMS
|
|
348
|
+
? available
|
|
349
|
+
: Math.min(count, MAX_GENERATED_ITEMS);
|
|
215
350
|
const values = [];
|
|
216
|
-
for (let
|
|
217
|
-
|
|
351
|
+
for (let index = 0; index < tickCount; index += 1) {
|
|
352
|
+
const exponent = available <= MAX_GENERATED_ITEMS
|
|
353
|
+
? start + index
|
|
354
|
+
: Math.round(start + (end - start) * index / Math.max(1, tickCount - 1));
|
|
355
|
+
const magnitude = radixPower(radix, exponent, logarithm);
|
|
356
|
+
const value = (negative ? -1 : 1) * magnitude;
|
|
357
|
+
if (
|
|
358
|
+
Number.isFinite(value) &&
|
|
359
|
+
magnitude >= minimumMagnitude &&
|
|
360
|
+
magnitude <= maximumMagnitude &&
|
|
361
|
+
(values.length === 0 || value !== values.at(-1))
|
|
362
|
+
) {
|
|
363
|
+
values.push(value);
|
|
364
|
+
}
|
|
218
365
|
}
|
|
219
366
|
if (negative) values.reverse();
|
|
220
367
|
if (reversed) values.reverse();
|