mayacharts 0.1.0 → 0.2.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/README.md CHANGED
@@ -52,55 +52,55 @@ Rule: `x` is always the category, `y` is always the value, whatever the orientat
52
52
 
53
53
  ### Data
54
54
 
55
- | Field | Type | Applies to | Default | Meaning |
56
- | ----------- | ------------------------------ | --------------------- | ---------- | ------------------------------------------------------------------------------------- |
57
- | `$schema` | string | all | - | Ignored; for editors and LLMs |
58
- | `type` | enum | all | required | `bar line area scatter heatmap waterfall kpi dumbbell treemap sunburst sankey hexmap` |
59
- | `data` | Row[] | all | required | Row objects |
60
- | `aggregate` | sum / mean / count / min / max | all | sum | How rows sharing a (category, series) combine; `count` counts non-null y |
61
- | `sort` | asc / desc | bar line area heatmap | data order | Categories by total across all series |
62
- | `limit` | positive integer | bar line area heatmap | - | Keep top N categories; rest roll up into "Other" |
55
+ | Field | Type | Applies to | Default | Meaning |
56
+ | ----------- | ------------------------------ | --------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | `$schema` | string | all | - | Ignored; for editors and LLMs |
58
+ | `type` | enum | all | required | `bar line area scatter heatmap waterfall kpi dumbbell ridgeline beeswarm parallel table treemap sunburst sankey chord marimekko waffle radial hexmap` |
59
+ | `data` | Row[] | all | required | Row objects |
60
+ | `aggregate` | sum / mean / count / min / max | all | sum | How rows sharing a (category, series) combine; `count` counts non-null y |
61
+ | `sort` | asc / desc | bar line area heatmap | data order | Categories by total across all series |
62
+ | `limit` | positive integer | bar line area heatmap | - | Keep top N categories; rest roll up into "Other" |
63
63
 
64
64
  ### Encoding
65
65
 
66
- | Field | Type | Applies to | Meaning |
67
- | ------------ | ---------------- | ------------------------------------------------- | ------------------------------------------------------------------------ |
68
- | `x` | field | all but path types | Category; scatter numeric x; hexmap state |
69
- | `y` | field or field[] | all | Value; array adds measure toggle |
70
- | `series` | field | bar line area scatter heatmap dumbbell | Split into series; heatmap row category; dumbbell exactly two (from, to) |
71
- | `path` | field[] | treemap sunburst sankey; bar/line/area with drill | Hierarchy outer to inner; replaces `x` |
72
- | `size` | field | scatter | Bubble area (sqrt scale) |
73
- | `name` | field | scatter | Point identity and tooltip title |
74
- | `totals` | string[] | waterfall | x values drawn as running-total bars |
75
- | `stack` | boolean | bar area | Stack series instead of grouping |
76
- | `horizontal` | boolean | bar dumbbell | Categories on the left axis |
77
- | `y2` | field | bar | Second value field as a line on right axis (vertical bars only) |
66
+ | Field | Type | Applies to | Meaning |
67
+ | ------------ | ---------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
68
+ | `x` | field | all but path types | Category; scatter numeric x; hexmap state; beeswarm optional row |
69
+ | `y` | field or field[] | all | Value; array adds measure toggle (all-y types: axes/columns) |
70
+ | `series` | field | bar line area scatter heatmap dumbbell ridgeline beeswarm parallel marimekko radial | Split into series; heatmap row category; dumbbell exactly two (from, to) |
71
+ | `path` | field[] | treemap sunburst sankey chord; bar/line/area/dumbbell with drill | Hierarchy outer to inner; replaces `x` |
72
+ | `size` | field | scatter | Bubble area (sqrt scale) |
73
+ | `name` | field | scatter beeswarm | Point identity and tooltip title |
74
+ | `totals` | string[] | waterfall | x values drawn as running-total bars |
75
+ | `stack` | boolean | bar area | Stack series instead of grouping |
76
+ | `horizontal` | boolean | bar dumbbell | Categories on the left axis |
77
+ | `y2` | field | bar | Second value field as a line on right axis (vertical bars only) |
78
78
 
79
79
  ### Formatting
80
80
 
