@communitiesuk/svelte-component-library 0.1.19-beta.2 → 0.1.19-beta.21
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/README.md +7 -0
- package/dist/components/data-vis/Histogram.svelte +282 -0
- package/dist/components/data-vis/Histogram.svelte.d.ts +75 -0
- package/dist/components/data-vis/axis/Axis.svelte +145 -34
- package/dist/components/data-vis/axis/Axis.svelte.d.ts +34 -30
- package/dist/components/data-vis/axis/Ticks.svelte +163 -60
- package/dist/components/data-vis/axis/Ticks.svelte.d.ts +26 -30
- package/dist/components/data-vis/line-chart/LineChart.svelte +51 -21
- package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +14 -6
- package/dist/components/data-vis/position-chart/PositionChart.svelte +255 -117
- package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +28 -4
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +39 -34
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +6 -2
- package/dist/components/layout/Footer.svelte +9 -0
- package/dist/components/layout/Footer.svelte.d.ts +1 -0
- package/dist/components/layout/PhaseBanner.svelte +10 -1
- package/dist/components/layout/PhaseBanner.svelte.d.ts +1 -0
- package/dist/components/layout/ServiceNavigation.svelte +19 -1
- package/dist/components/layout/ServiceNavigation.svelte.d.ts +2 -0
- package/dist/components/ui/BasicMultiSelect.svelte +185 -0
- package/dist/components/ui/BasicMultiSelect.svelte.d.ts +8 -0
- package/dist/components/ui/Button.svelte +1 -0
- package/dist/components/ui/Card.svelte +48 -60
- package/dist/components/ui/Card.svelte.d.ts +26 -12
- package/dist/components/ui/CardHeader.svelte +46 -0
- package/dist/components/ui/CardHeader.svelte.d.ts +21 -0
- package/dist/components/ui/ChartExporter.svelte +142 -0
- package/dist/components/ui/ChartExporter.svelte.d.ts +16 -0
- package/dist/components/ui/Details.svelte +10 -2
- package/dist/components/ui/Details.svelte.d.ts +2 -0
- package/dist/components/ui/Masthead.svelte +36 -6
- package/dist/components/ui/Masthead.svelte.d.ts +4 -0
- package/dist/components/ui/PostcodeOrAreaSearch.svelte +12 -0
- package/dist/components/ui/PostcodeOrAreaSearch.svelte.d.ts +4 -0
- package/dist/components/ui/RelatedContent.svelte +4 -1
- package/dist/components/ui/RelatedContent.svelte.d.ts +1 -0
- package/dist/components/ui/SearchAutocomplete.svelte +185 -34
- package/dist/components/ui/SearchAutocomplete.svelte.d.ts +5 -0
- package/dist/components/ui/Tabs.svelte +190 -18
- package/dist/components/ui/Tabs.svelte.d.ts +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -103,6 +103,13 @@ Make sure you are on your main development branch you want to release (e.g., `ma
|
|
|
103
103
|
|
|
104
104
|
Use the `npm version` command to update `package.json` and `package-lock.json`, create a commit, and create an annotated Git tag. Choose **one** of the following based on [Semantic Versioning (SemVer)](https://semver.org/):
|
|
105
105
|
|
|
106
|
+
|
|
107
|
+
- **Pre-Release:**
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm version prerelease --preid=alpha
|
|
111
|
+
```
|
|
112
|
+
|
|
106
113
|
- **Patch Release (Bug fixes, tiny changes - e.g., 1.0.0 → 1.0.1):**
|
|
107
114
|
|
|
108
115
|
```bash
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { scaleLinear } from "d3-scale";
|
|
3
|
+
import { bin, range as d3range } from "d3-array";
|
|
4
|
+
import Axis from "./axis/Axis.svelte";
|
|
5
|
+
import chroma from "chroma-js";
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
averageValue = undefined,
|
|
9
|
+
distribution = [],
|
|
10
|
+
minX = 0,
|
|
11
|
+
maxX = 1,
|
|
12
|
+
minY = 0,
|
|
13
|
+
maxY = 100,
|
|
14
|
+
showXAxis = true,
|
|
15
|
+
showYAxis = true,
|
|
16
|
+
showArrows = true,
|
|
17
|
+
midColor = "#DDDDDD",
|
|
18
|
+
startColor = "#B70000",
|
|
19
|
+
endColor = "#2D6644",
|
|
20
|
+
floor = undefined,
|
|
21
|
+
ceiling = undefined,
|
|
22
|
+
fill = "grey",
|
|
23
|
+
nBins = 10,
|
|
24
|
+
padding = 0,
|
|
25
|
+
height = 50,
|
|
26
|
+
polarity = "standard",
|
|
27
|
+
annotationValue = 0,
|
|
28
|
+
annotationText = "",
|
|
29
|
+
labelFormatter = (tick, index, numberOfTicks, values) => {
|
|
30
|
+
return tick;
|
|
31
|
+
},
|
|
32
|
+
containerWidth = $bindable(100),
|
|
33
|
+
numberOfTicks,
|
|
34
|
+
customColorScale = undefined,
|
|
35
|
+
skew = true,
|
|
36
|
+
showGridlines = true,
|
|
37
|
+
showTickMarks = false,
|
|
38
|
+
tickStrokeWidth = 0.25,
|
|
39
|
+
barStrokeWidth = 0,
|
|
40
|
+
barStrokeColor = "white",
|
|
41
|
+
topLabel = true,
|
|
42
|
+
includeOutliers = true,
|
|
43
|
+
} = $props();
|
|
44
|
+
|
|
45
|
+
let xTicks = $state([]);
|
|
46
|
+
let yTicks = $state([]);
|
|
47
|
+
|
|
48
|
+
let xTickFirst = $derived(xTicks.length ? xTicks[0] : 0);
|
|
49
|
+
let xTickLast = $derived(xTicks.length ? xTicks.at(-1) : 1);
|
|
50
|
+
|
|
51
|
+
let domainXMin = $derived(Math.min(xTickFirst, xTickLast));
|
|
52
|
+
let domainXMax = $derived(Math.max(xTickFirst, xTickLast));
|
|
53
|
+
|
|
54
|
+
let yTickFirst = $derived(yTicks.length ? yTicks[0] : 0);
|
|
55
|
+
let yTickLast = $derived(yTicks.length ? yTicks.at(-1) : 1);
|
|
56
|
+
|
|
57
|
+
let domainYMin = $derived(Math.min(yTickFirst, yTickLast));
|
|
58
|
+
let domainYMax = $derived(Math.max(yTickFirst, yTickLast));
|
|
59
|
+
|
|
60
|
+
let useRange = $derived(
|
|
61
|
+
polarity === "standard"
|
|
62
|
+
? [0, containerWidth - padding]
|
|
63
|
+
: [containerWidth - padding, 0],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
let xScale = $derived(
|
|
67
|
+
scaleLinear().domain([domainXMin, domainXMax]).range(useRange),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const segmentScale = $derived(
|
|
71
|
+
scaleLinear().domain([0, nBins]).range([domainXMin, domainXMax]),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const binThresholds = $derived(d3range(1, nBins).map(segmentScale));
|
|
75
|
+
|
|
76
|
+
const binner = $derived(
|
|
77
|
+
bin().domain([domainXMin, domainXMax]).thresholds(binThresholds),
|
|
78
|
+
);
|
|
79
|
+
const clampedDistribution = $derived(
|
|
80
|
+
distribution.map((d) => Math.min(Math.max(d, domainXMin), domainXMax)),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const binnedDistribution = $derived(
|
|
84
|
+
binner(includeOutliers ? clampedDistribution : distribution),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const bins = $derived(
|
|
88
|
+
polarity === "reverse"
|
|
89
|
+
? binnedDistribution.toReversed()
|
|
90
|
+
: binnedDistribution,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const proportionsInBins = $derived(
|
|
94
|
+
bins.map((b) => b.length / distribution.length),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
let proportionInExtremeBins = $derived([
|
|
98
|
+
proportionsInBins[0],
|
|
99
|
+
proportionsInBins.at(-1),
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
let yScale = $derived(
|
|
103
|
+
scaleLinear()
|
|
104
|
+
.domain([0, Math.max(...bins.map((b) => b.length))])
|
|
105
|
+
.range([0, height]),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
function interpolateColors(
|
|
109
|
+
startColor,
|
|
110
|
+
endColor,
|
|
111
|
+
nSegments,
|
|
112
|
+
midColor = null,
|
|
113
|
+
skew,
|
|
114
|
+
) {
|
|
115
|
+
const colorArray = [startColor, midColor, endColor].filter(Boolean);
|
|
116
|
+
|
|
117
|
+
if (!skew) {
|
|
118
|
+
return chroma.scale(colorArray).colors(nSegments);
|
|
119
|
+
} else {
|
|
120
|
+
const extremeColors = chroma
|
|
121
|
+
.scale([startColor, midColor, endColor])
|
|
122
|
+
.padding([
|
|
123
|
+
proportionInExtremeBins[0] / 2,
|
|
124
|
+
proportionInExtremeBins[1] / 2,
|
|
125
|
+
])
|
|
126
|
+
.colors(2);
|
|
127
|
+
|
|
128
|
+
const averageNormalised =
|
|
129
|
+
(averageValue - xTickFirst) / (xTickLast - xTickFirst);
|
|
130
|
+
|
|
131
|
+
const binColors = chroma
|
|
132
|
+
.scale([extremeColors[0], midColor, extremeColors[1]])
|
|
133
|
+
.domain([
|
|
134
|
+
0,
|
|
135
|
+
polarity === "reverse" ? 1 - averageNormalised : averageNormalised,
|
|
136
|
+
1,
|
|
137
|
+
])
|
|
138
|
+
.colors(10);
|
|
139
|
+
|
|
140
|
+
return binColors;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let colorScale = $derived(
|
|
145
|
+
customColorScale ??
|
|
146
|
+
interpolateColors(startColor, endColor, nBins, midColor, skew),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
$inspect({ colorScale });
|
|
150
|
+
|
|
151
|
+
const layout = $derived.by(() => {
|
|
152
|
+
let y = 0;
|
|
153
|
+
|
|
154
|
+
const topLabelY = topLabel ? y : null;
|
|
155
|
+
if (topLabel) y += 20;
|
|
156
|
+
|
|
157
|
+
const annotationY = annotationText ? y : null;
|
|
158
|
+
if (annotationText) y += 25;
|
|
159
|
+
|
|
160
|
+
const chartY = y;
|
|
161
|
+
y += height;
|
|
162
|
+
|
|
163
|
+
const xAxisY = showXAxis ? y : null;
|
|
164
|
+
if (showXAxis) y += 25;
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
topLabelY,
|
|
168
|
+
annotationY,
|
|
169
|
+
chartY,
|
|
170
|
+
xAxisY,
|
|
171
|
+
totalHeight: y,
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
{#key containerWidth}
|
|
177
|
+
<div class="scale-container" bind:clientWidth={containerWidth}>
|
|
178
|
+
<svg width={containerWidth} height={layout.totalHeight}>
|
|
179
|
+
<g transform="translate({padding / 2}, 0)">
|
|
180
|
+
{#if topLabel && layout.topLabelY !== null}
|
|
181
|
+
<text x={0} y={layout.topLabelY + 14} fill="#666" font-size="0.75em">
|
|
182
|
+
Number of areas
|
|
183
|
+
</text>
|
|
184
|
+
{/if}
|
|
185
|
+
|
|
186
|
+
{#if annotationText && layout.annotationY !== null}
|
|
187
|
+
<g
|
|
188
|
+
transform="translate({xScale(
|
|
189
|
+
annotationValue,
|
|
190
|
+
)}, {layout.annotationY})"
|
|
191
|
+
>
|
|
192
|
+
<text
|
|
193
|
+
fill="#555555"
|
|
194
|
+
font-size="0.8em"
|
|
195
|
+
text-anchor="middle"
|
|
196
|
+
dominant-baseline="hanging"
|
|
197
|
+
>
|
|
198
|
+
<tspan x="0" dy="0">{annotationText}</tspan>
|
|
199
|
+
<tspan x="0" dy="12">▼</tspan>
|
|
200
|
+
</text>
|
|
201
|
+
</g>
|
|
202
|
+
{/if}
|
|
203
|
+
|
|
204
|
+
<g transform="translate(0, {layout.chartY})">
|
|
205
|
+
{#if showYAxis}
|
|
206
|
+
<Axis
|
|
207
|
+
bind:ticksArray={yTicks}
|
|
208
|
+
chartHeight={height}
|
|
209
|
+
chartWidth={containerWidth - padding}
|
|
210
|
+
orientation={{ axis: "y", position: "left" }}
|
|
211
|
+
min={minY}
|
|
212
|
+
max={maxY}
|
|
213
|
+
domain={[yTickLast, 0]}
|
|
214
|
+
range={[0, height]}
|
|
215
|
+
fontSize={0}
|
|
216
|
+
numberOfTicks={3}
|
|
217
|
+
{showGridlines}
|
|
218
|
+
{showTickMarks}
|
|
219
|
+
strokeWidth={tickStrokeWidth}
|
|
220
|
+
/>
|
|
221
|
+
{/if}
|
|
222
|
+
|
|
223
|
+
{#each bins as bin, i}
|
|
224
|
+
{#key bin.x0}
|
|
225
|
+
{@const fullWidth = Math.abs(xScale(bin.x1) - xScale(bin.x0))}
|
|
226
|
+
{@const barWidth = fullWidth * 0.97}
|
|
227
|
+
{@const offset = (fullWidth - barWidth) / 2}
|
|
228
|
+
<rect
|
|
229
|
+
x={(polarity === "reverse" ? xScale(bin.x1) : xScale(bin.x0)) +
|
|
230
|
+
offset}
|
|
231
|
+
y={height - yScale(bin.length)}
|
|
232
|
+
width={barWidth}
|
|
233
|
+
height={yScale(bin.length)}
|
|
234
|
+
fill={fill ?? colorScale[i]}
|
|
235
|
+
></rect>
|
|
236
|
+
{/key}
|
|
237
|
+
{/each}
|
|
238
|
+
</g>
|
|
239
|
+
|
|
240
|
+
{#if showXAxis && layout.xAxisY !== null}
|
|
241
|
+
<g transform="translate(0, {layout.xAxisY})">
|
|
242
|
+
<Axis
|
|
243
|
+
bind:ticksArray={xTicks}
|
|
244
|
+
chartHeight={height}
|
|
245
|
+
chartWidth={containerWidth - padding}
|
|
246
|
+
orientation={{ axis: "x", position: "bottom" }}
|
|
247
|
+
domain={[xTickFirst, xTickLast]}
|
|
248
|
+
min={minX}
|
|
249
|
+
max={maxX}
|
|
250
|
+
range={useRange}
|
|
251
|
+
fontSize={13}
|
|
252
|
+
{floor}
|
|
253
|
+
{ceiling}
|
|
254
|
+
{labelFormatter}
|
|
255
|
+
{numberOfTicks}
|
|
256
|
+
/>
|
|
257
|
+
</g>
|
|
258
|
+
{/if}
|
|
259
|
+
</g>
|
|
260
|
+
</svg>
|
|
261
|
+
</div>
|
|
262
|
+
{/key}
|
|
263
|
+
|
|
264
|
+
<div style="content-visibility: hidden;">
|
|
265
|
+
{#if !showXAxis}
|
|
266
|
+
<Axis
|
|
267
|
+
bind:ticksArray={xTicks}
|
|
268
|
+
chartHeight={height}
|
|
269
|
+
chartWidth={containerWidth - padding}
|
|
270
|
+
orientation={{ axis: "x", position: "bottom" }}
|
|
271
|
+
domain={[xTickFirst, xTickLast]}
|
|
272
|
+
min={minX}
|
|
273
|
+
max={maxX}
|
|
274
|
+
range={useRange}
|
|
275
|
+
fontSize={13}
|
|
276
|
+
{floor}
|
|
277
|
+
{ceiling}
|
|
278
|
+
{labelFormatter}
|
|
279
|
+
{numberOfTicks}
|
|
280
|
+
></Axis>
|
|
281
|
+
{/if}
|
|
282
|
+
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export default Histogram;
|
|
2
|
+
type Histogram = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const Histogram: import("svelte").Component<{
|
|
7
|
+
averageValue?: any;
|
|
8
|
+
distribution?: any[];
|
|
9
|
+
minX?: number;
|
|
10
|
+
maxX?: number;
|
|
11
|
+
minY?: number;
|
|
12
|
+
maxY?: number;
|
|
13
|
+
showXAxis?: boolean;
|
|
14
|
+
showYAxis?: boolean;
|
|
15
|
+
showArrows?: boolean;
|
|
16
|
+
midColor?: string;
|
|
17
|
+
startColor?: string;
|
|
18
|
+
endColor?: string;
|
|
19
|
+
floor?: any;
|
|
20
|
+
ceiling?: any;
|
|
21
|
+
fill?: string;
|
|
22
|
+
nBins?: number;
|
|
23
|
+
padding?: number;
|
|
24
|
+
height?: number;
|
|
25
|
+
polarity?: string;
|
|
26
|
+
annotationValue?: number;
|
|
27
|
+
annotationText?: string;
|
|
28
|
+
labelFormatter?: Function;
|
|
29
|
+
containerWidth?: number;
|
|
30
|
+
numberOfTicks: any;
|
|
31
|
+
customColorScale?: any;
|
|
32
|
+
skew?: boolean;
|
|
33
|
+
showGridlines?: boolean;
|
|
34
|
+
showTickMarks?: boolean;
|
|
35
|
+
tickStrokeWidth?: number;
|
|
36
|
+
barStrokeWidth?: number;
|
|
37
|
+
barStrokeColor?: string;
|
|
38
|
+
topLabel?: boolean;
|
|
39
|
+
includeOutliers?: boolean;
|
|
40
|
+
}, {}, "containerWidth">;
|
|
41
|
+
type $$ComponentProps = {
|
|
42
|
+
averageValue?: any;
|
|
43
|
+
distribution?: any[];
|
|
44
|
+
minX?: number;
|
|
45
|
+
maxX?: number;
|
|
46
|
+
minY?: number;
|
|
47
|
+
maxY?: number;
|
|
48
|
+
showXAxis?: boolean;
|
|
49
|
+
showYAxis?: boolean;
|
|
50
|
+
showArrows?: boolean;
|
|
51
|
+
midColor?: string;
|
|
52
|
+
startColor?: string;
|
|
53
|
+
endColor?: string;
|
|
54
|
+
floor?: any;
|
|
55
|
+
ceiling?: any;
|
|
56
|
+
fill?: string;
|
|
57
|
+
nBins?: number;
|
|
58
|
+
padding?: number;
|
|
59
|
+
height?: number;
|
|
60
|
+
polarity?: string;
|
|
61
|
+
annotationValue?: number;
|
|
62
|
+
annotationText?: string;
|
|
63
|
+
labelFormatter?: Function;
|
|
64
|
+
containerWidth?: number;
|
|
65
|
+
numberOfTicks: any;
|
|
66
|
+
customColorScale?: any;
|
|
67
|
+
skew?: boolean;
|
|
68
|
+
showGridlines?: boolean;
|
|
69
|
+
showTickMarks?: boolean;
|
|
70
|
+
tickStrokeWidth?: number;
|
|
71
|
+
barStrokeWidth?: number;
|
|
72
|
+
barStrokeColor?: string;
|
|
73
|
+
topLabel?: boolean;
|
|
74
|
+
includeOutliers?: boolean;
|
|
75
|
+
};
|
|
@@ -1,51 +1,162 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
scaleLinear,
|
|
4
|
+
type ScaleContinuousNumeric,
|
|
5
|
+
type ScaleLinear,
|
|
6
|
+
} from "d3-scale";
|
|
3
7
|
import Ticks from "./Ticks.svelte";
|
|
4
8
|
|
|
9
|
+
type AxisName = "x" | "y";
|
|
10
|
+
type AxisPosition = "bottom" | "top" | "left" | "right";
|
|
11
|
+
type Orientation = { axis: AxisName; position: AxisPosition };
|
|
12
|
+
type AxisProjector = (value: number) => number;
|
|
13
|
+
type LabelFormatter = (
|
|
14
|
+
tick: number,
|
|
15
|
+
index: number,
|
|
16
|
+
ticksArrayLength: number,
|
|
17
|
+
) => string | number;
|
|
18
|
+
|
|
19
|
+
type Polarity = "standard" | "reverse";
|
|
20
|
+
|
|
5
21
|
let {
|
|
6
|
-
chartHeight,
|
|
7
|
-
chartWidth,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
chartHeight = 100,
|
|
23
|
+
chartWidth = $bindable<number>(200),
|
|
24
|
+
|
|
25
|
+
numberOfTicks = undefined as number | undefined,
|
|
26
|
+
|
|
27
|
+
// Bindable, but avoid binding undefined – initialize as [] for safety
|
|
28
|
+
ticksArray = $bindable<number[]>([]),
|
|
29
|
+
|
|
30
|
+
// Values to derive ticks/domain from if ticksArray not provided
|
|
31
|
+
min = undefined as number | undefined,
|
|
32
|
+
max = undefined as number | undefined,
|
|
33
|
+
|
|
34
|
+
orientation = { axis: "x", position: "bottom" } as Orientation,
|
|
35
|
+
|
|
36
|
+
floor = undefined as number | undefined,
|
|
37
|
+
ceiling = undefined as number | undefined,
|
|
38
|
+
|
|
39
|
+
paddingTop = 100,
|
|
40
|
+
paddingBottom = 100,
|
|
41
|
+
paddingLeft = 0,
|
|
42
|
+
paddingRight = 0,
|
|
43
|
+
|
|
44
|
+
labelFormatter = undefined as LabelFormatter | undefined,
|
|
45
|
+
|
|
46
|
+
// --- New inputs for D3 scale + optional overrides ---
|
|
47
|
+
// A ready-made D3 continuous scale (linear/log/time, etc.)
|
|
48
|
+
// For this component we use numeric-only; time scales also implement numeric mapping.
|
|
49
|
+
scale = undefined as ScaleContinuousNumeric<number, number> | undefined,
|
|
50
|
+
|
|
51
|
+
// Optional overrides for domain/range applied to a COPY of the provided scale
|
|
52
|
+
domain = undefined as [number, number] | undefined,
|
|
53
|
+
range = undefined as [number, number] | undefined,
|
|
54
|
+
fontSize = 19,
|
|
55
|
+
polarity = "standard",
|
|
56
|
+
showGridlines = false,
|
|
57
|
+
showTickMarks = false,
|
|
58
|
+
strokeWidth = 2,
|
|
59
|
+
}: {
|
|
60
|
+
chartHeight?: number;
|
|
61
|
+
chartWidth?: number;
|
|
62
|
+
numberOfTicks?: number;
|
|
63
|
+
ticksArray?: number[];
|
|
64
|
+
min?: number;
|
|
65
|
+
max?: number;
|
|
66
|
+
|
|
67
|
+
orientation?: Orientation;
|
|
68
|
+
floor?: number;
|
|
69
|
+
ceiling?: number;
|
|
70
|
+
paddingTop?: number;
|
|
71
|
+
paddingBottom?: number;
|
|
72
|
+
paddingLeft?: number;
|
|
73
|
+
paddingRight?: number;
|
|
74
|
+
labelFormatter?: LabelFormatter;
|
|
75
|
+
|
|
76
|
+
// New
|
|
77
|
+
scale?: ScaleContinuousNumeric<number, number>;
|
|
78
|
+
domain?: [number, number];
|
|
79
|
+
range?: [number, number];
|
|
80
|
+
fontSize?: number;
|
|
81
|
+
polarity?: Polarity;
|
|
82
|
+
gridlines?: Boolean;
|
|
83
|
+
strokeWidth?: Number;
|
|
84
|
+
showGridlines?: Boolean;
|
|
85
|
+
showTickMarks?: Boolean;
|
|
18
86
|
} = $props();
|
|
87
|
+
|
|
88
|
+
// --- Helpers to compute default domain/range when not supplied ---
|
|
89
|
+
const innerWidth = $derived(Math.max(0, chartWidth));
|
|
90
|
+
const innerHeight = $derived(Math.max(0, chartHeight));
|
|
91
|
+
|
|
92
|
+
function computeDefaultDomain(): [number, number] {
|
|
93
|
+
const arr =
|
|
94
|
+
(ticksArray && ticksArray.length ? ticksArray : [min, max]) ?? [];
|
|
95
|
+
const dMin =
|
|
96
|
+
floor ?? (arr.length ? arr.reduce((a, b) => (a < b ? a : b)) : 0);
|
|
97
|
+
const dMax =
|
|
98
|
+
ceiling ?? (arr.length ? arr.reduce((a, b) => (a > b ? a : b)) : 1);
|
|
99
|
+
return [dMin, dMax];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function computeDefaultRange(innerWidth, innerHeight): [number, number] {
|
|
103
|
+
if (orientation.axis === "x") {
|
|
104
|
+
return [0, innerWidth];
|
|
105
|
+
} else {
|
|
106
|
+
return [innerHeight, 0];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//Returns d3 scale function
|
|
110
|
+
const resolvedScale = $derived(() => {
|
|
111
|
+
const base: ScaleContinuousNumeric<number, number> = scale
|
|
112
|
+
? scale.copy()
|
|
113
|
+
: scaleLinear<number, number>();
|
|
114
|
+
|
|
115
|
+
const useDomain = domain ?? computeDefaultDomain();
|
|
116
|
+
base.domain(useDomain);
|
|
117
|
+
|
|
118
|
+
const useRange = range ?? computeDefaultRange(innerWidth, innerHeight);
|
|
119
|
+
base.range(useRange);
|
|
120
|
+
|
|
121
|
+
return base;
|
|
122
|
+
});
|
|
123
|
+
const axisFunction: AxisProjector = $derived((v: number) => resolvedScale(v));
|
|
19
124
|
</script>
|
|
20
125
|
|
|
21
126
|
<g
|
|
22
127
|
data-role="{orientation.axis}-axis"
|
|
23
|
-
transform="translate({orientation.position
|
|
128
|
+
transform="translate({orientation.position !== 'right'
|
|
24
129
|
? 0
|
|
25
130
|
: chartWidth},{orientation.position === 'bottom' ? chartHeight : 0})"
|
|
26
131
|
>
|
|
27
132
|
<line
|
|
28
|
-
x1=
|
|
133
|
+
x1={range[0]}
|
|
29
134
|
y1="0"
|
|
30
|
-
x2={orientation.axis === "x" ?
|
|
135
|
+
x2={orientation.axis === "x" ? range[1] : 0}
|
|
31
136
|
y2={orientation.axis === "y" ? chartHeight : 0}
|
|
32
|
-
stroke="
|
|
137
|
+
stroke="grey"
|
|
33
138
|
stroke-width="2px"
|
|
34
139
|
></line>
|
|
35
|
-
{#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
140
|
+
{#if ticksArray || (min && max)}
|
|
141
|
+
{#key numberOfTicks}
|
|
142
|
+
<Ticks
|
|
143
|
+
bind:ticksArray
|
|
144
|
+
{chartWidth}
|
|
145
|
+
{chartHeight}
|
|
146
|
+
{axisFunction}
|
|
147
|
+
{min}
|
|
148
|
+
{max}
|
|
149
|
+
{numberOfTicks}
|
|
150
|
+
{orientation}
|
|
151
|
+
{floor}
|
|
152
|
+
{ceiling}
|
|
153
|
+
{labelFormatter}
|
|
154
|
+
{fontSize}
|
|
155
|
+
{polarity}
|
|
156
|
+
{showGridlines}
|
|
157
|
+
{showTickMarks}
|
|
158
|
+
{strokeWidth}
|
|
159
|
+
/>
|
|
160
|
+
{/key}
|
|
161
|
+
{/if}
|
|
51
162
|
</g>
|
|
@@ -1,33 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { type ScaleContinuousNumeric } from "d3-scale";
|
|
2
|
+
type AxisName = "x" | "y";
|
|
3
|
+
type AxisPosition = "bottom" | "top" | "left" | "right";
|
|
4
|
+
type Orientation = {
|
|
5
|
+
axis: AxisName;
|
|
6
|
+
position: AxisPosition;
|
|
5
7
|
};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
chartWidth: any;
|
|
9
|
-
numberOfTicks: any;
|
|
10
|
-
ticksArray?: any;
|
|
11
|
-
axisFunction: any;
|
|
12
|
-
values: any;
|
|
13
|
-
orientation: any;
|
|
14
|
-
prefix: any;
|
|
15
|
-
suffix: any;
|
|
16
|
-
floor: any;
|
|
17
|
-
ceiling: any;
|
|
18
|
-
yearsInput: any;
|
|
19
|
-
}, {}, "ticksArray">;
|
|
8
|
+
type LabelFormatter = (tick: number, index: number, ticksArrayLength: number) => string | number;
|
|
9
|
+
type Polarity = "standard" | "reverse";
|
|
20
10
|
type $$ComponentProps = {
|
|
21
|
-
chartHeight
|
|
22
|
-
chartWidth
|
|
23
|
-
numberOfTicks
|
|
24
|
-
ticksArray?:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
orientation
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
11
|
+
chartHeight?: number;
|
|
12
|
+
chartWidth?: number;
|
|
13
|
+
numberOfTicks?: number;
|
|
14
|
+
ticksArray?: number[];
|
|
15
|
+
min?: number;
|
|
16
|
+
max?: number;
|
|
17
|
+
orientation?: Orientation;
|
|
18
|
+
floor?: number;
|
|
19
|
+
ceiling?: number;
|
|
20
|
+
paddingTop?: number;
|
|
21
|
+
paddingBottom?: number;
|
|
22
|
+
paddingLeft?: number;
|
|
23
|
+
paddingRight?: number;
|
|
24
|
+
labelFormatter?: LabelFormatter;
|
|
25
|
+
scale?: ScaleContinuousNumeric<number, number>;
|
|
26
|
+
domain?: [number, number];
|
|
27
|
+
range?: [number, number];
|
|
28
|
+
fontSize?: number;
|
|
29
|
+
polarity?: Polarity;
|
|
30
|
+
gridlines?: Boolean;
|
|
31
|
+
strokeWidth?: Number;
|
|
32
|
+
showGridlines?: Boolean;
|
|
33
|
+
showTickMarks?: Boolean;
|
|
33
34
|
};
|
|
35
|
+
declare const Axis: import("svelte").Component<$$ComponentProps, {}, "ticksArray" | "chartWidth">;
|
|
36
|
+
type Axis = ReturnType<typeof Axis>;
|
|
37
|
+
export default Axis;
|