@coinbase/cds-web-visualization 3.4.0-beta.5 → 3.4.0-beta.6

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.
Files changed (167) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dts/chart/CartesianChart.d.ts +38 -2
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/Path.d.ts +27 -7
  5. package/dts/chart/Path.d.ts.map +1 -1
  6. package/dts/chart/PeriodSelector.d.ts +0 -4
  7. package/dts/chart/PeriodSelector.d.ts.map +1 -1
  8. package/dts/chart/area/Area.d.ts +54 -24
  9. package/dts/chart/area/Area.d.ts.map +1 -1
  10. package/dts/chart/area/AreaChart.d.ts +33 -6
  11. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  12. package/dts/chart/area/DottedArea.d.ts +21 -44
  13. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  14. package/dts/chart/area/GradientArea.d.ts +21 -12
  15. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  16. package/dts/chart/area/SolidArea.d.ts +16 -1
  17. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  18. package/dts/chart/axis/Axis.d.ts +89 -43
  19. package/dts/chart/axis/Axis.d.ts.map +1 -1
  20. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  21. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  22. package/dts/chart/axis/XAxis.d.ts +1 -1
  23. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  24. package/dts/chart/axis/YAxis.d.ts +1 -1
  25. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  26. package/dts/chart/axis/index.d.ts +1 -0
  27. package/dts/chart/axis/index.d.ts.map +1 -1
  28. package/dts/chart/bar/Bar.d.ts +16 -13
  29. package/dts/chart/bar/Bar.d.ts.map +1 -1
  30. package/dts/chart/bar/BarChart.d.ts +17 -8
  31. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  32. package/dts/chart/bar/BarPlot.d.ts +2 -1
  33. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  34. package/dts/chart/bar/BarStack.d.ts +40 -48
  35. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  36. package/dts/chart/bar/BarStackGroup.d.ts +1 -0
  37. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  38. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  39. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  40. package/dts/chart/gradient/Gradient.d.ts +35 -0
  41. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  42. package/dts/chart/gradient/index.d.ts +2 -0
  43. package/dts/chart/gradient/index.d.ts.map +1 -0
  44. package/dts/chart/index.d.ts +2 -1
  45. package/dts/chart/index.d.ts.map +1 -1
  46. package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
  47. package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
  48. package/dts/chart/line/DottedLine.d.ts +15 -3
  49. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  50. package/dts/chart/line/Line.d.ts +70 -28
  51. package/dts/chart/line/Line.d.ts.map +1 -1
  52. package/dts/chart/line/LineChart.d.ts +26 -8
  53. package/dts/chart/line/LineChart.d.ts.map +1 -1
  54. package/dts/chart/line/ReferenceLine.d.ts +85 -44
  55. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  56. package/dts/chart/line/SolidLine.d.ts +14 -3
  57. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  58. package/dts/chart/line/index.d.ts +1 -1
  59. package/dts/chart/line/index.d.ts.map +1 -1
  60. package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
  61. package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
  62. package/dts/chart/point/Point.d.ts +201 -0
  63. package/dts/chart/point/Point.d.ts.map +1 -0
  64. package/dts/chart/point/index.d.ts +3 -0
  65. package/dts/chart/point/index.d.ts.map +1 -0
  66. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +24 -0
  67. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
  68. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
  69. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
  70. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +10 -0
  71. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  72. package/dts/chart/scrubber/Scrubber.d.ts +203 -64
  73. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  74. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +70 -0
  75. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  76. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +32 -0
  77. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  78. package/dts/chart/scrubber/index.d.ts +3 -0
  79. package/dts/chart/scrubber/index.d.ts.map +1 -1
  80. package/dts/chart/text/ChartText.d.ts +46 -43
  81. package/dts/chart/text/ChartText.d.ts.map +1 -1
  82. package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
  83. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  84. package/dts/chart/text/index.d.ts +1 -1
  85. package/dts/chart/text/index.d.ts.map +1 -1
  86. package/dts/chart/utils/chart.d.ts +27 -7
  87. package/dts/chart/utils/chart.d.ts.map +1 -1
  88. package/dts/chart/utils/context.d.ts +6 -0
  89. package/dts/chart/utils/context.d.ts.map +1 -1
  90. package/dts/chart/utils/gradient.d.ts +104 -0
  91. package/dts/chart/utils/gradient.d.ts.map +1 -0
  92. package/dts/chart/utils/index.d.ts +4 -0
  93. package/dts/chart/utils/index.d.ts.map +1 -1
  94. package/dts/chart/utils/interpolate.d.ts +112 -0
  95. package/dts/chart/utils/interpolate.d.ts.map +1 -0
  96. package/dts/chart/utils/path.d.ts +24 -1
  97. package/dts/chart/utils/path.d.ts.map +1 -1
  98. package/dts/chart/utils/point.d.ts +29 -0
  99. package/dts/chart/utils/point.d.ts.map +1 -1
  100. package/dts/chart/utils/scrubber.d.ts +39 -0
  101. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  102. package/dts/chart/utils/transition.d.ts +65 -0
  103. package/dts/chart/utils/transition.d.ts.map +1 -0
  104. package/esm/chart/CartesianChart.js +140 -85
  105. package/esm/chart/Path.js +51 -46
  106. package/esm/chart/PeriodSelector.js +4 -18
  107. package/esm/chart/area/Area.js +24 -34
  108. package/esm/chart/area/AreaChart.js +24 -15
  109. package/esm/chart/area/DottedArea.js +35 -89
  110. package/esm/chart/area/GradientArea.js +34 -80
  111. package/esm/chart/area/SolidArea.js +29 -11
  112. package/esm/chart/axis/Axis.js +4 -25
  113. package/esm/chart/axis/DefaultAxisTickLabel.js +15 -0
  114. package/esm/chart/axis/XAxis.js +53 -36
  115. package/esm/chart/axis/YAxis.js +55 -32
  116. package/esm/chart/axis/index.js +1 -0
  117. package/esm/chart/bar/Bar.js +3 -1
  118. package/esm/chart/bar/BarChart.js +15 -32
  119. package/esm/chart/bar/BarPlot.js +3 -2
  120. package/esm/chart/bar/BarStack.js +65 -23
  121. package/esm/chart/bar/BarStackGroup.js +7 -17
  122. package/esm/chart/bar/DefaultBar.js +4 -7
  123. package/esm/chart/bar/DefaultBarStack.js +5 -7
  124. package/esm/chart/gradient/Gradient.js +104 -0
  125. package/esm/chart/gradient/index.js +1 -0
  126. package/esm/chart/index.js +2 -1
  127. package/esm/chart/line/DefaultReferenceLineLabel.js +81 -0
  128. package/esm/chart/line/DottedLine.js +38 -17
  129. package/esm/chart/line/Line.js +96 -70
  130. package/esm/chart/line/LineChart.js +18 -6
  131. package/esm/chart/line/ReferenceLine.js +34 -41
  132. package/esm/chart/line/SolidLine.js +36 -15
  133. package/esm/chart/line/index.js +1 -1
  134. package/esm/chart/{line/GradientLine.js → point/DefaultPointLabel.js} +31 -45
  135. package/esm/chart/point/Point.css +2 -0
  136. package/esm/chart/{Point.js → point/Point.js} +66 -57
  137. package/esm/chart/point/index.js +2 -0
  138. package/esm/chart/scrubber/DefaultScrubberBeacon.js +155 -0
  139. package/esm/chart/scrubber/{ScrubberBeaconLabel.js → DefaultScrubberBeaconLabel.js} +23 -10
  140. package/esm/chart/scrubber/DefaultScrubberLabel.js +30 -0
  141. package/esm/chart/scrubber/Scrubber.js +98 -392
  142. package/esm/chart/scrubber/ScrubberBeaconGroup.js +166 -0
  143. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +186 -0
  144. package/esm/chart/scrubber/index.js +3 -1
  145. package/esm/chart/text/ChartText.js +13 -19
  146. package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +4 -3
  147. package/esm/chart/text/index.js +1 -1
  148. package/esm/chart/utils/chart.js +29 -3
  149. package/esm/chart/utils/gradient.js +257 -0
  150. package/esm/chart/utils/index.js +4 -0
  151. package/esm/chart/utils/interpolate.js +644 -0
  152. package/esm/chart/utils/path.js +32 -9
  153. package/esm/chart/utils/point.js +69 -0
  154. package/esm/chart/utils/scrubber.js +132 -0
  155. package/esm/chart/utils/transition.js +111 -0
  156. package/package.json +5 -5
  157. package/dts/chart/Point.d.ts +0 -153
  158. package/dts/chart/Point.d.ts.map +0 -1
  159. package/dts/chart/line/GradientLine.d.ts +0 -42
  160. package/dts/chart/line/GradientLine.d.ts.map +0 -1
  161. package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -93
  162. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
  163. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +0 -7
  164. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +0 -1
  165. package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
  166. package/esm/chart/Point.css +0 -2
  167. package/esm/chart/scrubber/ScrubberBeacon.js +0 -195
