@thomasfosterau/charts 0.0.0-stage → 0.1.0
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 +21 -0
- package/README.md +591 -2
- package/dist/core-BVbfW7N6.mjs +936 -0
- package/dist/core-BVbfW7N6.mjs.map +1 -0
- package/dist/core.d.mts +2 -0
- package/dist/core.mjs +1 -0
- package/dist/index-B32E5tbG.d.mts +405 -0
- package/dist/index-M0KOYMo4.d.mts +200 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/prosemirror.d.mts +106 -0
- package/dist/prosemirror.mjs +245 -0
- package/dist/prosemirror.mjs.map +1 -0
- package/dist/spec-FF2Tds2a.mjs +351 -0
- package/dist/spec-FF2Tds2a.mjs.map +1 -0
- package/dist/svelte/Chart.svelte +73 -0
- package/dist/svelte/Chart.svelte.d.ts +37 -0
- package/dist/svelte/ChartAxes.svelte +39 -0
- package/dist/svelte/ChartAxes.svelte.d.ts +11 -0
- package/dist/svelte/ChartMarks.svelte +74 -0
- package/dist/svelte/ChartMarks.svelte.d.ts +9 -0
- package/dist/svelte/index.d.ts +9 -0
- package/dist/svelte/index.js +9 -0
- package/dist/vega.d.mts +97 -0
- package/dist/vega.mjs +82 -0
- package/dist/vega.mjs.map +1 -0
- package/package.json +90 -3
- package/schema/chart-spec.v1.json +393 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component A chart's marks as SVG: one path per series for lines and areas, a rect per bar, a circle per point, a labelled box per tree node with its links.
|
|
3
|
+
-->
|
|
4
|
+
<script lang="ts">import { CATEGORICAL_PALETTE } from "@thomasfosterau/charts/core";
|
|
5
|
+
let { geometry } = $props();
|
|
6
|
+
const DEFAULT_COLOR = CATEGORICAL_PALETTE[0];
|
|
7
|
+
const LINK_COLOR = "#9ca3af";
|
|
8
|
+
const NODE_TEXT_COLOR = "#111827";
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
{#snippet seriesPaths(series: ReadonlyArray<Series>, filled: boolean)}
|
|
12
|
+
{#each series.filter((line) => line.path.length > 0) as line, index (line.key ?? index)}
|
|
13
|
+
{#if filled}
|
|
14
|
+
<path d={line.path} fill={line.color ?? DEFAULT_COLOR} fill-opacity="0.7" stroke="none" />
|
|
15
|
+
{:else}
|
|
16
|
+
<path d={line.path} fill="none" stroke={line.color ?? DEFAULT_COLOR} stroke-width="2" />
|
|
17
|
+
{/if}
|
|
18
|
+
{/each}
|
|
19
|
+
{/snippet}
|
|
20
|
+
|
|
21
|
+
{#snippet bars(rects: ReadonlyArray<BarRect>)}
|
|
22
|
+
{#each rects as bar, index (index)}
|
|
23
|
+
<rect x={bar.x} y={bar.y} width={bar.width} height={bar.height} fill={bar.color ?? DEFAULT_COLOR} />
|
|
24
|
+
{/each}
|
|
25
|
+
{/snippet}
|
|
26
|
+
|
|
27
|
+
{#snippet points(circles: ReadonlyArray<PointCircle>)}
|
|
28
|
+
{#each circles as point, index (index)}
|
|
29
|
+
<circle cx={point.cx} cy={point.cy} r={point.r} fill={point.color ?? DEFAULT_COLOR} />
|
|
30
|
+
{/each}
|
|
31
|
+
{/snippet}
|
|
32
|
+
|
|
33
|
+
{#snippet tree(shape: TreeGeometry)}
|
|
34
|
+
{#each shape.links as link (`${link.from}->${link.to}`)}
|
|
35
|
+
<path d={link.path} fill="none" stroke={LINK_COLOR} />
|
|
36
|
+
{/each}
|
|
37
|
+
{#each shape.nodes as node (node.id)}
|
|
38
|
+
<g>
|
|
39
|
+
<rect
|
|
40
|
+
x={node.x}
|
|
41
|
+
y={node.y}
|
|
42
|
+
width={node.width}
|
|
43
|
+
height={node.height}
|
|
44
|
+
rx="4"
|
|
45
|
+
fill="#ffffff"
|
|
46
|
+
stroke={node.color ?? DEFAULT_COLOR}
|
|
47
|
+
stroke-width="1.5"
|
|
48
|
+
/>
|
|
49
|
+
<text
|
|
50
|
+
x={node.x + node.width / 2}
|
|
51
|
+
y={node.y + node.height / 2}
|
|
52
|
+
text-anchor="middle"
|
|
53
|
+
dominant-baseline="middle"
|
|
54
|
+
font-family="system-ui, sans-serif"
|
|
55
|
+
font-size="11"
|
|
56
|
+
fill={NODE_TEXT_COLOR}>{node.label}</text
|
|
57
|
+
>
|
|
58
|
+
</g>
|
|
59
|
+
{/each}
|
|
60
|
+
{/snippet}
|
|
61
|
+
|
|
62
|
+
<g data-mark={geometry.mark}>
|
|
63
|
+
{#if geometry.mark === 'line'}
|
|
64
|
+
{@render seriesPaths(geometry.series, false)}
|
|
65
|
+
{:else if geometry.mark === 'area'}
|
|
66
|
+
{@render seriesPaths(geometry.series, true)}
|
|
67
|
+
{:else if geometry.mark === 'bar'}
|
|
68
|
+
{@render bars(geometry.bars)}
|
|
69
|
+
{:else if geometry.mark === 'tree'}
|
|
70
|
+
{@render tree(geometry)}
|
|
71
|
+
{:else}
|
|
72
|
+
{@render points(geometry.points)}
|
|
73
|
+
{/if}
|
|
74
|
+
</g>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Geometry } from '@thomasfosterau/charts/core';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** The mark geometry from `computeContext`. */
|
|
4
|
+
geometry: Geometry;
|
|
5
|
+
}
|
|
6
|
+
/** A chart's marks as SVG: one path per series for lines and areas, a rect per bar, a circle per point, a labelled box per tree node with its links. */
|
|
7
|
+
declare const ChartMarks: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type ChartMarks = ReturnType<typeof ChartMarks>;
|
|
9
|
+
export default ChartMarks;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@thomasfosterau/charts/svelte`
|
|
3
|
+
*
|
|
4
|
+
* Layer 3 interpreter: a Svelte 5 component rendering portable chart specs as
|
|
5
|
+
* SVG via the chart core. Pure rendering — works identically with
|
|
6
|
+
* `svelte/server` and on the client. Shipped as `.svelte` source by
|
|
7
|
+
* `svelte-package`, so the consumer's Svelte compiles it.
|
|
8
|
+
*/
|
|
9
|
+
export { default as Chart } from './Chart.svelte';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@thomasfosterau/charts/svelte`
|
|
3
|
+
*
|
|
4
|
+
* Layer 3 interpreter: a Svelte 5 component rendering portable chart specs as
|
|
5
|
+
* SVG via the chart core. Pure rendering — works identically with
|
|
6
|
+
* `svelte/server` and on the client. Shipped as `.svelte` source by
|
|
7
|
+
* `svelte-package`, so the consumer's Svelte compiles it.
|
|
8
|
+
*/
|
|
9
|
+
export { default as Chart } from './Chart.svelte';
|
package/dist/vega.d.mts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { l as ChartSpec, m as Datum } from "./index-M0KOYMo4.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* The subset of Vega-Lite's specification shape that the emitter produces.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately structural (not imported from the vega-lite package) so this
|
|
6
|
+
* package stays dependency-light; the test suite validates emitted specs
|
|
7
|
+
* against the real Vega-Lite compiler. Optional members are bare `prop?: T`:
|
|
8
|
+
* like the chart spec's types, these describe a JSON document, in which a key
|
|
9
|
+
* is present with a value or absent.
|
|
10
|
+
*/
|
|
11
|
+
/** A Vega-Lite field definition for a positional or mark-property channel. */
|
|
12
|
+
interface VegaLiteFieldDef {
|
|
13
|
+
readonly field: string;
|
|
14
|
+
readonly type: 'quantitative' | 'ordinal' | 'nominal' | 'temporal';
|
|
15
|
+
readonly scale?: {
|
|
16
|
+
readonly domain?: ReadonlyArray<number | string>;
|
|
17
|
+
readonly nice?: boolean;
|
|
18
|
+
readonly zero?: boolean;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A Vega-Lite secondary positional channel (`x2` / `y2`): a field only. It
|
|
23
|
+
* shares the type and scale of its primary channel.
|
|
24
|
+
*/
|
|
25
|
+
interface VegaLiteSecondaryFieldDef {
|
|
26
|
+
readonly field: string;
|
|
27
|
+
}
|
|
28
|
+
/** The Vega-Lite encoding block. */
|
|
29
|
+
interface VegaLiteEncoding {
|
|
30
|
+
readonly x?: VegaLiteFieldDef;
|
|
31
|
+
readonly y?: VegaLiteFieldDef;
|
|
32
|
+
readonly x2?: VegaLiteSecondaryFieldDef;
|
|
33
|
+
readonly y2?: VegaLiteSecondaryFieldDef;
|
|
34
|
+
readonly color?: VegaLiteFieldDef;
|
|
35
|
+
readonly size?: VegaLiteFieldDef;
|
|
36
|
+
readonly opacity?: VegaLiteFieldDef;
|
|
37
|
+
}
|
|
38
|
+
/** The Vega-Lite data block. */
|
|
39
|
+
type VegaLiteData = {
|
|
40
|
+
readonly values: ReadonlyArray<Record<string, unknown>>;
|
|
41
|
+
} | {
|
|
42
|
+
readonly url: string;
|
|
43
|
+
};
|
|
44
|
+
/** A single-view Vega-Lite specification. */
|
|
45
|
+
interface VegaLiteSpec {
|
|
46
|
+
readonly $schema: string;
|
|
47
|
+
readonly title?: string;
|
|
48
|
+
readonly mark: {
|
|
49
|
+
readonly type: 'bar' | 'line' | 'point' | 'area';
|
|
50
|
+
readonly tooltip?: boolean;
|
|
51
|
+
};
|
|
52
|
+
readonly data: VegaLiteData;
|
|
53
|
+
readonly encoding: VegaLiteEncoding;
|
|
54
|
+
readonly width?: number | 'container';
|
|
55
|
+
readonly height?: number;
|
|
56
|
+
}
|
|
57
|
+
/** The Vega-Lite schema the emitter targets. */
|
|
58
|
+
export declare const VEGA_LITE_SCHEMA = "https://vega.github.io/schema/vega-lite/v6.json";
|
|
59
|
+
/** Options for {@link emitVegaLite}. */
|
|
60
|
+
interface EmitVegaLiteOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Resolved data rows for specs whose data is a `query` or `node` reference.
|
|
63
|
+
* Vega-Lite has no concept of host data references, so the host must
|
|
64
|
+
* pre-resolve them (see the capability matrix).
|
|
65
|
+
*/
|
|
66
|
+
readonly rows?: ReadonlyArray<Datum> | undefined;
|
|
67
|
+
/** Chart width. Defaults to 'container' (responsive). */
|
|
68
|
+
readonly width?: number | 'container' | undefined;
|
|
69
|
+
/** Chart height in pixels. */
|
|
70
|
+
readonly height?: number | undefined;
|
|
71
|
+
}
|
|
72
|
+
/** Why a spec could not be emitted: a mark Vega-Lite has no equivalent for, or data the host must resolve. */
|
|
73
|
+
type VegaLiteEmitErrorReason = 'unsupported-mark' | 'unresolved-data';
|
|
74
|
+
/**
|
|
75
|
+
* Thrown when a spec cannot be represented in Vega-Lite. `reason` says
|
|
76
|
+
* which way, so a host can fall back without parsing the message: on
|
|
77
|
+
* `'unsupported-mark'` (the `tree` mark, ⛔ in the capability matrix) render
|
|
78
|
+
* the spec with a TS interpreter instead, which also carries the
|
|
79
|
+
* nested-list text alternative.
|
|
80
|
+
*/
|
|
81
|
+
export declare class VegaLiteEmitError extends Error {
|
|
82
|
+
readonly name = "VegaLiteEmitError";
|
|
83
|
+
readonly reason: VegaLiteEmitErrorReason;
|
|
84
|
+
constructor(message: string, reason?: VegaLiteEmitErrorReason);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Emits a Vega-Lite specification from a portable chart spec.
|
|
88
|
+
*
|
|
89
|
+
* This is the escape hatch / SSR fallback interpreter, and doubles as the
|
|
90
|
+
* proof that the portable spec is genuinely Vega-Lite-shaped: marks and
|
|
91
|
+
* typed encodings translate one-to-one.
|
|
92
|
+
*
|
|
93
|
+
* Web-only `extensions` are ignored, per the capability matrix.
|
|
94
|
+
*/
|
|
95
|
+
export declare function emitVegaLite(spec: ChartSpec, options?: EmitVegaLiteOptions): VegaLiteSpec;
|
|
96
|
+
export type { EmitVegaLiteOptions, VegaLiteData, VegaLiteEmitErrorReason, VegaLiteEncoding, VegaLiteFieldDef, VegaLiteSecondaryFieldDef, VegaLiteSpec };
|
|
97
|
+
//# sourceMappingURL=vega.d.mts.map
|
package/dist/vega.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { a as isDataRef, o as isInlineData } from "./spec-FF2Tds2a.mjs";
|
|
2
|
+
// src/vega/emit.ts
|
|
3
|
+
/** The Vega-Lite schema the emitter targets. */
|
|
4
|
+
const VEGA_LITE_SCHEMA = "https://vega.github.io/schema/vega-lite/v6.json";
|
|
5
|
+
/**
|
|
6
|
+
* Thrown when a spec cannot be represented in Vega-Lite. `reason` says
|
|
7
|
+
* which way, so a host can fall back without parsing the message: on
|
|
8
|
+
* `'unsupported-mark'` (the `tree` mark, ⛔ in the capability matrix) render
|
|
9
|
+
* the spec with a TS interpreter instead, which also carries the
|
|
10
|
+
* nested-list text alternative.
|
|
11
|
+
*/
|
|
12
|
+
var VegaLiteEmitError = class extends Error {
|
|
13
|
+
name = "VegaLiteEmitError";
|
|
14
|
+
reason;
|
|
15
|
+
constructor(message, reason = "unresolved-data") {
|
|
16
|
+
super(message);
|
|
17
|
+
this.reason = reason;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Emits a Vega-Lite specification from a portable chart spec.
|
|
22
|
+
*
|
|
23
|
+
* This is the escape hatch / SSR fallback interpreter, and doubles as the
|
|
24
|
+
* proof that the portable spec is genuinely Vega-Lite-shaped: marks and
|
|
25
|
+
* typed encodings translate one-to-one.
|
|
26
|
+
*
|
|
27
|
+
* Web-only `extensions` are ignored, per the capability matrix.
|
|
28
|
+
*/
|
|
29
|
+
function emitVegaLite(spec, options) {
|
|
30
|
+
if (spec.mark === "tree") throw new VegaLiteEmitError("Vega-Lite has no tree layout (that is full Vega); render a \"tree\" spec with a TS interpreter", "unsupported-mark");
|
|
31
|
+
return {
|
|
32
|
+
$schema: VEGA_LITE_SCHEMA,
|
|
33
|
+
...spec.config?.title !== void 0 ? { title: spec.config.title } : {},
|
|
34
|
+
mark: {
|
|
35
|
+
type: spec.mark,
|
|
36
|
+
...spec.config?.tooltip !== void 0 ? { tooltip: spec.config.tooltip } : {}
|
|
37
|
+
},
|
|
38
|
+
data: emitData(spec, options?.rows),
|
|
39
|
+
encoding: emitEncoding(spec),
|
|
40
|
+
width: options?.width ?? "container",
|
|
41
|
+
...options?.height !== void 0 ? { height: options.height } : {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function emitData(spec, rows) {
|
|
45
|
+
if (rows) return { values: rows };
|
|
46
|
+
if (isInlineData(spec.data)) return { values: spec.data.values };
|
|
47
|
+
if (isDataRef(spec.data) && spec.data.ref.kind === "url") return { url: spec.data.ref.id };
|
|
48
|
+
throw new VegaLiteEmitError(`Vega-Lite cannot resolve ${spec.data.ref.kind} data references; the host must resolve the data and pass rows via options.rows`);
|
|
49
|
+
}
|
|
50
|
+
function emitEncoding(spec) {
|
|
51
|
+
return {
|
|
52
|
+
...emitChannel("x", spec.encoding.x, spec.scales?.x),
|
|
53
|
+
...emitChannel("y", spec.encoding.y, spec.scales?.y),
|
|
54
|
+
...spec.encoding.x2 ? { x2: { field: spec.encoding.x2.field } } : {},
|
|
55
|
+
...spec.encoding.y2 ? { y2: { field: spec.encoding.y2.field } } : {},
|
|
56
|
+
...emitChannel("color", spec.encoding.color),
|
|
57
|
+
...emitChannel("size", spec.encoding.size),
|
|
58
|
+
...emitChannel("opacity", spec.encoding.opacity)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function emitChannel(name, channel, hint) {
|
|
62
|
+
if (!channel) return {};
|
|
63
|
+
const scale = emitScale(hint);
|
|
64
|
+
const fieldDef = {
|
|
65
|
+
field: channel.field,
|
|
66
|
+
type: channel.type,
|
|
67
|
+
...scale ? { scale } : {}
|
|
68
|
+
};
|
|
69
|
+
return { [name]: fieldDef };
|
|
70
|
+
}
|
|
71
|
+
function emitScale(hint) {
|
|
72
|
+
if (!hint) return void 0;
|
|
73
|
+
const scale = {
|
|
74
|
+
...hint.domain !== void 0 ? { domain: hint.domain } : {},
|
|
75
|
+
...hint.nice !== void 0 ? { nice: hint.nice } : {},
|
|
76
|
+
...hint.zero !== void 0 ? { zero: hint.zero } : {}
|
|
77
|
+
};
|
|
78
|
+
return Object.keys(scale).length > 0 ? scale : void 0;
|
|
79
|
+
}
|
|
80
|
+
export { VEGA_LITE_SCHEMA, VegaLiteEmitError, emitVegaLite };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=vega.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vega.mjs","names":[],"sources":["../src/vega/emit.ts"],"sourcesContent":["import {\n isDataRef,\n isInlineData,\n type ChartSpec,\n type Channel,\n type Datum,\n type ScaleHint,\n} from '../spec/index.ts';\nimport type { VegaLiteData, VegaLiteEncoding, VegaLiteFieldDef, VegaLiteSpec } from './types.ts';\n\n/** The Vega-Lite schema the emitter targets. */\nexport const VEGA_LITE_SCHEMA = 'https://vega.github.io/schema/vega-lite/v6.json';\n\n/** Options for {@link emitVegaLite}. */\nexport interface EmitVegaLiteOptions {\n /**\n * Resolved data rows for specs whose data is a `query` or `node` reference.\n * Vega-Lite has no concept of host data references, so the host must\n * pre-resolve them (see the capability matrix).\n */\n readonly rows?: ReadonlyArray<Datum> | undefined;\n /** Chart width. Defaults to 'container' (responsive). */\n readonly width?: number | 'container' | undefined;\n /** Chart height in pixels. */\n readonly height?: number | undefined;\n}\n\n/** Why a spec could not be emitted: a mark Vega-Lite has no equivalent for, or data the host must resolve. */\nexport type VegaLiteEmitErrorReason = 'unsupported-mark' | 'unresolved-data';\n\n/**\n * Thrown when a spec cannot be represented in Vega-Lite. `reason` says\n * which way, so a host can fall back without parsing the message: on\n * `'unsupported-mark'` (the `tree` mark, ⛔ in the capability matrix) render\n * the spec with a TS interpreter instead, which also carries the\n * nested-list text alternative.\n */\nexport class VegaLiteEmitError extends Error {\n override readonly name = 'VegaLiteEmitError';\n readonly reason: VegaLiteEmitErrorReason;\n\n constructor(message: string, reason: VegaLiteEmitErrorReason = 'unresolved-data') {\n super(message);\n this.reason = reason;\n }\n}\n\n/**\n * Emits a Vega-Lite specification from a portable chart spec.\n *\n * This is the escape hatch / SSR fallback interpreter, and doubles as the\n * proof that the portable spec is genuinely Vega-Lite-shaped: marks and\n * typed encodings translate one-to-one.\n *\n * Web-only `extensions` are ignored, per the capability matrix.\n */\nexport function emitVegaLite(spec: ChartSpec, options?: EmitVegaLiteOptions): VegaLiteSpec {\n if (spec.mark === 'tree') {\n throw new VegaLiteEmitError(\n 'Vega-Lite has no tree layout (that is full Vega); render a \"tree\" spec with a TS interpreter',\n 'unsupported-mark',\n );\n }\n return {\n $schema: VEGA_LITE_SCHEMA,\n ...(spec.config?.title !== undefined ? { title: spec.config.title } : {}),\n mark: {\n type: spec.mark,\n ...(spec.config?.tooltip !== undefined ? { tooltip: spec.config.tooltip } : {}),\n },\n data: emitData(spec, options?.rows),\n encoding: emitEncoding(spec),\n width: options?.width ?? 'container',\n ...(options?.height !== undefined ? { height: options.height } : {}),\n };\n}\n\nfunction emitData(spec: ChartSpec, rows?: ReadonlyArray<Datum>): VegaLiteData {\n // Pre-resolved rows always win: they are what the chart should show.\n if (rows) return { values: rows };\n\n if (isInlineData(spec.data)) {\n return { values: spec.data.values };\n }\n\n if (isDataRef(spec.data) && spec.data.ref.kind === 'url') {\n return { url: spec.data.ref.id };\n }\n\n throw new VegaLiteEmitError(\n `Vega-Lite cannot resolve ${spec.data.ref.kind} data references; ` +\n 'the host must resolve the data and pass rows via options.rows',\n );\n}\n\nfunction emitEncoding(spec: ChartSpec): VegaLiteEncoding {\n return {\n ...emitChannel('x', spec.encoding.x, spec.scales?.x),\n ...emitChannel('y', spec.encoding.y, spec.scales?.y),\n // Range ends map straight across: Vega-Lite's x2 / y2 take the primary\n // channel's type and scale, so only the field is emitted.\n ...(spec.encoding.x2 ? { x2: { field: spec.encoding.x2.field } } : {}),\n ...(spec.encoding.y2 ? { y2: { field: spec.encoding.y2.field } } : {}),\n ...emitChannel('color', spec.encoding.color),\n ...emitChannel('size', spec.encoding.size),\n ...emitChannel('opacity', spec.encoding.opacity),\n };\n}\n\nfunction emitChannel(\n name: 'x' | 'y' | 'color' | 'size' | 'opacity',\n channel: Channel | undefined,\n hint?: ScaleHint,\n): Partial<VegaLiteEncoding> {\n if (!channel) return {};\n\n const scale = emitScale(hint);\n const fieldDef: VegaLiteFieldDef = {\n field: channel.field,\n type: channel.type,\n ...(scale ? { scale } : {}),\n };\n return { [name]: fieldDef };\n}\n\nfunction emitScale(hint?: ScaleHint): VegaLiteFieldDef['scale'] | undefined {\n if (!hint) return undefined;\n const scale = {\n ...(hint.domain !== undefined ? { domain: hint.domain } : {}),\n ...(hint.nice !== undefined ? { nice: hint.nice } : {}),\n ...(hint.zero !== undefined ? { zero: hint.zero } : {}),\n };\n return Object.keys(scale).length > 0 ? scale : undefined;\n}\n"],"mappings":";;;AAWA,MAAa,mBAAmB;;;;;;;;AA0BhC,IAAa,oBAAb,cAAuC,MAAM;CAC3C,OAAyB;CACzB;CAEA,YAAY,SAAiB,SAAkC,mBAAmB;EAChF,MAAM,OAAO;EACb,KAAK,SAAS;CAChB;AACF;;;;;;;;;;AAWA,SAAgB,aAAa,MAAiB,SAA6C;CACzF,IAAI,KAAK,SAAS,QAChB,MAAM,IAAI,kBACR,kGACA,kBACF;CAEF,OAAO;EACL,SAAS;EACT,GAAI,KAAK,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,OAAO,MAAM,IAAI,CAAC;EACvE,MAAM;GACJ,MAAM,KAAK;GACX,GAAI,KAAK,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,OAAO,QAAQ,IAAI,CAAC;EAC/E;EACA,MAAM,SAAS,MAAM,SAAS,IAAI;EAClC,UAAU,aAAa,IAAI;EAC3B,OAAO,SAAS,SAAS;EACzB,GAAI,SAAS,WAAW,KAAA,IAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;CACpE;AACF;AAEA,SAAS,SAAS,MAAiB,MAA2C;CAE5E,IAAI,MAAM,OAAO,EAAE,QAAQ,KAAK;CAEhC,IAAI,aAAa,KAAK,IAAI,GACxB,OAAO,EAAE,QAAQ,KAAK,KAAK,OAAO;CAGpC,IAAI,UAAU,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,SAAS,OACjD,OAAO,EAAE,KAAK,KAAK,KAAK,IAAI,GAAG;CAGjC,MAAM,IAAI,kBACR,4BAA4B,KAAK,KAAK,IAAI,KAAK,gFAEjD;AACF;AAEA,SAAS,aAAa,MAAmC;CACvD,OAAO;EACL,GAAG,YAAY,KAAK,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;EACnD,GAAG,YAAY,KAAK,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;EAGnD,GAAI,KAAK,SAAS,KAAK,EAAE,IAAI,EAAE,OAAO,KAAK,SAAS,GAAG,MAAM,EAAE,IAAI,CAAC;EACpE,GAAI,KAAK,SAAS,KAAK,EAAE,IAAI,EAAE,OAAO,KAAK,SAAS,GAAG,MAAM,EAAE,IAAI,CAAC;EACpE,GAAG,YAAY,SAAS,KAAK,SAAS,KAAK;EAC3C,GAAG,YAAY,QAAQ,KAAK,SAAS,IAAI;EACzC,GAAG,YAAY,WAAW,KAAK,SAAS,OAAO;CACjD;AACF;AAEA,SAAS,YACP,MACA,SACA,MAC2B;CAC3B,IAAI,CAAC,SAAS,OAAO,CAAC;CAEtB,MAAM,QAAQ,UAAU,IAAI;CAC5B,MAAM,WAA6B;EACjC,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC3B;CACA,OAAO,GAAG,OAAO,SAAS;AAC5B;AAEA,SAAS,UAAU,MAAyD;CAC1E,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,MAAM,QAAQ;EACZ,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;CACvD;CACA,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ,KAAA;AACjD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,93 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://www.schemastore.org/package",
|
|
2
3
|
"name": "@thomasfosterau/charts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "A portable, renderer-agnostic chart spec — its JSON Schema, a pure TypeScript geometry core, and Svelte, ProseMirror and Vega-Lite interpreters",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"charts",
|
|
8
|
+
"grammar-of-graphics",
|
|
9
|
+
"json-schema",
|
|
10
|
+
"prosemirror",
|
|
11
|
+
"svelte",
|
|
12
|
+
"svelte5",
|
|
13
|
+
"vega-lite",
|
|
14
|
+
"visualization"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Thomas Foster <me@thomasfoster.au>",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/thomasfosterau/components.git",
|
|
21
|
+
"directory": "packages/charts"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"schema"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.mts",
|
|
33
|
+
"default": "./dist/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./core": {
|
|
36
|
+
"types": "./dist/core.d.mts",
|
|
37
|
+
"default": "./dist/core.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./prosemirror": {
|
|
40
|
+
"types": "./dist/prosemirror.d.mts",
|
|
41
|
+
"default": "./dist/prosemirror.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./svelte": {
|
|
44
|
+
"types": "./dist/svelte/index.d.ts",
|
|
45
|
+
"svelte": "./dist/svelte/index.js",
|
|
46
|
+
"default": "./dist/svelte/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./vega": {
|
|
49
|
+
"types": "./dist/vega.d.mts",
|
|
50
|
+
"default": "./dist/vega.mjs"
|
|
51
|
+
},
|
|
52
|
+
"./schema.json": "./schema/chart-spec.v1.json"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"d3-scale": "^4.0.2",
|
|
59
|
+
"d3-shape": "^3.2.0",
|
|
60
|
+
"effect": "^4.0.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@sveltejs/package": "3.0.2",
|
|
64
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
65
|
+
"@types/d3-scale": "^4.0.9",
|
|
66
|
+
"@types/d3-shape": "^3.1.8",
|
|
67
|
+
"@types/node": "^26.6.6",
|
|
68
|
+
"happy-dom": "^21.0.4",
|
|
69
|
+
"prosemirror-model": "^1.25.7",
|
|
70
|
+
"prosemirror-view": "^1.42.9",
|
|
71
|
+
"svelte": "^5.57.3",
|
|
72
|
+
"svelte-check": "^4.7.7",
|
|
73
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
74
|
+
"vega": "^6.2.0",
|
|
75
|
+
"vega-lite": "^6.4.3"
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"prosemirror-model": "^1.0.0",
|
|
79
|
+
"prosemirror-view": "^1.0.0",
|
|
80
|
+
"svelte": "^5.40.0"
|
|
81
|
+
},
|
|
82
|
+
"peerDependenciesMeta": {
|
|
83
|
+
"prosemirror-model": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"prosemirror-view": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"svelte": {
|
|
90
|
+
"optional": true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
6
93
|
}
|