@communitiesuk/svelte-component-library 0.1.19-beta.3 → 0.1.19-beta.33
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/content/Tag.svelte +32 -0
- package/dist/components/content/Tag.svelte.d.ts +13 -0
- package/dist/components/data-vis/Histogram.svelte +302 -0
- package/dist/components/data-vis/Histogram.svelte.d.ts +75 -0
- package/dist/components/data-vis/axis/Axis.svelte +217 -34
- package/dist/components/data-vis/axis/Axis.svelte.d.ts +38 -30
- package/dist/components/data-vis/axis/Ticks.svelte +142 -78
- package/dist/components/data-vis/axis/Ticks.svelte.d.ts +28 -31
- 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/line-chart/ValueLabel.svelte +2 -1
- package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +2 -0
- package/dist/components/data-vis/position-chart/PositionChart.svelte +278 -122
- package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +37 -5
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +59 -48
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +4 -4
- 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 +716 -0
- package/dist/components/ui/BasicMultiSelect.svelte.d.ts +18 -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/CheckBox.svelte +1 -0
- package/dist/components/ui/Details.svelte +47 -8
- package/dist/components/ui/Details.svelte.d.ts +8 -10
- package/dist/components/ui/Masthead.svelte +44 -6
- package/dist/components/ui/Masthead.svelte.d.ts +6 -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 +69 -44
- package/dist/components/ui/SearchAutocomplete.svelte.d.ts +1 -0
- package/dist/components/ui/Select.svelte +18 -7
- package/dist/components/ui/Tabs.svelte +192 -18
- package/dist/components/ui/Tabs.svelte.d.ts +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -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,32 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
let { text, color } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<strong class="govuk-tag trend-tag {color ? `govuk-tag--${color}` : ''}"
|
|
6
|
+
>{text}</strong
|
|
7
|
+
>
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
.govuk-tag.trend-tag {
|
|
11
|
+
padding: 0.25rem 0.625rem;
|
|
12
|
+
border-bottom: 2px solid #b1b4b6;
|
|
13
|
+
font-size: 1rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.govuk-tag.trend-tag.govuk-tag--red {
|
|
17
|
+
border-bottom-color: #ff5e5e;
|
|
18
|
+
}
|
|
19
|
+
.govuk-tag.trend-tag.govuk-tag--orange {
|
|
20
|
+
border-bottom-color: #ffaf4a;
|
|
21
|
+
}
|
|
22
|
+
.govuk-tag.trend-tag.govuk-tag--green {
|
|
23
|
+
border-bottom-color: #0fbd54;
|
|
24
|
+
}
|
|
25
|
+
.govuk-tag.trend-tag.govuk-tag--grey {
|
|
26
|
+
border-bottom-color: #b1b4b6;
|
|
27
|
+
}
|
|
28
|
+
.govuk-tag.trend-tag.govuk-tag--white {
|
|
29
|
+
background-color: #fbfbfb;
|
|
30
|
+
border-bottom-color: #cdcdcd;
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default Tag;
|
|
2
|
+
type Tag = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const Tag: import("svelte").Component<{
|
|
7
|
+
text: any;
|
|
8
|
+
color: any;
|
|
9
|
+
}, {}, "">;
|
|
10
|
+
type $$ComponentProps = {
|
|
11
|
+
text: any;
|
|
12
|
+
color: any;
|
|
13
|
+
};
|
|
@@ -0,0 +1,302 @@
|
|
|
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 useRange = $derived(
|
|
46
|
+
polarity === "standard"
|
|
47
|
+
? [0, containerWidth - padding]
|
|
48
|
+
: [containerWidth - padding, 0],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
let xValueFirst = $derived(polarity === "standard" ? minX : maxX);
|
|
52
|
+
let xValueLast = $derived(polarity === "standard" ? maxX : minX);
|
|
53
|
+
|
|
54
|
+
let xScale = $derived(scaleLinear().domain([minX, maxX]).range(useRange));
|
|
55
|
+
|
|
56
|
+
const segmentScale = $derived(
|
|
57
|
+
scaleLinear().domain([0, nBins]).range([minX, maxX]),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const binThresholds = $derived(d3range(1, nBins).map(segmentScale));
|
|
61
|
+
|
|
62
|
+
const binner = $derived(bin().domain([minX, maxX]).thresholds(binThresholds));
|
|
63
|
+
|
|
64
|
+
const clampedDistribution = $derived(
|
|
65
|
+
distribution.map((d) => Math.min(Math.max(d, minX), maxX)),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const binnedDistribution = $derived(
|
|
69
|
+
binner(includeOutliers ? clampedDistribution : distribution),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const bins = $derived(
|
|
73
|
+
polarity === "reverse"
|
|
74
|
+
? binnedDistribution.toReversed()
|
|
75
|
+
: binnedDistribution,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const proportionsInBins = $derived(
|
|
79
|
+
bins.map((b) => b.length / distribution.length),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let proportionInExtremeBins = $derived([
|
|
83
|
+
proportionsInBins[0],
|
|
84
|
+
proportionsInBins.at(-1),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
let yScale = $derived(
|
|
88
|
+
scaleLinear()
|
|
89
|
+
.domain([0, Math.max(...bins.map((b) => b.length))])
|
|
90
|
+
.range([0, height]),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
function interpolateColors(
|
|
94
|
+
startColor,
|
|
95
|
+
endColor,
|
|
96
|
+
nSegments,
|
|
97
|
+
midColor = null,
|
|
98
|
+
skew,
|
|
99
|
+
) {
|
|
100
|
+
const colorArray = [startColor, midColor, endColor].filter(Boolean);
|
|
101
|
+
|
|
102
|
+
if (!skew) {
|
|
103
|
+
return chroma.scale(colorArray).colors(nSegments);
|
|
104
|
+
} else {
|
|
105
|
+
const extremeColors = chroma
|
|
106
|
+
.scale([startColor, midColor, endColor])
|
|
107
|
+
.padding([
|
|
108
|
+
proportionInExtremeBins[0] / 2,
|
|
109
|
+
proportionInExtremeBins[1] / 2,
|
|
110
|
+
])
|
|
111
|
+
.colors(2);
|
|
112
|
+
|
|
113
|
+
const averageNormalised =
|
|
114
|
+
(averageValue - xValueFirst) / (xValueLast - xValueFirst);
|
|
115
|
+
|
|
116
|
+
const binColors = chroma
|
|
117
|
+
.scale([extremeColors[0], midColor, extremeColors[1]])
|
|
118
|
+
.domain([
|
|
119
|
+
0,
|
|
120
|
+
polarity === "reverse" ? 1 - averageNormalised : averageNormalised,
|
|
121
|
+
1,
|
|
122
|
+
])
|
|
123
|
+
.colors(10);
|
|
124
|
+
|
|
125
|
+
return binColors;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let colorScale = $derived(() => {
|
|
130
|
+
if (customColorScale) return customColorScale;
|
|
131
|
+
|
|
132
|
+
if (!startColor || !endColor || !nBins) return [];
|
|
133
|
+
|
|
134
|
+
if (skew) {
|
|
135
|
+
if (
|
|
136
|
+
!midColor ||
|
|
137
|
+
averageValue == null ||
|
|
138
|
+
xValueFirst == null ||
|
|
139
|
+
xValueLast == null
|
|
140
|
+
) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return interpolateColors(startColor, endColor, nBins, midColor, skew);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const layout = $derived.by(() => {
|
|
149
|
+
let y = 0;
|
|
150
|
+
|
|
151
|
+
const topLabelY = topLabel ? y : null;
|
|
152
|
+
if (topLabel) y += 20;
|
|
153
|
+
|
|
154
|
+
const annotationY = annotationText ? y : null;
|
|
155
|
+
if (annotationText) y += 25;
|
|
156
|
+
|
|
157
|
+
const chartY = y;
|
|
158
|
+
y += height;
|
|
159
|
+
|
|
160
|
+
const xAxisY = showXAxis ? y : null;
|
|
161
|
+
if (showXAxis) y += 25;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
topLabelY,
|
|
165
|
+
annotationY,
|
|
166
|
+
chartY,
|
|
167
|
+
xAxisY,
|
|
168
|
+
totalHeight: y,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
</script>
|
|
172
|
+
|
|
173
|
+
{#key containerWidth}
|
|
174
|
+
<div class="scale-container" bind:clientWidth={containerWidth}>
|
|
175
|
+
<svg width={containerWidth} height={layout.totalHeight}>
|
|
176
|
+
<g transform="translate({padding / 2}, 0)">
|
|
177
|
+
{#if topLabel && layout.topLabelY !== null}
|
|
178
|
+
<text x={0} y={layout.topLabelY + 14} fill="#666" font-size="0.75em">
|
|
179
|
+
Number of areas
|
|
180
|
+
{minX}, {maxX}
|
|
181
|
+
</text>
|
|
182
|
+
{/if}
|
|
183
|
+
|
|
184
|
+
{#if annotationText && layout.annotationY !== null}
|
|
185
|
+
<g
|
|
186
|
+
transform="translate({xScale(
|
|
187
|
+
annotationValue,
|
|
188
|
+
)}, {layout.annotationY})"
|
|
189
|
+
>
|
|
190
|
+
<text
|
|
191
|
+
fill="#555555"
|
|
192
|
+
font-size="0.8em"
|
|
193
|
+
text-anchor="middle"
|
|
194
|
+
dominant-baseline="hanging"
|
|
195
|
+
>
|
|
196
|
+
<tspan x="0" dy="0">{annotationText}</tspan>
|
|
197
|
+
<tspan x="0" dy="12">▼</tspan>
|
|
198
|
+
</text>
|
|
199
|
+
</g>
|
|
200
|
+
{/if}
|
|
201
|
+
|
|
202
|
+
<g transform="translate(0, {layout.chartY})">
|
|
203
|
+
{#if showYAxis}
|
|
204
|
+
<!-- <Axis
|
|
205
|
+
bind:axisDomain
|
|
206
|
+
bind:ticksArray={ticksDomain}
|
|
207
|
+
{chartHeight}
|
|
208
|
+
chartWidth={chartWidth - markerRadius * 2}
|
|
209
|
+
orientation={{ axis: "x", position: "bottom" }}
|
|
210
|
+
range={[markerRadius, chartWidth - markerRadius]}
|
|
211
|
+
domain={[xValueFirst, xValueLast]}
|
|
212
|
+
{min}
|
|
213
|
+
{max}
|
|
214
|
+
fontSize={14}
|
|
215
|
+
{floor}
|
|
216
|
+
{ceiling}
|
|
217
|
+
{numberOfTicks}
|
|
218
|
+
{polarity}
|
|
219
|
+
{showTickMarks}
|
|
220
|
+
{showGridlines}
|
|
221
|
+
{labelFormatter}
|
|
222
|
+
{niceTicks}
|
|
223
|
+
{markerRadius}
|
|
224
|
+
{distribution}
|
|
225
|
+
></Axis> -->
|
|
226
|
+
{/if}
|
|
227
|
+
|
|
228
|
+
{#each bins as bin, i}
|
|
229
|
+
{#key bin.x0}
|
|
230
|
+
{@const fullWidth = Math.abs(xScale(bin.x1) - xScale(bin.x0))}
|
|
231
|
+
{@const barWidth = fullWidth * 0.97}
|
|
232
|
+
{@const offset = (fullWidth - barWidth) / 2}
|
|
233
|
+
<rect
|
|
234
|
+
x={(polarity === "reverse" ? xScale(bin.x1) : xScale(bin.x0)) +
|
|
235
|
+
offset}
|
|
236
|
+
y={height - yScale(bin.length)}
|
|
237
|
+
width={barWidth}
|
|
238
|
+
height={yScale(bin.length)}
|
|
239
|
+
fill={fill ?? colorScale[i]}
|
|
240
|
+
></rect>
|
|
241
|
+
<!-- <text
|
|
242
|
+
x={(polarity === "reverse" ? xScale(bin.x1) : xScale(bin.x0)) +
|
|
243
|
+
offset}
|
|
244
|
+
y={height - yScale(bin.length)}
|
|
245
|
+
font-size={5}
|
|
246
|
+
>{bin.length} areas between
|
|
247
|
+
{Math.round(bin.x0)} and {Math.round(bin.x1)}
|
|
248
|
+
</text> -->
|
|
249
|
+
{/key}
|
|
250
|
+
{/each}
|
|
251
|
+
</g>
|
|
252
|
+
|
|
253
|
+
{#if showXAxis && layout.xAxisY !== null}
|
|
254
|
+
<g transform="translate(0, {layout.xAxisY})">
|
|
255
|
+
<!-- <Axis
|
|
256
|
+
bind:ticksArray={xTicks}
|
|
257
|
+
chartHeight={height}
|
|
258
|
+
chartWidth={containerWidth - padding}
|
|
259
|
+
orientation={{ axis: "x", position: "bottom" }}
|
|
260
|
+
domain={[xValueFirst, xValueLast]}
|
|
261
|
+
min={minX}
|
|
262
|
+
max={maxX}
|
|
263
|
+
range={useRange}
|
|
264
|
+
fontSize={13}
|
|
265
|
+
{floor}
|
|
266
|
+
{ceiling}
|
|
267
|
+
{labelFormatter}
|
|
268
|
+
{numberOfTicks}
|
|
269
|
+
/> -->
|
|
270
|
+
</g>
|
|
271
|
+
{/if}
|
|
272
|
+
</g>
|
|
273
|
+
</svg>
|
|
274
|
+
</div>
|
|
275
|
+
{/key}
|
|
276
|
+
|
|
277
|
+
<div style="content-visibility: hidden;">
|
|
278
|
+
{#if !showXAxis}
|
|
279
|
+
<!-- <Axis
|
|
280
|
+
bind:axisDomain
|
|
281
|
+
bind:ticksArray={ticksDomain}
|
|
282
|
+
{chartHeight}
|
|
283
|
+
chartWidth={chartWidth - markerRadius * 2}
|
|
284
|
+
orientation={{ axis: "x", position: "bottom" }}
|
|
285
|
+
range={[markerRadius, chartWidth - markerRadius]}
|
|
286
|
+
domain={[xValueFirst, xValueLast]}
|
|
287
|
+
{min}
|
|
288
|
+
{max}
|
|
289
|
+
fontSize={14}
|
|
290
|
+
{floor}
|
|
291
|
+
{ceiling}
|
|
292
|
+
{numberOfTicks}
|
|
293
|
+
{polarity}
|
|
294
|
+
{showTickMarks}
|
|
295
|
+
{showGridlines}
|
|
296
|
+
{labelFormatter}
|
|
297
|
+
{niceTicks}
|
|
298
|
+
{markerRadius}
|
|
299
|
+
{distribution}
|
|
300
|
+
></Axis> -->
|
|
301
|
+
{/if}
|
|
302
|
+
</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,234 @@
|
|
|
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
|
-
numberOfTicks,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
chartHeight = 100,
|
|
23
|
+
chartWidth = 200,
|
|
24
|
+
numberOfTicks = undefined as number | undefined,
|
|
25
|
+
axisDomain = $bindable<number[]>([]),
|
|
26
|
+
ticksArray = $bindable<number[]>([]),
|
|
27
|
+
min = undefined as number | undefined,
|
|
28
|
+
max = undefined as number | undefined,
|
|
29
|
+
orientation = { axis: "x", position: "bottom" } as Orientation,
|
|
30
|
+
floor = undefined as number | undefined,
|
|
31
|
+
ceiling = undefined as number | undefined,
|
|
32
|
+
paddingTop = 100,
|
|
33
|
+
paddingBottom = 100,
|
|
34
|
+
paddingLeft = 0,
|
|
35
|
+
paddingRight = 0,
|
|
36
|
+
labelFormatter = undefined as LabelFormatter | undefined,
|
|
37
|
+
scale = undefined as ScaleContinuousNumeric<number, number> | undefined,
|
|
38
|
+
domain = undefined as [number, number] | undefined,
|
|
39
|
+
range = undefined as [number, number] | undefined,
|
|
40
|
+
fontSize = 19,
|
|
41
|
+
polarity = "standard",
|
|
42
|
+
showGridlines = false,
|
|
43
|
+
showTickMarks = false,
|
|
44
|
+
strokeWidth = 2,
|
|
45
|
+
niceTicks = true,
|
|
46
|
+
markerRadius = 0 as number,
|
|
47
|
+
distribution = [],
|
|
48
|
+
}: {
|
|
49
|
+
chartHeight?: number;
|
|
50
|
+
chartWidth?: number;
|
|
51
|
+
numberOfTicks?: number;
|
|
52
|
+
axisDomain?: number[];
|
|
53
|
+
ticksArray?: number[];
|
|
54
|
+
min?: number;
|
|
55
|
+
max?: number;
|
|
56
|
+
orientation?: Orientation;
|
|
57
|
+
floor?: number;
|
|
58
|
+
ceiling?: number;
|
|
59
|
+
paddingTop?: number;
|
|
60
|
+
paddingBottom?: number;
|
|
61
|
+
paddingLeft?: number;
|
|
62
|
+
paddingRight?: number;
|
|
63
|
+
labelFormatter?: LabelFormatter;
|
|
64
|
+
scale?: ScaleContinuousNumeric<number, number>;
|
|
65
|
+
domain?: [number, number];
|
|
66
|
+
range?: [number, number];
|
|
67
|
+
fontSize?: number;
|
|
68
|
+
polarity?: Polarity;
|
|
69
|
+
gridlines?: boolean;
|
|
70
|
+
strokeWidth?: number;
|
|
71
|
+
showGridlines?: boolean;
|
|
72
|
+
showTickMarks?: boolean;
|
|
73
|
+
niceTicks?: boolean;
|
|
74
|
+
markerRadius?: number;
|
|
75
|
+
distribution?: number[];
|
|
18
76
|
} = $props();
|
|
77
|
+
|
|
78
|
+
let minTick = $derived(ticksArray.length ? Math.min(...ticksArray) : 0);
|
|
79
|
+
let maxTick = $derived(ticksArray.length ? Math.max(...ticksArray) : 1);
|
|
80
|
+
let minValue = $derived(distribution.length ? Math.min(...distribution) : 0);
|
|
81
|
+
let maxValue = $derived(distribution.length ? Math.max(...distribution) : 1);
|
|
82
|
+
|
|
83
|
+
let leftPad = $derived(
|
|
84
|
+
niceTicks
|
|
85
|
+
? polarity === "standard"
|
|
86
|
+
? minValue < minTick
|
|
87
|
+
? 0.1
|
|
88
|
+
: 0
|
|
89
|
+
: polarity === "reverse"
|
|
90
|
+
? maxValue > maxTick
|
|
91
|
+
? 0.1
|
|
92
|
+
: 0
|
|
93
|
+
: 0
|
|
94
|
+
: polarity === "standard"
|
|
95
|
+
? minValue < min
|
|
96
|
+
? 0.1
|
|
97
|
+
: 0
|
|
98
|
+
: polarity === "reverse"
|
|
99
|
+
? maxValue > max
|
|
100
|
+
? 0.1
|
|
101
|
+
: 0
|
|
102
|
+
: 0,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
let rightPad = $derived(
|
|
106
|
+
niceTicks
|
|
107
|
+
? polarity === "standard"
|
|
108
|
+
? maxValue > maxTick
|
|
109
|
+
? 0.1
|
|
110
|
+
: 0
|
|
111
|
+
: polarity === "reverse"
|
|
112
|
+
? minValue < minTick
|
|
113
|
+
? 0.1
|
|
114
|
+
: 0
|
|
115
|
+
: 0
|
|
116
|
+
: polarity === "standard"
|
|
117
|
+
? maxValue > max
|
|
118
|
+
? 0.1
|
|
119
|
+
: 0
|
|
120
|
+
: polarity === "reverse"
|
|
121
|
+
? minValue < min
|
|
122
|
+
? 0.1
|
|
123
|
+
: 0
|
|
124
|
+
: 0,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
let widthForTicks = $derived(
|
|
128
|
+
chartWidth - chartWidth * leftPad - chartWidth * rightPad,
|
|
129
|
+
);
|
|
130
|
+
let heightForTicks = $derived(Math.max(0, chartHeight));
|
|
131
|
+
|
|
132
|
+
function calculateFullAxisDomain(
|
|
133
|
+
minTick,
|
|
134
|
+
maxTick,
|
|
135
|
+
leftPad,
|
|
136
|
+
rightPad,
|
|
137
|
+
polarity,
|
|
138
|
+
) {
|
|
139
|
+
const ticksDomainRange = maxTick - minTick;
|
|
140
|
+
const axisDomainRange = ticksDomainRange / (1 - leftPad - rightPad);
|
|
141
|
+
|
|
142
|
+
if (polarity === "standard") {
|
|
143
|
+
return [
|
|
144
|
+
minTick - axisDomainRange * leftPad,
|
|
145
|
+
maxTick + axisDomainRange * rightPad,
|
|
146
|
+
];
|
|
147
|
+
} else {
|
|
148
|
+
return [
|
|
149
|
+
maxTick + axisDomainRange * leftPad,
|
|
150
|
+
minTick - axisDomainRange * rightPad,
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let fullAxisDomain = $derived(
|
|
156
|
+
calculateFullAxisDomain(minTick, maxTick, leftPad, rightPad, polarity),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
$effect(() => {
|
|
160
|
+
axisDomain = fullAxisDomain;
|
|
161
|
+
});
|
|
19
162
|
</script>
|
|
20
163
|
|
|
21
164
|
<g
|
|
22
165
|
data-role="{orientation.axis}-axis"
|
|
23
|
-
transform="translate({orientation.position
|
|
166
|
+
transform="translate({orientation.position !== 'right'
|
|
24
167
|
? 0
|
|
25
168
|
: chartWidth},{orientation.position === 'bottom' ? chartHeight : 0})"
|
|
26
169
|
>
|
|
27
170
|
<line
|
|
28
|
-
x1=
|
|
171
|
+
x1={markerRadius ?? 0}
|
|
29
172
|
y1="0"
|
|
30
|
-
x2={orientation.axis === "x"
|
|
173
|
+
x2={orientation.axis === "x"
|
|
174
|
+
? markerRadius
|
|
175
|
+
? chartWidth + markerRadius
|
|
176
|
+
: chartWidth
|
|
177
|
+
: 0}
|
|
31
178
|
y2={orientation.axis === "y" ? chartHeight : 0}
|
|
32
|
-
stroke="
|
|
179
|
+
stroke="grey"
|
|
33
180
|
stroke-width="2px"
|
|
34
181
|
></line>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{numberOfTicks}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
182
|
+
<g
|
|
183
|
+
data-role="{orientation.axis}-axis"
|
|
184
|
+
transform="translate({orientation.position !== 'right'
|
|
185
|
+
? chartWidth * leftPad + markerRadius
|
|
186
|
+
: chartWidth},{orientation.position === 'bottom' ? 0 : 0})"
|
|
187
|
+
>
|
|
188
|
+
{#if ticksArray || (min && max)}
|
|
189
|
+
{#key numberOfTicks}
|
|
190
|
+
{#if niceTicks}
|
|
191
|
+
<Ticks
|
|
192
|
+
bind:ticksArray
|
|
193
|
+
tickWidth={widthForTicks}
|
|
194
|
+
chartHeight={heightForTicks}
|
|
195
|
+
{min}
|
|
196
|
+
{max}
|
|
197
|
+
{numberOfTicks}
|
|
198
|
+
{orientation}
|
|
199
|
+
{floor}
|
|
200
|
+
{ceiling}
|
|
201
|
+
{labelFormatter}
|
|
202
|
+
{fontSize}
|
|
203
|
+
{polarity}
|
|
204
|
+
{showGridlines}
|
|
205
|
+
{showTickMarks}
|
|
206
|
+
{strokeWidth}
|
|
207
|
+
{niceTicks}
|
|
208
|
+
/>
|
|
209
|
+
{:else}
|
|
210
|
+
<Ticks
|
|
211
|
+
bind:ticksArray
|
|
212
|
+
tickWidth={widthForTicks}
|
|
213
|
+
chartHeight={heightForTicks}
|
|
214
|
+
{min}
|
|
215
|
+
{max}
|
|
216
|
+
{numberOfTicks}
|
|
217
|
+
{orientation}
|
|
218
|
+
{floor}
|
|
219
|
+
{ceiling}
|
|
220
|
+
{labelFormatter}
|
|
221
|
+
{fontSize}
|
|
222
|
+
{polarity}
|
|
223
|
+
{showGridlines}
|
|
224
|
+
{showTickMarks}
|
|
225
|
+
{strokeWidth}
|
|
226
|
+
{niceTicks}
|
|
227
|
+
{leftPad}
|
|
228
|
+
{rightPad}
|
|
229
|
+
/>
|
|
230
|
+
{/if}
|
|
231
|
+
{/key}
|
|
232
|
+
{/if}
|
|
233
|
+
</g>
|
|
51
234
|
</g>
|