81
- | Field | Type | Default | Meaning |
82
- | ------------- | ----------------- | ------------------------------- | ------------------------------------------------------- |
83
- | `format` | preset or options | auto | Per field or one string for all measures; display only |
84
- | `titles` | {[field]: string} | field names | Display names everywhere (axis, tooltip, legend, table) |
85
- | `labels` | boolean | false (heatmap: true at ≥24 px) | Formatted value on marks |
86
- | `text` | {[key]: string} | English | Localisable UI strings with {0} placeholders |
87
- | `locale` | BCP 47 | en-US | Formatting locale |
88
- | `currency` | ISO 4217 | USD | Currency for the currency preset |
89
- | `title` | string | - | Visible heading and accessible name |
90
- | `description` | string | auto | Accessible description |
91
- | `yDomain` | [min, max] | - | Fixed value-axis domain |
92
- | `xDomain` | [min, max] | - | Fixed x domain (scatter only) |
81
+ | Field | Type | Default | Meaning |
82
+ | ------------- | ----------------- | ------------------------------- | ------------------------------------------------------------------- |
83
+ | `format` | preset or options | auto | Per field or one string for all measures; display only |
84
+ | `titles` | {[field]: string} | field names | Display names everywhere (axis, tooltip, legend, table) |
85
+ | `labels` | boolean | false (heatmap: true at ≥24 px) | Formatted value on marks |
86
+ | `text` | {[key]: string} | English | Localisable UI strings with {0} placeholders |
87
+ | `locale` | BCP 47 | en-US | Formatting locale |
88
+ | `currency` | ISO 4217 | USD | Currency for the currency preset |
89
+ | `title` | string | - | Visible heading and accessible name |
90
+ | `description` | string | auto | Accessible description |
91
+ | `yDomain` | [min, max] | - | Fixed value-axis domain; [hi, lo] reverses it (ranks with 1 on top) |
92
+ | `xDomain` | [min, max] | - | Fixed x domain (scatter only) |
93
93
 
94
94
  ### Interaction
95
95
 
96
- | Field | Type | Applies to | Default | Meaning |
97
- | --------- | -------------- | -------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------ |
98
- | `tooltip` | boolean | all | true | Hover/keyboard tooltip |
99
- | `legend` | boolean | all | true when `series` is set | Legend; clicking toggles series |
100
- | `drill` | boolean | treemap sunburst sankey; bar line area with `path` | false | Click/Enter zooms into a branch of path; breadcrumb, Back and Escape pop |
101
- | `select` | true / "multi" | all but sankey | off | Click/Enter/legend selects marks; Escape clears. Not with drill |
102
- | `zoom` | boolean | line area scatter | false | Drag to zoom; Reset, double-click, Escape restore |
103
- | `animate` | boolean | all (element only) | true | Animate updates |
96
+ | Field | Type | Applies to | Default | Meaning |
97
+ | --------- | -------------- | ----------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------ |
98
+ | `tooltip` | boolean | all | true | Hover/keyboard tooltip |
99
+ | `legend` | boolean | all | true when `series` is set | Legend; clicking toggles series |
100
+ | `drill` | boolean | treemap sunburst sankey; bar line area dumbbell with `path` | false | Click/Enter zooms into a branch of path; breadcrumb, Back and Escape pop |
101
+ | `select` | true / "multi" | all but sankey | off | Click/Enter/legend selects marks; Escape clears. Not with drill |
102
+ | `zoom` | boolean | line area scatter | false | Drag to zoom; Reset, double-click, Escape restore |
103
+ | `animate` | boolean | all (element only) | true | Animate updates |
104
104
 
105
105
  ### Style
106
106
 
@@ -294,15 +294,136 @@ Rule: `x` is always the category, `y` is always the value, whatever the orientat
294
294
  }
