@juspay/svelte-ui-components 2.107.0 → 2.108.1
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.
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
xAxisCategories,
|
|
49
49
|
xTickFormat,
|
|
50
50
|
yTickFormat,
|
|
51
|
+
yIntegerTicks = false,
|
|
51
52
|
aspectRatio = 16 / 9,
|
|
52
53
|
minHeight = 0,
|
|
53
54
|
maxHeight = DEFAULT_CHART_MAX_HEIGHT,
|
|
@@ -581,6 +582,7 @@
|
|
|
581
582
|
orientation="left"
|
|
582
583
|
scale={yScale}
|
|
583
584
|
tickCount={yTickCount}
|
|
585
|
+
integerTicks={yIntegerTicks}
|
|
584
586
|
{showGridlines}
|
|
585
587
|
gridlineLength={dims.innerWidth}
|
|
586
588
|
label={yAxisLabel}
|
|
@@ -93,6 +93,13 @@ export type OptionalLineChartProperties = {
|
|
|
93
93
|
xTickFormat?: (value: number | string) => string;
|
|
94
94
|
/** Formatter for Y axis tick labels. */
|
|
95
95
|
yTickFormat?: (value: number | string) => string;
|
|
96
|
+
/**
|
|
97
|
+
* Snap Y-axis ticks to whole numbers (mirrors the X axis' category
|
|
98
|
+
* behaviour). Use for count-style series (orders, items) where a small
|
|
99
|
+
* domain would otherwise produce fractional ticks (0, 0.5, 1, 1.5, 2) —
|
|
100
|
+
* `yTickFormat` only changes label text, not tick placement.
|
|
101
|
+
*/
|
|
102
|
+
yIntegerTicks?: boolean;
|
|
96
103
|
/** Width-to-height ratio for the chart. */
|
|
97
104
|
aspectRatio?: number;
|
|
98
105
|
/** Minimum chart height in pixels, regardless of computed aspect-ratio height. */
|
package/dist/_chart/geometry.js
CHANGED
|
@@ -145,30 +145,49 @@ export function computeSankeyLayout(nodes, links, width, height, nodeWidth = 16,
|
|
|
145
145
|
}
|
|
146
146
|
const colWidth = maxCol === 0 ? 0 : (width - nodeWidth) / maxCol;
|
|
147
147
|
const columnPadding = new Map();
|
|
148
|
-
//
|
|
148
|
+
// Global px-per-value scale (d3-sankey's `ky`): the tightest column — least
|
|
149
|
+
// height left after node gaps — sets one scale for the whole diagram, so a
|
|
150
|
+
// given value renders the same height in every column. The previous layout
|
|
151
|
+
// stretched every column to fill the full plot height, which gave each
|
|
152
|
+
// column its own scale; link widths (sized at the source column's scale)
|
|
153
|
+
// then overflowed target nodes laid out at a smaller scale, and the ribbon
|
|
154
|
+
// stacks spilled below the bottom node row.
|
|
155
|
+
let pxPerValue = Number.POSITIVE_INFINITY;
|
|
156
|
+
for (const ids of columnGroups.values()) {
|
|
157
|
+
const totalValue = ids.reduce((s, id) => s + (nodeValues.get(id) ?? 0), 0);
|
|
158
|
+
const availableHeight = height - (ids.length - 1) * nodePadding;
|
|
159
|
+
if (totalValue > 0 && availableHeight > 0) {
|
|
160
|
+
pxPerValue = Math.min(pxPerValue, availableHeight / totalValue);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!Number.isFinite(pxPerValue)) {
|
|
164
|
+
// All-zero data: nothing carries volume, every bar collapses to the minimum.
|
|
165
|
+
pxPerValue = 0;
|
|
166
|
+
}
|
|
167
|
+
const linkRenderWidth = (value) => Math.max(minLinkWidth, value * pxPerValue);
|
|
168
|
+
// Initialize y positions. A node must be at least as tall as its thicker
|
|
169
|
+
// side's rendered link stack: every ribbon is clamped to minLinkWidth, so a
|
|
170
|
+
// node fanning into many near-zero links would otherwise be shorter than the
|
|
171
|
+
// inflated stack attached to it.
|
|
149
172
|
const nodeY = new Map();
|
|
150
173
|
const nodeH = new Map();
|
|
151
174
|
for (const [col, ids] of columnGroups) {
|
|
152
|
-
const totalValue = ids.reduce((s, id) => s + (nodeValues.get(id) ?? 0), 0);
|
|
153
175
|
const gapCount = ids.length - 1;
|
|
154
|
-
const availableHeight = height - gapCount * nodePadding;
|
|
155
176
|
const renderedHeights = ids.map((id) => {
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
return Math.max(minLinkWidth,
|
|
177
|
+
const outStack = (outgoing.get(id) ?? []).reduce((s, link) => s + linkRenderWidth(link.value), 0);
|
|
178
|
+
const inStack = (incoming.get(id) ?? []).reduce((s, link) => s + linkRenderWidth(link.value), 0);
|
|
179
|
+
return Math.max(minLinkWidth, (nodeValues.get(id) ?? 0) * pxPerValue, outStack, inStack);
|
|
159
180
|
});
|
|
160
181
|
const sumRendered = renderedHeights.reduce((s, h) => s + h, 0);
|
|
161
182
|
const paddingBudget = gapCount > 0 ? (height - sumRendered) / gapCount : 0;
|
|
162
183
|
const effectivePadding = Math.max(0, Math.min(nodePadding, paddingBudget));
|
|
163
|
-
const scale = sumRendered > height && sumRendered > 0 ? height / sumRendered : 1;
|
|
164
184
|
columnPadding.set(col, effectivePadding);
|
|
165
185
|
let y = 0;
|
|
166
186
|
for (let index = 0; index < ids.length; index++) {
|
|
167
187
|
const id = ids[index];
|
|
168
|
-
const renderedH = renderedHeights[index] * scale;
|
|
169
188
|
nodeY.set(id, y);
|
|
170
|
-
nodeH.set(id,
|
|
171
|
-
y +=
|
|
189
|
+
nodeH.set(id, renderedHeights[index]);
|
|
190
|
+
y += renderedHeights[index] + effectivePadding;
|
|
172
191
|
}
|
|
173
192
|
}
|
|
174
193
|
// Iterative relaxation (upstream pass)
|
|
@@ -245,11 +264,11 @@ export function computeSankeyLayout(nodes, links, width, height, nodeWidth = 16,
|
|
|
245
264
|
}));
|
|
246
265
|
const nodeById = new Map(computedNodes.map((n) => [n.id, n]));
|
|
247
266
|
const linkKey = (l) => `${l.source}${l.target}`;
|
|
267
|
+
// Link widths use the same global scale as node heights, so each node's link
|
|
268
|
+
// stack fills its bar exactly and never runs past its bottom edge.
|
|
248
269
|
const linkWidths = new Map();
|
|
249
270
|
for (const l of links) {
|
|
250
|
-
|
|
251
|
-
const sourceH = nodeH.get(l.source) ?? 0;
|
|
252
|
-
linkWidths.set(linkKey(l), Math.max(minLinkWidth, (l.value / Math.max(sVal, 1)) * sourceH));
|
|
271
|
+
linkWidths.set(linkKey(l), linkRenderWidth(l.value));
|
|
253
272
|
}
|
|
254
273
|
const linkSy = new Map();
|
|
255
274
|
const linkTy = new Map();
|