@faintshadow/flarecharts 26.3.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.
- package/LICENSE +40 -0
- package/README.md +103 -0
- package/dist/charts/AreaChart.svelte +150 -0
- package/dist/charts/AreaChart.svelte.d.ts +60 -0
- package/dist/charts/BarChart.svelte +142 -0
- package/dist/charts/BarChart.svelte.d.ts +58 -0
- package/dist/charts/BoxPlotChart.svelte +138 -0
- package/dist/charts/BoxPlotChart.svelte.d.ts +56 -0
- package/dist/charts/DonutChart.svelte +129 -0
- package/dist/charts/DonutChart.svelte.d.ts +73 -0
- package/dist/charts/LineChart.svelte +149 -0
- package/dist/charts/LineChart.svelte.d.ts +63 -0
- package/dist/charts/Sparkline.svelte +87 -0
- package/dist/charts/Sparkline.svelte.d.ts +40 -0
- package/dist/charts/StackChart.svelte +157 -0
- package/dist/charts/StackChart.svelte.d.ts +69 -0
- package/dist/components/Arc.svelte +202 -0
- package/dist/components/Arc.svelte.d.ts +50 -0
- package/dist/components/Area.svelte +264 -0
- package/dist/components/Area.svelte.d.ts +54 -0
- package/dist/components/Axis.svelte +139 -0
- package/dist/components/Axis.svelte.d.ts +26 -0
- package/dist/components/Bars.svelte +192 -0
- package/dist/components/Bars.svelte.d.ts +55 -0
- package/dist/components/Box.svelte +287 -0
- package/dist/components/Box.svelte.d.ts +48 -0
- package/dist/components/Chart.svelte +207 -0
- package/dist/components/Chart.svelte.d.ts +23 -0
- package/dist/components/Crosshair.svelte +67 -0
- package/dist/components/Crosshair.svelte.d.ts +14 -0
- package/dist/components/Grid.svelte +38 -0
- package/dist/components/Grid.svelte.d.ts +14 -0
- package/dist/components/Labels.svelte +61 -0
- package/dist/components/Labels.svelte.d.ts +35 -0
- package/dist/components/Legend.svelte +81 -0
- package/dist/components/Legend.svelte.d.ts +12 -0
- package/dist/components/Line.svelte +192 -0
- package/dist/components/Line.svelte.d.ts +47 -0
- package/dist/components/PlotBand.svelte +68 -0
- package/dist/components/PlotBand.svelte.d.ts +14 -0
- package/dist/components/PlotLine.svelte +54 -0
- package/dist/components/PlotLine.svelte.d.ts +16 -0
- package/dist/components/Points.svelte +179 -0
- package/dist/components/Points.svelte.d.ts +53 -0
- package/dist/components/Svg.svelte +36 -0
- package/dist/components/Svg.svelte.d.ts +8 -0
- package/dist/components/Tooltip.svelte +211 -0
- package/dist/components/Tooltip.svelte.d.ts +44 -0
- package/dist/core/bisect.d.ts +5 -0
- package/dist/core/bisect.js +23 -0
- package/dist/core/context.svelte.d.ts +140 -0
- package/dist/core/context.svelte.js +294 -0
- package/dist/core/curves.d.ts +4 -0
- package/dist/core/curves.js +13 -0
- package/dist/core/hit.d.ts +34 -0
- package/dist/core/hit.js +43 -0
- package/dist/core/keynav.d.ts +20 -0
- package/dist/core/keynav.js +41 -0
- package/dist/core/labels.d.ts +39 -0
- package/dist/core/labels.js +27 -0
- package/dist/core/merge.d.ts +17 -0
- package/dist/core/merge.js +46 -0
- package/dist/core/motion.svelte.d.ts +31 -0
- package/dist/core/motion.svelte.js +129 -0
- package/dist/core/normalize.d.ts +35 -0
- package/dist/core/normalize.js +97 -0
- package/dist/core/options.d.ts +113 -0
- package/dist/core/options.js +36 -0
- package/dist/core/palette.d.ts +8 -0
- package/dist/core/palette.js +24 -0
- package/dist/core/responsive.d.ts +6 -0
- package/dist/core/responsive.js +19 -0
- package/dist/core/scales.d.ts +31 -0
- package/dist/core/scales.js +89 -0
- package/dist/core/stack.d.ts +19 -0
- package/dist/core/stack.js +133 -0
- package/dist/core/stats.d.ts +45 -0
- package/dist/core/stats.js +114 -0
- package/dist/core/symbols.d.ts +8 -0
- package/dist/core/symbols.js +31 -0
- package/dist/core/types.d.ts +28 -0
- package/dist/core/types.js +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +42 -0
- package/package.json +81 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import Chart from '../components/Chart.svelte';
|
|
3
|
+
import Svg from '../components/Svg.svelte';
|
|
4
|
+
import Axis from '../components/Axis.svelte';
|
|
5
|
+
import Grid from '../components/Grid.svelte';
|
|
6
|
+
import Area from '../components/Area.svelte';
|
|
7
|
+
|
|
8
|
+
import Labels from '../components/Labels.svelte';
|
|
9
|
+
import PlotBand from '../components/PlotBand.svelte';
|
|
10
|
+
import PlotLine from '../components/PlotLine.svelte';
|
|
11
|
+
import Tooltip from '../components/Tooltip.svelte';
|
|
12
|
+
import Crosshair from '../components/Crosshair.svelte';
|
|
13
|
+
import Legend from '../components/Legend.svelte';
|
|
14
|
+
import { resolveSeries, splitAxisOptions } from '../core/options.js';
|
|
15
|
+
import type {
|
|
16
|
+
BandSpec,
|
|
17
|
+
LegendSpec,
|
|
18
|
+
PlotLineSpec,
|
|
19
|
+
PlotOptions,
|
|
20
|
+
SeriesOptions,
|
|
21
|
+
SimpleAxisOptions,
|
|
22
|
+
TooltipSpec
|
|
23
|
+
} from '../core/options.js';
|
|
24
|
+
import type { StackOffset, StackOrder } from '../core/stack.js';
|
|
25
|
+
import { applyResponsive } from '../core/responsive.js';
|
|
26
|
+
import type { ResponsiveRule } from '../core/responsive.js';
|
|
27
|
+
import type { Padding } from '../core/types.js';
|
|
28
|
+
|
|
29
|
+
interface BaseProps {
|
|
30
|
+
series: SeriesOptions<T>[];
|
|
31
|
+
/** How the stack sits: normal/percent anchor at zero; stream/silhouette float. */
|
|
32
|
+
offset?: StackOffset;
|
|
33
|
+
/** Layer ordering within the stack. */
|
|
34
|
+
order?: StackOrder;
|
|
35
|
+
xAxis?: SimpleAxisOptions;
|
|
36
|
+
yAxis?: SimpleAxisOptions;
|
|
37
|
+
bands?: BandSpec[];
|
|
38
|
+
lines?: PlotLineSpec[];
|
|
39
|
+
grid?: boolean;
|
|
40
|
+
crosshair?: boolean;
|
|
41
|
+
tooltip?: boolean | TooltipSpec;
|
|
42
|
+
legend?: boolean | LegendSpec;
|
|
43
|
+
plotOptions?: PlotOptions<T>;
|
|
44
|
+
padding?: Padding;
|
|
45
|
+
label?: string;
|
|
46
|
+
/** Accessible chart description. */
|
|
47
|
+
description?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface Props extends BaseProps {
|
|
51
|
+
responsive?: ResponsiveRule<BaseProps>[];
|
|
52
|
+
class?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let {
|
|
56
|
+
series,
|
|
57
|
+
offset = 'normal',
|
|
58
|
+
order = 'none',
|
|
59
|
+
xAxis,
|
|
60
|
+
yAxis,
|
|
61
|
+
bands,
|
|
62
|
+
lines,
|
|
63
|
+
grid = true,
|
|
64
|
+
crosshair = false,
|
|
65
|
+
tooltip = true,
|
|
66
|
+
legend,
|
|
67
|
+
plotOptions,
|
|
68
|
+
padding,
|
|
69
|
+
label = 'Stacked chart',
|
|
70
|
+
description,
|
|
71
|
+
responsive,
|
|
72
|
+
class: klass = ''
|
|
73
|
+
}: Props = $props();
|
|
74
|
+
|
|
75
|
+
let width = $state(0);
|
|
76
|
+
|
|
77
|
+
const eff = $derived(
|
|
78
|
+
applyResponsive(
|
|
79
|
+
{ series, offset, order, xAxis, yAxis, bands, lines, grid, crosshair, tooltip, legend, plotOptions, padding, label, description },
|
|
80
|
+
responsive,
|
|
81
|
+
width
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Stacked areas read more solidly than the default 0.2 fill; consumers can
|
|
86
|
+
// still override via plotOptions/series.
|
|
87
|
+
const resolved = $derived(eff.series.map((s) => resolveSeries({ fillOpacity: 0.85, ...eff.plotOptions }, s)));
|
|
88
|
+
const xa = $derived(splitAxisOptions(eff.xAxis));
|
|
89
|
+
const ya = $derived(splitAxisOptions(eff.yAxis));
|
|
90
|
+
|
|
91
|
+
const legendOn = $derived(
|
|
92
|
+
eff.legend === undefined ? eff.series.length > 1 : eff.legend !== false
|
|
93
|
+
);
|
|
94
|
+
const legendPos = $derived(
|
|
95
|
+
typeof eff.legend === 'object' && eff.legend ? (eff.legend.position ?? 'bottom') : 'bottom'
|
|
96
|
+
);
|
|
97
|
+
const tooltipOn = $derived(eff.tooltip !== false);
|
|
98
|
+
const tip = $derived(typeof eff.tooltip === 'object' && eff.tooltip ? eff.tooltip : {});
|
|
99
|
+
const pad = $derived({
|
|
100
|
+
...(legendOn ? (legendPos === 'top' ? { top: 48 } : { bottom: 56 }) : {}),
|
|
101
|
+
...eff.padding
|
|
102
|
+
});
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<div class="fc-simple fc-stack-chart {klass}" bind:clientWidth={width}>
|
|
106
|
+
<Chart x={xa.scale} y={ya.scale} padding={pad} label={eff.label} description={eff.description}>
|
|
107
|
+
<Svg>
|
|
108
|
+
{#if eff.grid}<Grid y />{/if}
|
|
109
|
+
{#each eff.bands ?? [] as band, i (i)}
|
|
110
|
+
<PlotBand axis={band.axis} from={band.from} to={band.to} color={band.color} label={band.label} />
|
|
111
|
+
{/each}
|
|
112
|
+
{#each eff.lines ?? [] as pl, i (i)}
|
|
113
|
+
<PlotLine axis={pl.axis} value={pl.value} color={pl.color} dash={pl.dash} label={pl.label} />
|
|
114
|
+
{/each}
|
|
115
|
+
{#each resolved as s, i (i)}
|
|
116
|
+
<Area
|
|
117
|
+
data={s.data}
|
|
118
|
+
x={s.x}
|
|
119
|
+
y={s.y}
|
|
120
|
+
color={s.color}
|
|
121
|
+
name={s.name}
|
|
122
|
+
description={s.description}
|
|
123
|
+
curve={s.curve}
|
|
124
|
+
fillOpacity={s.fillOpacity}
|
|
125
|
+
stacking={eff.offset}
|
|
126
|
+
order={eff.order}
|
|
127
|
+
stack="fc-stack"
|
|
128
|
+
line={false}
|
|
129
|
+
index={i}
|
|
130
|
+
/>
|
|
131
|
+
{/each}
|
|
132
|
+
{#each resolved as s, i (i)}
|
|
133
|
+
{#if s.labels}
|
|
134
|
+
<Labels data={s.data} x={s.x} y={s.y} />
|
|
135
|
+
{/if}
|
|
136
|
+
{/each}
|
|
137
|
+
{#if eff.crosshair}<Crosshair />{/if}
|
|
138
|
+
{#if xa.visible}
|
|
139
|
+
<Axis placement="bottom" title={xa.display.title} ticks={xa.display.ticks} format={xa.display.format} rotate={xa.display.rotate} />
|
|
140
|
+
{/if}
|
|
141
|
+
{#if ya.visible}
|
|
142
|
+
<Axis placement="left" title={ya.display.title} ticks={ya.display.ticks} format={ya.display.format} rotate={ya.display.rotate} />
|
|
143
|
+
{/if}
|
|
144
|
+
</Svg>
|
|
145
|
+
{#if tooltipOn}
|
|
146
|
+
<Tooltip mode={tip.mode ?? 'bisect-x'} shared={tip.shared ?? true} formatX={tip.formatX} formatY={tip.formatY} />
|
|
147
|
+
{/if}
|
|
148
|
+
{#if legendOn}<Legend position={legendPos} />{/if}
|
|
149
|
+
</Chart>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<style>
|
|
153
|
+
.fc-simple {
|
|
154
|
+
width: 100%;
|
|
155
|
+
height: 100%;
|
|
156
|
+
}
|
|
157
|
+
</style>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { BandSpec, LegendSpec, PlotLineSpec, PlotOptions, SeriesOptions, SimpleAxisOptions, TooltipSpec } from '../core/options.js';
|
|
2
|
+
import type { StackOffset, StackOrder } from '../core/stack.js';
|
|
3
|
+
import type { ResponsiveRule } from '../core/responsive.js';
|
|
4
|
+
import type { Padding } from '../core/types.js';
|
|
5
|
+
declare function $$render<T>(): {
|
|
6
|
+
props: {
|
|
7
|
+
series: SeriesOptions<T>[];
|
|
8
|
+
/** How the stack sits: normal/percent anchor at zero; stream/silhouette float. */
|
|
9
|
+
offset?: StackOffset;
|
|
10
|
+
/** Layer ordering within the stack. */
|
|
11
|
+
order?: StackOrder;
|
|
12
|
+
xAxis?: SimpleAxisOptions;
|
|
13
|
+
yAxis?: SimpleAxisOptions;
|
|
14
|
+
bands?: BandSpec[];
|
|
15
|
+
lines?: PlotLineSpec[];
|
|
16
|
+
grid?: boolean;
|
|
17
|
+
crosshair?: boolean;
|
|
18
|
+
tooltip?: boolean | TooltipSpec;
|
|
19
|
+
legend?: boolean | LegendSpec;
|
|
20
|
+
plotOptions?: PlotOptions<T>;
|
|
21
|
+
padding?: Padding;
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Accessible chart description. */
|
|
24
|
+
description?: string;
|
|
25
|
+
} & {
|
|
26
|
+
responsive?: ResponsiveRule<{
|
|
27
|
+
series: SeriesOptions<T>[];
|
|
28
|
+
/** How the stack sits: normal/percent anchor at zero; stream/silhouette float. */
|
|
29
|
+
offset?: StackOffset;
|
|
30
|
+
/** Layer ordering within the stack. */
|
|
31
|
+
order?: StackOrder;
|
|
32
|
+
xAxis?: SimpleAxisOptions;
|
|
33
|
+
yAxis?: SimpleAxisOptions;
|
|
34
|
+
bands?: BandSpec[];
|
|
35
|
+
lines?: PlotLineSpec[];
|
|
36
|
+
grid?: boolean;
|
|
37
|
+
crosshair?: boolean;
|
|
38
|
+
tooltip?: boolean | TooltipSpec;
|
|
39
|
+
legend?: boolean | LegendSpec;
|
|
40
|
+
plotOptions?: PlotOptions<T>;
|
|
41
|
+
padding?: Padding;
|
|
42
|
+
label?: string;
|
|
43
|
+
/** Accessible chart description. */
|
|
44
|
+
description?: string;
|
|
45
|
+
}>[];
|
|
46
|
+
class?: string;
|
|
47
|
+
};
|
|
48
|
+
exports: {};
|
|
49
|
+
bindings: "";
|
|
50
|
+
slots: {};
|
|
51
|
+
events: {};
|
|
52
|
+
};
|
|
53
|
+
declare class __sveltets_Render<T> {
|
|
54
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
55
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
56
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
57
|
+
bindings(): "";
|
|
58
|
+
exports(): {};
|
|
59
|
+
}
|
|
60
|
+
interface $$IsomorphicComponent {
|
|
61
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
62
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
63
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
64
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
65
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
66
|
+
}
|
|
67
|
+
declare const StackChart: $$IsomorphicComponent;
|
|
68
|
+
type StackChart<T> = InstanceType<typeof StackChart<T>>;
|
|
69
|
+
export default StackChart;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import { arc as d3arc, pie as d3pie } from 'd3-shape';
|
|
3
|
+
import type { PieArcDatum } from 'd3-shape';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import { onMount } from 'svelte';
|
|
6
|
+
import { getChartContext } from '../core/context.svelte.js';
|
|
7
|
+
import { seriesColorVar } from '../core/palette.js';
|
|
8
|
+
|
|
9
|
+
interface Slice {
|
|
10
|
+
value: number;
|
|
11
|
+
label: string;
|
|
12
|
+
datum: T;
|
|
13
|
+
index: number;
|
|
14
|
+
color: string;
|
|
15
|
+
percent: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
/** number[] | { value, label? }[] | T[] with accessors. Zero/negative values are skipped. */
|
|
20
|
+
data: readonly T[];
|
|
21
|
+
value?: (datum: T, index: number) => number | null | undefined;
|
|
22
|
+
label?: (datum: T, index: number) => string;
|
|
23
|
+
/** Inner radius as a 0–1 fraction of the outer radius (0 = pie, ~0.6 = donut). */
|
|
24
|
+
innerRadius?: number;
|
|
25
|
+
/** Outer radius as a 0–1 fraction of the available half-extent. */
|
|
26
|
+
radius?: number;
|
|
27
|
+
/** Gap between slices, degrees. */
|
|
28
|
+
padAngle?: number;
|
|
29
|
+
cornerRadius?: number;
|
|
30
|
+
/** Degrees, 0 = 12 o'clock, clockwise. */
|
|
31
|
+
startAngle?: number;
|
|
32
|
+
endAngle?: number;
|
|
33
|
+
/** Per-slice color overrides (any CSS strings); defaults to the palette. */
|
|
34
|
+
colors?: readonly string[];
|
|
35
|
+
labelPosition?: 'inside' | 'outside' | 'none';
|
|
36
|
+
/** Rendered at the center (SVG coordinates, origin = center) — donut totals etc. */
|
|
37
|
+
center?: Snippet<[{ total: number; radius: number; innerRadius: number }]>;
|
|
38
|
+
class?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let {
|
|
42
|
+
data,
|
|
43
|
+
value,
|
|
44
|
+
label,
|
|
45
|
+
innerRadius = 0,
|
|
46
|
+
radius = 1,
|
|
47
|
+
padAngle = 0,
|
|
48
|
+
cornerRadius = 0,
|
|
49
|
+
startAngle = 0,
|
|
50
|
+
endAngle = 360,
|
|
51
|
+
colors,
|
|
52
|
+
labelPosition = 'none',
|
|
53
|
+
center,
|
|
54
|
+
class: klass = ''
|
|
55
|
+
}: Props = $props();
|
|
56
|
+
|
|
57
|
+
const ctx = getChartContext();
|
|
58
|
+
|
|
59
|
+
let mounted = $state(false);
|
|
60
|
+
onMount(() => {
|
|
61
|
+
mounted = true;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const rad = (degrees: number) => (degrees * Math.PI) / 180;
|
|
65
|
+
|
|
66
|
+
function sliceValue(datum: T, index: number): number | null {
|
|
67
|
+
if (value) return value(datum, index) ?? null;
|
|
68
|
+
if (typeof datum === 'number') return datum;
|
|
69
|
+
if (datum && typeof datum === 'object' && 'value' in datum) {
|
|
70
|
+
const v = (datum as { value: unknown }).value;
|
|
71
|
+
return typeof v === 'number' ? v : null;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function sliceLabel(datum: T, index: number): string {
|
|
77
|
+
if (label) return label(datum, index);
|
|
78
|
+
if (datum && typeof datum === 'object' && 'label' in datum) {
|
|
79
|
+
return String((datum as { label: unknown }).label);
|
|
80
|
+
}
|
|
81
|
+
return String(index);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const slices = $derived.by((): Slice[] => {
|
|
85
|
+
const kept: Slice[] = [];
|
|
86
|
+
let total = 0;
|
|
87
|
+
for (let i = 0; i < data.length; i++) {
|
|
88
|
+
const v = sliceValue(data[i], i);
|
|
89
|
+
if (v == null || !Number.isFinite(v) || v <= 0) continue;
|
|
90
|
+
total += v;
|
|
91
|
+
kept.push({
|
|
92
|
+
value: v,
|
|
93
|
+
label: sliceLabel(data[i], i),
|
|
94
|
+
datum: data[i],
|
|
95
|
+
index: i,
|
|
96
|
+
color: colors?.[kept.length % (colors.length || 1)] ?? seriesColorVar(kept.length),
|
|
97
|
+
percent: 0
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
for (const s of kept) s.percent = total === 0 ? 0 : (s.value / total) * 100;
|
|
101
|
+
return kept;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const total = $derived(slices.reduce((sum, s) => sum + s.value, 0));
|
|
105
|
+
|
|
106
|
+
const outerR = $derived((Math.min(ctx.innerWidth, ctx.innerHeight) / 2) * radius);
|
|
107
|
+
const innerR = $derived(outerR * Math.max(0, Math.min(0.99, innerRadius)));
|
|
108
|
+
|
|
109
|
+
const arcs = $derived.by(() => {
|
|
110
|
+
const generator = d3pie<Slice>()
|
|
111
|
+
.sort(null)
|
|
112
|
+
.value((s) => s.value)
|
|
113
|
+
.startAngle(rad(startAngle))
|
|
114
|
+
.endAngle(rad(endAngle))
|
|
115
|
+
.padAngle(rad(padAngle));
|
|
116
|
+
return generator(slices);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const arcPath = $derived(
|
|
120
|
+
d3arc<PieArcDatum<Slice>>()
|
|
121
|
+
.innerRadius(innerR)
|
|
122
|
+
.outerRadius(outerR)
|
|
123
|
+
.cornerRadius(cornerRadius)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
function labelPlacement(a: PieArcDatum<Slice>) {
|
|
127
|
+
if (labelPosition === 'inside') {
|
|
128
|
+
const [x, y] = arcPath.centroid(a);
|
|
129
|
+
return { x, y, anchor: 'middle' as const };
|
|
130
|
+
}
|
|
131
|
+
const mid = (a.startAngle + a.endAngle) / 2;
|
|
132
|
+
const r = outerR + 12;
|
|
133
|
+
return {
|
|
134
|
+
x: Math.sin(mid) * r,
|
|
135
|
+
y: -Math.cos(mid) * r,
|
|
136
|
+
anchor: mid > Math.PI ? ('end' as const) : ('start' as const)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<g class="fc-arc {klass}" class:fc-arc-enter={mounted} transform="translate({ctx.innerWidth / 2}, {ctx.innerHeight / 2})">
|
|
142
|
+
{#each arcs as a (a.data.index)}
|
|
143
|
+
<path class="fc-arc-slice" d={arcPath(a) ?? ''} fill={a.data.color} data-label={a.data.label} />
|
|
144
|
+
{/each}
|
|
145
|
+
{#if labelPosition !== 'none'}
|
|
146
|
+
{#each arcs as a (a.data.index)}
|
|
147
|
+
{@const placement = labelPlacement(a)}
|
|
148
|
+
<text
|
|
149
|
+
class="fc-arc-label fc-arc-label-{labelPosition}"
|
|
150
|
+
x={placement.x}
|
|
151
|
+
y={placement.y}
|
|
152
|
+
text-anchor={placement.anchor}
|
|
153
|
+
dy="0.32em"
|
|
154
|
+
>
|
|
155
|
+
{a.data.label}
|
|
156
|
+
</text>
|
|
157
|
+
{/each}
|
|
158
|
+
{/if}
|
|
159
|
+
{#if center}
|
|
160
|
+
<g class="fc-arc-center">
|
|
161
|
+
{@render center({ total, radius: outerR, innerRadius: innerR })}
|
|
162
|
+
</g>
|
|
163
|
+
{/if}
|
|
164
|
+
</g>
|
|
165
|
+
|
|
166
|
+
<style>
|
|
167
|
+
.fc-arc-enter {
|
|
168
|
+
animation: fc-arc-in var(--fc-duration, 500ms) var(--fc-ease, ease);
|
|
169
|
+
}
|
|
170
|
+
@keyframes fc-arc-in {
|
|
171
|
+
from {
|
|
172
|
+
opacity: 0;
|
|
173
|
+
}
|
|
174
|
+
to {
|
|
175
|
+
opacity: 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
.fc-arc-slice {
|
|
179
|
+
stroke: none;
|
|
180
|
+
transition: opacity var(--fc-duration-hover, 120ms) var(--fc-ease, ease);
|
|
181
|
+
}
|
|
182
|
+
.fc-arc-slice:hover {
|
|
183
|
+
opacity: 0.85;
|
|
184
|
+
}
|
|
185
|
+
@media (prefers-reduced-motion: reduce) {
|
|
186
|
+
.fc-arc-enter {
|
|
187
|
+
animation: none;
|
|
188
|
+
}
|
|
189
|
+
.fc-arc-slice {
|
|
190
|
+
transition: none;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
.fc-arc-label {
|
|
194
|
+
font-size: 11px;
|
|
195
|
+
}
|
|
196
|
+
.fc-arc-label-outside {
|
|
197
|
+
fill: var(--fc-axis-label, #64748b);
|
|
198
|
+
}
|
|
199
|
+
.fc-arc-label-inside {
|
|
200
|
+
fill: var(--fc-arc-label-inside, #ffffff);
|
|
201
|
+
}
|
|
202
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
declare function $$render<T>(): {
|
|
3
|
+
props: {
|
|
4
|
+
/** number[] | { value, label? }[] | T[] with accessors. Zero/negative values are skipped. */
|
|
5
|
+
data: readonly T[];
|
|
6
|
+
value?: (datum: T, index: number) => number | null | undefined;
|
|
7
|
+
label?: (datum: T, index: number) => string;
|
|
8
|
+
/** Inner radius as a 0–1 fraction of the outer radius (0 = pie, ~0.6 = donut). */
|
|
9
|
+
innerRadius?: number;
|
|
10
|
+
/** Outer radius as a 0–1 fraction of the available half-extent. */
|
|
11
|
+
radius?: number;
|
|
12
|
+
/** Gap between slices, degrees. */
|
|
13
|
+
padAngle?: number;
|
|
14
|
+
cornerRadius?: number;
|
|
15
|
+
/** Degrees, 0 = 12 o'clock, clockwise. */
|
|
16
|
+
startAngle?: number;
|
|
17
|
+
endAngle?: number;
|
|
18
|
+
/** Per-slice color overrides (any CSS strings); defaults to the palette. */
|
|
19
|
+
colors?: readonly string[];
|
|
20
|
+
labelPosition?: "inside" | "outside" | "none";
|
|
21
|
+
/** Rendered at the center (SVG coordinates, origin = center) — donut totals etc. */
|
|
22
|
+
center?: Snippet<[{
|
|
23
|
+
total: number;
|
|
24
|
+
radius: number;
|
|
25
|
+
innerRadius: number;
|
|
26
|
+
}]>;
|
|
27
|
+
class?: string;
|
|
28
|
+
};
|
|
29
|
+
exports: {};
|
|
30
|
+
bindings: "";
|
|
31
|
+
slots: {};
|
|
32
|
+
events: {};
|
|
33
|
+
};
|
|
34
|
+
declare class __sveltets_Render<T> {
|
|
35
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
36
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
37
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
38
|
+
bindings(): "";
|
|
39
|
+
exports(): {};
|
|
40
|
+
}
|
|
41
|
+
interface $$IsomorphicComponent {
|
|
42
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
43
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
44
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
45
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
46
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
47
|
+
}
|
|
48
|
+
declare const Arc: $$IsomorphicComponent;
|
|
49
|
+
type Arc<T> = InstanceType<typeof Arc<T>>;
|
|
50
|
+
export default Arc;
|