295
295
  ```
296
296
 
297
+ **Ridgeline**
298
+
299
+ ```json
300
+ {
301
+ "type": "ridgeline",
302
+ "x": "year",
303
+ "y": "value",
304
+ "series": "product",
305
+ "data": [
306
+ { "year": 2020, "product": "A", "value": 100 },
307
+ { "year": 2021, "product": "A", "value": 120 }
308
+ ]
309
+ }
310
+ ```
311
+
312
+ **Beeswarm**
313
+
314
+ ```json
315
+ {
316
+ "type": "beeswarm",
317
+ "y": "value",
318
+ "series": "category",
319
+ "name": "id",
320
+ "data": [
321
+ { "id": "1", "category": "A", "value": 15 },
322
+ { "id": "2", "category": "A", "value": 18 }
323
+ ]
324
+ }
325
+ ```
326
+
327
+ **Parallel coordinates**
328
+
329
+ ```json
330
+ {
331
+ "type": "parallel",
332
+ "x": "item",
333
+ "y": ["revenue", "units", "margin"],
334
+ "series": "region",
335
+ "data": [
336
+ { "item": "1", "region": "North", "revenue": 1000, "units": 50, "margin": 0.25 },
337
+ { "item": "2", "region": "South", "revenue": 1200, "units": 60, "margin": 0.22 }
338
+ ]
339
+ }
340
+ ```
341
+
342
+ **Table**
343
+
344
+ ```json
345
+ {
346
+ "type": "table",
347
+ "x": "product",
348
+ "y": ["revenue", "units"],
349
+ "sort": "desc",
350
+ "format": { "revenue": "currency", "units": "integer" },
351
+ "data": [
352
+ { "product": "A", "revenue": 5000, "units": 100 },
353
+ { "product": "B", "revenue": 3500, "units": 75 }
354
+ ]
355
+ }
356
+ ```
357
+
358
+ **Radial**
359
+
360
+ ```json
361
+ {
362
+ "type": "radial",
363
+ "x": "month",
364
+ "y": "value",
365
+ "series": "product",
366
+ "data": [
367
+ { "month": "Jan", "product": "A", "value": 10 },
368
+ { "month": "Feb", "product": "A", "value": 15 }
369
+ ]
370
+ }
371
+ ```
372
+
373
+ **Chord diagram**
374
+
375
+ ```json
376
+ {
377
+ "type": "chord",
378
+ "path": ["from", "to"],
379
+ "y": "flow",
380
+ "data": [
381
+ { "from": "A", "to": "B", "flow": 100 },
382
+ { "from": "B", "to": "C", "flow": 75 }
383
+ ]
384
+ }
385
+ ```
386
+
387
+ **Marimekko (treemap grid)**
388
+
389
+ ```json
390
+ {
391
+ "type": "marimekko",
392
+ "x": "category",
393
+ "y": "value",
394
+ "series": "segment",
395
+ "data": [
396
+ { "category": "A", "segment": "X", "value": 50 },
397
+ { "category": "A", "segment": "Y", "value": 30 }
398
+ ]
399
+ }
400
+ ```
401
+
402
+ **Waffle**
403
+
404
+ ```json
405
+ {
406
+ "type": "waffle",
407
+ "x": "category",
408
+ "y": "value",
409
+ "data": [
410
+ { "category": "A", "value": 45 },
411
+ { "category": "B", "value": 30 },
412
+ { "category": "C", "value": 25 }
413
+ ]
414
+ }
415
+ ```
416
+
297
417
  ## Modules
298
418
 
299
419
  Each module extends the core with chart types and shares the same spec, theme, tooltip, a11y, and animation.
300
420
 
301
- | Module | Types | Size budget (gzip) |
302
- | ---------------------- | ------------------------------- | ------------------ |
303
- | `mayacharts/hierarchy` | treemap, sunburst | 3 KB |
304
- | `mayacharts/flow` | sankey | 2.5 KB |
305
- | `mayacharts/geo` | hexmap (50 US states + DC + PR) | 3.5 KB |
421
+ | Module | Types | Size budget (gzip) |
422
+ | ---------------------- | ------------------------------------ | ------------------ |
423
+ | `mayacharts/hierarchy` | treemap, sunburst, marimekko, waffle | 3.5 KB |
424
+ | `mayacharts/flow` | sankey, chord | 3 KB |
425
+ | `mayacharts/radial` | radial | 2 KB |
426
+ | `mayacharts/geo` | hexmap (50 US states + DC + PR) | 3.5 KB |
306
427
 
307
428
  ## Global build
308
429
 
@@ -0,0 +1,3 @@
1
+ import type { Mark } from "../types.ts";
2
+ /** Dots dodged off a shared value axis: y = value (bottom axis), x = optional row category (left band). */
3
+ export declare const beeswarm: Mark;
@@ -0,0 +1,6 @@
1
+ import type { Mark } from "../types.ts";
2
+ /**
3
+ * One polyline per x category across one vertical axis per measure (`spec.measures`), each with its
4
+ * own linear scale. No Mark.axes: axes, ticks and titles are drawn here (grid + labels).
5
+ */
6
+ export declare const parallel: Mark;
@@ -0,0 +1,3 @@
1
+ import type { Mark } from "../types.ts";
2
+ /** Rows of areas, first series on top, each scaled 0..global max so peaks overlap the row above. */
3
+ export declare const ridgeline: Mark;
@@ -0,0 +1,6 @@
1
+ import type { Mark } from "../types.ts";
2
+ /**
3
+ * Rows = x categories, one column per measure (every `spec.y` entry), value text plus a thin bar
4
+ * scaled to the column max. Header cells are `data-maya="sort"` groups (element/sort.ts).
5
+ */
6
+ export declare const table: Mark;
@@ -1,10 +1,10 @@
1
1
  import type { Mark } from "./types.ts";
2
- export declare const VERSION = "0.1.0";
2
+ export declare const VERSION = "0.2.0";
3
3
  export declare const MAJOR = "0";
4
4
  /** type -> Mark for every registered module type (shared across bundles). */
5
5
  export declare const MODULES: Map<string, Mark>;
6
6
  /** Types that ship in core (static CORE map in render.ts). */
7
- export declare const CORE_TYPES: readonly ["bar", "line", "area", "scatter", "heatmap", "waterfall", "kpi", "dumbbell"];
7
+ export declare const CORE_TYPES: readonly ["bar", "line", "area", "scatter", "heatmap", "waterfall", "kpi", "dumbbell", "ridgeline", "beeswarm", "parallel", "table"];
8
8
  /** Module types and the import that provides them (for the unknown-type hint). */
9
9
  export declare const MODULE_OF: Readonly<Record<string, string>>;
10
10
  /** Not exported from the public entry: modules call it on import. First wins. */
@@ -14,6 +14,8 @@ export declare const TEXT: {
14
14
  readonly selectionCleared: "Selection cleared";
15
15
  /** Auto description: {0} = noun, {1} = y title, {2} = x title. */
16
16
  readonly chartOf: "{0} chart of {1} by {2}";
17
+ /** Auto description without a category field: {0} = noun, {1} = y title. */
18
+ readonly chartOfAll: "{0} chart of {1}";
17
19
  /** Table caption when rows are capped: {0} = shown, {1} = total. */
18
20
  readonly firstOf: "First {0} of {1} rows";
19
21
  /** aria-label of the measure radiogroup. */
@@ -27,6 +29,10 @@ export declare const TEXT: {
27
29
  readonly below: "below target";
28
30
  /** kpi delta: {0} = signed change, {1} = previous period. */
29
31
  readonly vs: "{0} vs {1}";
32
+ /** Live region after a table header click: {0} = column title, {1} = ascending/descending. */
33
+ readonly sortedBy: "Sorted by {0}, {1}";
34
+ readonly ascending: "ascending";
35
+ readonly descending: "descending";
30
36
  /** kpi bullet: {0} = share of target, {1} = target. */
31
37
  readonly ofTarget: "{0} of target {1}";
32
38
  };
@@ -2,7 +2,7 @@ import type { TextKey } from "./strings.ts";
2
2
  export type { TextKey };
3
3
  /** A data row. Field values are read by name via `spec.x`, `spec.y`, `spec.series`… */
4
4
  export type Row = Readonly<Record<string, string | number | boolean | null | undefined>>;
5
- export type ChartType = "bar" | "line" | "area" | "scatter" | "heatmap" | "waterfall" | "kpi" | "dumbbell" | "treemap" | "sunburst" | "sankey" | "hexmap";
5
+ export type ChartType = "bar" | "line" | "area" | "scatter" | "heatmap" | "waterfall" | "kpi" | "dumbbell" | "ridgeline" | "beeswarm" | "parallel" | "table" | "treemap" | "sunburst" | "sankey" | "chord" | "marimekko" | "waffle" | "radial" | "hexmap";
6
6
  export type Aggregate = "sum" | "mean" | "count" | "min" | "max";
7
7
  export type NumberPreset = "auto" | "integer" | "decimal" | "compact" | "percent" | "currency";
8
8
  export type DatePreset = "date" | "month" | "year" | "time" | "datetime";
@@ -29,7 +29,7 @@ export interface ChartSpec<R extends object = Row> {
29
29
  /** Ignored; lets editors and LLMs find the JSON schema.
30
30
  * @example "$schema": "https://unpkg.com/mayacharts/schema.json" */
31
31
  $schema?: string;
32
- /** Chart type. treemap/sunburst need `mayacharts/hierarchy`, sankey `flow`, hexmap `geo`.
32
+ /** Chart type. treemap/sunburst/marimekko/waffle need `mayacharts/hierarchy`, sankey/chord `flow`, radial `radial`, hexmap `geo`.
33
33
  * @example type: "bar" */
34
34
  type: ChartType;
35
35
  /** Row objects.
@@ -44,22 +44,22 @@ export interface ChartSpec<R extends object = Row> {
44
44
  /** Keep the top N categories by total; the rest roll up into a final "Other".
45
45
  * @example limit: 10 */
46
46
  limit?: number;
47
- /** Category field (scatter: numeric x; hexmap: US state; kpi: optional period, last one is the headline). Not used by path types.
47
+ /** Category field (scatter: numeric x; hexmap: US state; kpi: optional period, last one is the headline; beeswarm: optional row; parallel: one line each; table: row label). Not used by path types.
48
48
  * @example x: "month" */
49
49
  x?: Field<R>;
50
- /** Value field; an array adds a measure toggle, first one active.
50
+ /** Value field; an array adds a measure toggle, first one active (parallel: one axis each; table: one column each).
51
51
  * @example y: ["revenue", "units"] */
52
52
  y: Field<R> | readonly Field<R>[];
53
- /** Splits rows into series (heatmap: the row category; dumbbell: exactly two, from and to). bar line area scatter heatmap dumbbell.
53
+ /** Splits rows into series (heatmap: the row category; dumbbell: exactly two, from and to; ridgeline: one row each; marimekko: the segments; radial: stacked outward). bar line area scatter heatmap dumbbell ridgeline beeswarm parallel marimekko radial.
54
54
  * @example series: "region" */
55
55
  series?: Field<R>;
56
- /** Hierarchy fields, outer to inner. treemap sunburst sankey; bar/line/area with `drill` (replaces `x`).
56
+ /** Hierarchy fields, outer to inner. treemap sunburst sankey; bar/line/area/dumbbell with `drill` (replaces `x`).
57
57
  * @example path: ["region", "state"] */
58
58
  path?: readonly Field<R>[];
59
59
  /** Bubble area field (sqrt scale). scatter only.
60
60
  * @example size: "population" */
61
61
  size?: Field<R>;
62
- /** Point identity and tooltip title. scatter only.
62
+ /** Point identity and tooltip title. scatter and beeswarm.
63
63
  * @example name: "country" */
64
64
  name?: Field<R>;
65
65
  /** x values drawn as running-total bars. waterfall only.
@@ -98,7 +98,7 @@ export interface ChartSpec<R extends object = Row> {
98
98
  /** Accessible description; auto-generated when omitted.
99
99
  * @example description: "Revenue doubled from January to December." */
100
100
  description?: string;
101
- /** Fixed value-axis domain. Not allowed with a `y` array.
101
+ /** Fixed value-axis domain; [hi, lo] reverses it (ranks with 1 on top). Not allowed with a `y` array.
102
102
  * @example yDomain: [0, 100] */
103
103
  yDomain?: readonly [number, number];
104
104
  /** Fixed x domain. scatter only.
@@ -162,6 +162,8 @@ export interface View {
162
162
  window?: readonly [number, number] | readonly [number, number, number, number];
163
163
  /** Series keys hidden by the legend. */
164
164
  hidden?: readonly string[];
165
+ /** Table column sort from a header click: [field, direction]. */
166
+ sortBy?: readonly [field: string, dir: "asc" | "desc"];
165
167
  }
166
168
  export interface RenderOptions {
167
169
  /** Pixel size of the plot box. Default 640 x 320. */
@@ -214,6 +216,8 @@ export interface ResolvedSpec {
214
216
  horizontal: boolean;
215
217
  aggregate: Aggregate;
216
218
  sort: "asc" | "desc" | null;
219
+ /** Table header sort from the view; null when unset. */
220
+ sortBy: readonly [field: string, dir: "asc" | "desc"] | null;
217
221
  limit: number | null;
218
222
  /** Per-field format; a bare-string `spec.format` is expanded to every measure. */
219
223
  format: ReadonlyMap<string, FieldFormat>;
@@ -9,6 +9,8 @@ export declare class MayaSpecError extends Error {
9
9
  export declare const MAX_MARKS = 5000;
10
10
  /** Every spec key (schema.json is tested against this). */
11
11
  export declare const KEYS: string[];
12
+ /** y arrays on these types are shown together (axes, columns), never a measure toggle. */
13
+ export declare const ALL_Y: string[];
12
14
  export declare const ONLY: Readonly<Record<string, readonly string[]>>;
13
15
  /** Format options holding any date key are Intl.DateTimeFormat options. */
14
16
  export declare const isDateOpts: (o: object) => boolean;
@@ -0,0 +1,8 @@
1
+ import type { Handlers, Host, SpecEvent, State } from "../core/types.ts";
2
+ export type SortEvent = {
3
+ type: "sort";
4
+ field: string;
5
+ label?: boolean;
6
+ } | SpecEvent;
7
+ export declare const reduce: (s: State, e: SortEvent) => State;
8
+ export declare const mount: (host: Host) => Handlers;