@@ -0,0 +1,257 @@
1
+ import { isCategoricalScale } from './scale';
2
+
3
+ /**
4
+ * Defines a color transition point in the gradient
5
+ */
6
+
7
+ /**
8
+ * Defines a gradient.
9
+ */
10
+
11
+ /**
12
+ * Resolves gradient stops, handling both static arrays and function forms.
13
+ * When stops is a function, calls it with the domain bounds.
14
+ */
15
+ const getGradientStops = (stops, domain) => {
16
+ if (typeof stops === 'function') {
17
+ return stops(domain);
18
+ }
19
+ return stops;
20
+ };
21
+
22
+ /**
23
+ * Processes Gradient to gradient configuration for SVG linearGradient.
24
+ * Colors are smoothly interpolated between stops by the browser.
25
+ * Multiple stops at the same offset create hard color transitions.
26
+ */
27
+ const processGradientStops = (stops, scale) => {
28
+ if (stops.length === 0) {
29
+ console.warn('Gradient has no stops - falling back to default');
30
+ return;
31
+ }
32
+
33
+ // Check if stops are in ascending order
34
+ const isOutOfOrder = stops.some((stop, i) => {
35
+ return i > 0 && stop.offset < stops[i - 1].offset;
36
+ });
37
+ if (isOutOfOrder) {
38
+ console.warn("Gradient: stop offsets must be in ascending order");
39
+ return;
40
+ }
41
+ const [rangeMin, rangeMax] = scale.range();
42
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
43
+
44
+ // Convert data value offsets to normalized positions (0-1) using scale
45
+ const normalizedStops = stops.map(stop => {
46
+ var _stop$opacity;
47
+ const stopPosition = scale(stop.offset);
48
+ const normalized = stopPosition === undefined ? 0 : Math.max(0, Math.min(1, Math.abs(stopPosition - rangeMin) / rangeSpan));
49
+ return {
50
+ offset: normalized,
51
+ // Now 0-1 normalized (not data space)
52
+ color: stop.color,
53
+ opacity: (_stop$opacity = stop.opacity) !== null && _stop$opacity !== void 0 ? _stop$opacity : 1
54
+ };
55
+ }).sort((a, b) => a.offset - b.offset);
56
+ return normalizedStops;
57
+ };
58
+
59
+ /**
60
+ * Evaluates the color at a specific data value based on the gradient stops, ignoring opacity.
61
+ * @param stops - The gradient stops configuration
62
+ * @param dataValue - The data value to evaluate (for band scales, this is the index)
63
+ * @param scale - The scale to use for value mapping (handles log scales correctly)
64
+ * @returns The color string at this data value, or undefined if invalid
65
+ */
66
+ export const evaluateGradientAtValue = (stops, dataValue, scale) => {
67
+ if (stops.length === 0) return;
68
+
69
+ // Use srgb color space to match our linearGradient which uses srgb color space
70
+ // https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty
71
+ const colorSpace = 'srgb';
72
+
73
+ // Use scale to map values to positions (handles log scales correctly)
74
+ // For numeric scales: scale(value) returns pixel position
75
+ // We normalize these positions to 0-1 based on the range
76
+ const scaleRange = scale.range();
77
+ const [rangeMin, rangeMax] = Array.isArray(scaleRange) ? scaleRange : [scaleRange, scaleRange]; // fallback for band scales
78
+
79
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
80
+ if (rangeSpan === 0) return stops[0].color;
81
+
82
+ // Map dataValue through scale to get position
83
+ const dataPosition = scale(dataValue);
84
+ if (dataPosition === undefined) return stops[0].color;
85
+
86
+ // Normalize to 0-1 based on range
87
+ const normalizedValue = Math.max(0, Math.min(1, Math.abs(dataPosition - rangeMin) / rangeSpan));
88
+
89
+ // stops already have normalized offsets (0-1), use them directly
90
+ const positions = stops.map(stop => stop.offset);
91
+
92
+ // Find which segment we're in
93
+ if (normalizedValue < positions[0]) {
94
+ return stops[0].color;
95
+ }
96
+ if (normalizedValue >= positions[positions.length - 1]) {
97
+ return stops[stops.length - 1].color;
98
+ }
99
+
100
+ // Check if normalizedValue matches any stop offset exactly (for hard transitions)
101
+ for (let i = 0; i < stops.length; i++) {
102
+ if (Math.abs(normalizedValue - stops[i].offset) < 1e-10) {
103
+ // Found exact match - check if there are multiple stops at this offset (hard transition)
104
+ // Use the LAST color at this offset for hard transitions
105
+ let lastIndexAtOffset = i;
106
+ while (lastIndexAtOffset + 1 < stops.length && Math.abs(stops[lastIndexAtOffset + 1].offset - stops[i].offset) < 1e-10) {
107
+ lastIndexAtOffset++;
108
+ }
109
+ return stops[lastIndexAtOffset].color;
110
+ }
111
+ }
112
+
113
+ // Find the two colors to mix based on normalized positions
114
+ for (let i = 0; i < positions.length - 1; i++) {
115
+ const start = positions[i];
116
+ const end = positions[i + 1];
117
+ if (normalizedValue >= start && normalizedValue <= end) {
118
+ const segmentProgress = (normalizedValue - start) / (end - start);
119
+ return "color-mix(in ".concat(colorSpace, ", ").concat(stops[i + 1].color, " ").concat(segmentProgress * 100, "%, ").concat(stops[i].color, ")");
120
+ }
121
+ }
122
+
123
+ // If we didn't reach any to be mixed, return the last color
124
+ return stops[stops.length - 1].color;
125
+ };
126
+
127
+ /**
128
+ * Creates a gradient configuration for SVG components.
129
+ * Processes a GradientDefinition into a renderable GradientConfig.
130
+ * Supports both numeric scales (linear, log) and categorical scales (band).
131
+ *
132
+ * @param gradient - GradientDefinition configuration (required)
133
+ * @param xScale - X-axis scale (required)
134
+ * @param yScale - Y-axis scale (required)
135
+ * @returns GradientConfig or null if gradient processing fails
136
+ *
137
+ * @example
138
+ * const gradientConfig = useMemo(() => {
139
+ * if (!gradient || !xScale || !yScale) return;
140
+ * return getGradientConfig(gradient, xScale, yScale);
141
+ * }, [gradient, xScale, yScale]);
142
+ *
143
+ * if (gradientConfig) {
144
+ * return (
145
+ * <defs>
146
+ * <Gradient
147
+ * config={gradientConfig}
148
+ * direction={gradient.axis === 'x' ? 'horizontal' : 'vertical'}
149
+ * id={gradientId}
150
+ * />
151
+ * </defs>
152
+ * );
153
+ * }
154
+ */
155
+ export const getGradientConfig = (gradient, xScale, yScale) => {
156
+ if (!gradient) return;
157
+
158
+ // Get the scale based on axis
159
+ const scale = gradient.axis === 'x' ? xScale : yScale;
160
+ if (!scale) return;
161
+
162
+ // Extract domain from scale
163
+ const scaleDomain = scale.domain();
164
+ let domain;
165
+ if (isCategoricalScale(scale)) {
166
+ const domainArray = scaleDomain;
167
+ domain = {
168
+ min: domainArray[0],
169
+ max: domainArray[domainArray.length - 1]
170
+ };
171
+ } else {
172
+ const [min, max] = scaleDomain;
173
+ domain = {
174
+ min,
175
+ max
176
+ };
177
+ }
178
+ const resolvedStops = getGradientStops(gradient.stops, domain);
179
+ return processGradientStops(resolvedStops, scale);
180
+ };
181
+
182
+ /**
183
+ * Determines the baseline value for the gradient area by finding the value
184
+ * within the axis bounds that is closest to the target baseline.
185
+ *
186
+ * @param axisBounds - The min and max bounds of the axis
187
+ * @param baseline - The target baseline value (defaults to 0)
188
+ * @returns The value within bounds closest to the baseline
189
+ */
190
+ export const getBaseline = function (axisBounds) {
191
+ let baseline = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
192
+ const {
193
+ min,
194
+ max
195
+ } = axisBounds;
196
+
197
+ // Normalize to ensure lowerBound <= upperBound
198
+ const lowerBound = Math.min(min, max);
199
+ const upperBound = Math.max(min, max);
200
+
201
+ // If baseline is within the range, use it
202
+ if (lowerBound <= baseline && baseline <= upperBound) return baseline;
203
+
204
+ // Otherwise, return the bound closest to baseline
205
+ return Math.abs(lowerBound - baseline) < Math.abs(upperBound - baseline) ? lowerBound : upperBound;
206
+ };
207
+
208
+ /**
209
+ * Generates a gradient definition for the area chart based on the axis bounds
210
+ * and styling parameters. Ensures gradient stops are in ascending order.
211
+ *
212
+ * @param axisBounds - The min and max bounds of the axis
213
+ * @param baselineValue - The baseline value for the gradient
214
+ * @param fill - The color to use for the gradient
215
+ * @param peakOpacity - Opacity at the peak of the gradient
216
+ * @param baselineOpacity - Opacity at the baseline
217
+ * @returns A gradient definition with y-axis stops in ascending order
218
+ */
219
+ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity) => {
220
+ const {
221
+ min,
222
+ max
223
+ } = axisBounds;
224
+ const lowerBound = Math.min(min, max);
225
+ const upperBound = Math.max(min, max);
226
+ if (lowerBound < baselineValue && baselineValue < upperBound) {
227
+ return {
228
+ axis: 'y',
229
+ stops: [{
230
+ offset: lowerBound,
231
+ color: fill,
232
+ opacity: peakOpacity
233
+ }, {
234
+ offset: baselineValue,
235
+ color: fill,
236
+ opacity: baselineOpacity
237
+ }, {
238
+ offset: upperBound,
239
+ color: fill,
240
+ opacity: peakOpacity
241
+ }]
242
+ };
243
+ }
244
+ const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
245
+ return {
246
+ axis: 'y',
247
+ stops: [{
248
+ offset: peakValue,
249
+ color: fill,
250
+ opacity: peakOpacity
251
+ }, {
252
+ offset: baselineValue,
253
+ color: fill,
254
+ opacity: baselineOpacity
255
+ }].sort((a, b) => a.offset - b.offset)
256
+ };
257
+ };
@@ -3,7 +3,11 @@ export * from './axis';
3
3
  export * from './bar';
4
4
  export * from './chart';
5
5
  export * from './context';
6
+ export * from './gradient';
7
+ export * from './interpolate';
6
8
  export * from './path';
7
9
  export * from './point';
8
10
  export * from './scale';
11
+ export * from './scrubber';
12
+ export * from './transition';
9
13
  // codegen:end