@blueprint-chart/lib 0.1.2
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 +109 -0
- package/dist/charts/axis/axis-service.d.ts +55 -0
- package/dist/charts/axis/horizontal-axis.d.ts +58 -0
- package/dist/charts/axis/index.d.ts +4 -0
- package/dist/charts/axis/vertical-axis.d.ts +12 -0
- package/dist/charts/canvas/canvas.d.ts +45 -0
- package/dist/charts/chart-helpers.d.ts +3 -0
- package/dist/charts/colorblind.d.ts +34 -0
- package/dist/charts/contrast.d.ts +33 -0
- package/dist/charts/curves.d.ts +2 -0
- package/dist/charts/date-parse.d.ts +12 -0
- package/dist/charts/defaults/expectations.d.ts +2 -0
- package/dist/charts/defaults/helpers.d.ts +6 -0
- package/dist/charts/defaults/types.d.ts +61 -0
- package/dist/charts/format-helpers.d.ts +31 -0
- package/dist/charts/frame/frame.d.ts +8 -0
- package/dist/charts/index.d.ts +17 -0
- package/dist/charts/legend/legend-size.d.ts +5 -0
- package/dist/charts/legend/legend.d.ts +4 -0
- package/dist/charts/line-symbols.d.ts +9 -0
- package/dist/charts/motion.d.ts +45 -0
- package/dist/charts/palettes.d.ts +7 -0
- package/dist/charts/plugins/annotations/context.d.ts +17 -0
- package/dist/charts/plugins/annotations/direction-helpers.d.ts +14 -0
- package/dist/charts/plugins/annotations/free-renderer.d.ts +4 -0
- package/dist/charts/plugins/annotations/index.d.ts +10 -0
- package/dist/charts/plugins/annotations/point-renderer.d.ts +6 -0
- package/dist/charts/plugins/annotations/position-helpers.d.ts +2 -0
- package/dist/charts/plugins/annotations/range-renderer.d.ts +4 -0
- package/dist/charts/plugins/annotations/shared.d.ts +57 -0
- package/dist/charts/plugins/annotations/snapshots.d.ts +21 -0
- package/dist/charts/plugins/arc-labels.d.ts +53 -0
- package/dist/charts/plugins/crosshair.d.ts +10 -0
- package/dist/charts/plugins/proximity.d.ts +27 -0
- package/dist/charts/plugins/test-helpers.d.ts +1 -0
- package/dist/charts/plugins/tooltip.d.ts +6 -0
- package/dist/charts/plugins/value-labels.d.ts +6 -0
- package/dist/charts/registry.d.ts +5 -0
- package/dist/charts/resolve.d.ts +3 -0
- package/dist/charts/scale-helpers.d.ts +19 -0
- package/dist/charts/series-helpers.d.ts +10 -0
- package/dist/charts/stack-helpers.d.ts +17 -0
- package/dist/charts/transition-cache.d.ts +8 -0
- package/dist/charts/types/area/area.d.ts +3 -0
- package/dist/charts/types/area-stacked/area-stacked.d.ts +3 -0
- package/dist/charts/types/bar-grouped/bar-grouped.d.ts +3 -0
- package/dist/charts/types/bar-horizontal/bar-horizontal.d.ts +3 -0
- package/dist/charts/types/bar-multi/bar-multi.d.ts +3 -0
- package/dist/charts/types/bar-split/bar-split.d.ts +3 -0
- package/dist/charts/types/bar-stacked/bar-stacked.d.ts +3 -0
- package/dist/charts/types/bar-vertical/bar-vertical.d.ts +3 -0
- package/dist/charts/types/column-stacked/column-stacked.d.ts +3 -0
- package/dist/charts/types/donut/donut.d.ts +4 -0
- package/dist/charts/types/line/line.d.ts +3 -0
- package/dist/charts/types/line-multi/line-multi.d.ts +3 -0
- package/dist/charts/types/pie/pie.d.ts +2 -0
- package/dist/charts/types.d.ts +269 -0
- package/dist/dsl/converter.d.ts +50 -0
- package/dist/dsl/index.d.ts +3 -0
- package/dist/dsl/lexer.d.ts +8 -0
- package/dist/dsl/parser.d.ts +2 -0
- package/dist/dsl/serializer.d.ts +3 -0
- package/dist/dsl/types.d.ts +88 -0
- package/dist/enums.d.ts +193 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +7088 -0
- package/dist/lib/lib.iife.js +186 -0
- package/dist/runtime/chart-css.d.ts +1 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/runtime.d.ts +1 -0
- package/dist/runtime/scenes.d.ts +19 -0
- package/dist/runtime/steps.d.ts +3 -0
- package/dist/samples.d.ts +10 -0
- package/package.json +73 -0
- package/src/charts/chart.scss +481 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pirhoo and Blueprint Chart contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @blueprint-chart/lib
|
|
2
|
+
|
|
3
|
+
Core library for Blueprint Chart — a DSL-driven charting engine built on D3.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @blueprint-chart/lib
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
The simplest way to render a chart is the IIFE runtime, which auto-scans the document for embedded chart definitions and renders each one inline (inside a sandboxed iframe inserted before the script tag):
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<script src="https://unpkg.com/@blueprint-chart/lib/dist/lib/lib.iife.js"></script>
|
|
17
|
+
|
|
18
|
+
<script type="application/blueprint-chart">
|
|
19
|
+
chart MyChart {
|
|
20
|
+
data { values = "[[0,1],[1,4],[2,2]]" }
|
|
21
|
+
series "line" { color = "steelblue" }
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For programmatic use in an ES module project, the lib exposes the underlying primitives: `parse` (DSL → AST), `buildChartOptions` (AST → render options), `createFrame`/`createCanvas`, and the chart registry (`registerChart`, `getChart`). See [src/index.ts](https://github.com/blueprint-chart/blueprint-chart/blob/main/packages/lib/src/index.ts) for the full public API.
|
|
27
|
+
|
|
28
|
+
## DSL Grammar
|
|
29
|
+
|
|
30
|
+
The chart DSL is defined by a PEG grammar in `src/dsl/grammar.peggy` and compiled to `src/dsl/grammar.js` using [Peggy](https://peggyjs.org/).
|
|
31
|
+
|
|
32
|
+
### EBNF Overview
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Chart = "chart" Identifier "{" ChartMember* "}"
|
|
36
|
+
ChartMember = DataBlock | Colorize | AreaFill | Annotation | Series | Scene | Property
|
|
37
|
+
|
|
38
|
+
DataBlock = "data" "{" Property* "}"
|
|
39
|
+
Colorize = "colorize" String "{" Property* "}"
|
|
40
|
+
AreaFill = "areafill" String String "{" Property* "}"
|
|
41
|
+
Annotation = "annotation" String "{" Property* "}"
|
|
42
|
+
Series = "series" String "{" Property* "}"
|
|
43
|
+
Scene = "scene" String "{" SceneMember* "}"
|
|
44
|
+
SceneMember = DataBlock | Colorize | AreaFill | Annotation | Property
|
|
45
|
+
|
|
46
|
+
Property = PropertyKey "=" PropertyValue
|
|
47
|
+
PropertyKey = String | Identifier
|
|
48
|
+
PropertyValue = Number "%" | Number | String | Identifier
|
|
49
|
+
|
|
50
|
+
Identifier = [a-zA-Z_#][a-zA-Z0-9_#-]*
|
|
51
|
+
Number = [0-9]+("."[0-9]+)?
|
|
52
|
+
String = '"' (EscapeSequence | [^"\\])* '"'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Example
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
chart horizontal-bar {
|
|
59
|
+
title = "Revenue by Region"
|
|
60
|
+
sort = descending
|
|
61
|
+
|
|
62
|
+
data {
|
|
63
|
+
"North America" = 75%
|
|
64
|
+
"Europe" = 53.85%
|
|
65
|
+
"Asia" = 44%
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
colorize "North America" {
|
|
69
|
+
color = "#e53e3e"
|
|
70
|
+
label = "Leader"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
scene "Focus" {
|
|
74
|
+
sort = ascending
|
|
75
|
+
colorize "Asia" {
|
|
76
|
+
color = "#38a169"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## AST Node Types
|
|
83
|
+
|
|
84
|
+
| Node | Fields |
|
|
85
|
+
|------|--------|
|
|
86
|
+
| `ChartNode` | `chartType`, `properties`, `data`, `colorizes`, `areaFills`, `annotations`, `series`, `scenes` |
|
|
87
|
+
| `PropertyNode` | `key`, `value`, `isPercentage` |
|
|
88
|
+
| `DataNode` | `entries` (PropertyNode[]) |
|
|
89
|
+
| `ColorizeNode` | `target`, `properties` |
|
|
90
|
+
| `AreaFillNode` | `from`, `to`, `properties` |
|
|
91
|
+
| `AnnotationNode` | `target`, `properties` |
|
|
92
|
+
| `SeriesNode` | `name`, `properties` |
|
|
93
|
+
| `SceneNode` | `name`, `properties`, `data`, `colorizes`, `areaFills`, `annotations` |
|
|
94
|
+
|
|
95
|
+
## Regenerating the Parser
|
|
96
|
+
|
|
97
|
+
The generated parser (`src/dsl/grammar.js`) is checked into git so downstream packages can import lib source directly without a build step.
|
|
98
|
+
|
|
99
|
+
To regenerate after editing `grammar.peggy`:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
pnpm --filter @blueprint-chart/lib run generate:parser
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This also runs automatically before `build` and `test` via `prebuild`/`pretest` hooks.
|
|
106
|
+
|
|
107
|
+
## Color Palettes
|
|
108
|
+
|
|
109
|
+
The built-in color palettes are curated from [pypalettes](https://github.com/y-sunflower/pypalettes) by Joseph Music, a collection of 2700+ color palettes for data visualization. Licensed under MIT.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AnyXScale } from './horizontal-axis';
|
|
2
|
+
import { AxisOptions } from '../types';
|
|
3
|
+
import * as d3 from 'd3';
|
|
4
|
+
export interface AxisServiceConfig {
|
|
5
|
+
vertical?: {
|
|
6
|
+
scale: d3.ScaleLinear<number, number> | d3.ScaleLogarithmic<number, number> | d3.ScaleSymLog<number, number> | d3.ScaleBand<string>;
|
|
7
|
+
height: number;
|
|
8
|
+
options: AxisOptions;
|
|
9
|
+
};
|
|
10
|
+
horizontal?: {
|
|
11
|
+
scale: AnyXScale;
|
|
12
|
+
height: number;
|
|
13
|
+
options: AxisOptions;
|
|
14
|
+
};
|
|
15
|
+
order?: 'vertical-first' | 'horizontal-first';
|
|
16
|
+
}
|
|
17
|
+
export declare class AxisService {
|
|
18
|
+
private vGroup;
|
|
19
|
+
private hGroup;
|
|
20
|
+
private vChart;
|
|
21
|
+
private hChart;
|
|
22
|
+
private container;
|
|
23
|
+
private initialized;
|
|
24
|
+
private constructor();
|
|
25
|
+
static for(container: HTMLElement): AxisService;
|
|
26
|
+
static clear(container: HTMLElement): void;
|
|
27
|
+
/**
|
|
28
|
+
* Remove axis groups from DOM before replaceChildren().
|
|
29
|
+
* The groups are kept in memory for reattachment.
|
|
30
|
+
*/
|
|
31
|
+
detach(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Insert axis wrapper groups into the given chartArea.
|
|
34
|
+
* On first call, creates new D3Blueprint instances.
|
|
35
|
+
* On subsequent calls, reinserts the existing groups.
|
|
36
|
+
*
|
|
37
|
+
* When marginDelta is provided (dx/dy from previous to current margin),
|
|
38
|
+
* axis groups are wrapped in a compensating transform that transitions
|
|
39
|
+
* to identity, preventing visual jumps when the chartArea origin shifts.
|
|
40
|
+
*/
|
|
41
|
+
attach(chartArea: SVGGElement, marginDelta?: {
|
|
42
|
+
dx: number;
|
|
43
|
+
dy: number;
|
|
44
|
+
}): void;
|
|
45
|
+
/**
|
|
46
|
+
* Configure and draw both axes.
|
|
47
|
+
*/
|
|
48
|
+
update(config: AxisServiceConfig): void;
|
|
49
|
+
private updateVertical;
|
|
50
|
+
private updateHorizontal;
|
|
51
|
+
/**
|
|
52
|
+
* Tear down the service and remove from the WeakMap.
|
|
53
|
+
*/
|
|
54
|
+
destroy(): void;
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { D3Blueprint } from 'd3-blueprint';
|
|
2
|
+
import { AxisOptions } from '../types';
|
|
3
|
+
import { detectDates, DateGranularity } from '../date-parse';
|
|
4
|
+
import * as d3 from 'd3';
|
|
5
|
+
interface AxisDatum {
|
|
6
|
+
placeholder: true;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a label across multiple lines by splitting on whitespace so each line
|
|
10
|
+
* fits within `maxWidthPx`. Returns `null` when it cannot be made to fit —
|
|
11
|
+
* either because a single word exceeds the width or the content requires more
|
|
12
|
+
* than `maxLines`. Used to avoid rotating labels when wrapping suffices.
|
|
13
|
+
*/
|
|
14
|
+
declare function wrapLabel(label: string, maxWidthPx: number, maxLines?: number): string[] | null;
|
|
15
|
+
type AnyXScale = d3.ScaleBand<string> | d3.ScalePoint<string> | d3.ScaleLinear<number, number> | d3.ScaleSymLog<number, number> | d3.ScaleTime<number, number>;
|
|
16
|
+
declare function buildTickFormatter(fmt: string | null, labels: string[]): ((d: string | d3.NumberValue) => string) | null;
|
|
17
|
+
declare function thinLabels(domain: string[], availableWidth: number, formatter?: ((d: string | d3.NumberValue) => string) | null): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Decide whether horizontal tick labels should be rotated 90° to avoid overlap.
|
|
20
|
+
* Applies only to ordinal (band/point) scales — time/linear scales thin instead.
|
|
21
|
+
*
|
|
22
|
+
* Ordinal domains of date-parseable labels (e.g. `"2024-01", "2024-02"…`) are
|
|
23
|
+
* treated as continuous: auto mode thins them rather than rotating. An explicit
|
|
24
|
+
* `labelRotation='vertical'` still forces rotation so the user override wins.
|
|
25
|
+
*
|
|
26
|
+
* - `labelRotation='vertical'` → always rotates (when domain has ≥2 entries).
|
|
27
|
+
* - `labelRotation='horizontal'` → never rotates.
|
|
28
|
+
* - `labelRotation='auto'` → rotates when the longest formatted label exceeds
|
|
29
|
+
* the per-tick band step and the domain is discrete (non-date).
|
|
30
|
+
*/
|
|
31
|
+
declare function willRotateLabels(domain: string[], availableWidth: number, labelRotation: string, formatter?: ((d: string | d3.NumberValue) => string) | null): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Estimate the pixel height needed below the chart for x-axis labels when
|
|
34
|
+
* rotated 90°. Returns 0 for empty label lists.
|
|
35
|
+
*/
|
|
36
|
+
declare function estimateRotatedAxisHeight(labels: string[], formatter?: ((d: string | d3.NumberValue) => string) | null): number;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the bottom margin needed for the x-axis, accounting for rotation.
|
|
39
|
+
* Returns the rotated height when rotation will apply and it exceeds
|
|
40
|
+
* `defaultBottom`; otherwise undefined (caller keeps its default).
|
|
41
|
+
*
|
|
42
|
+
* Chart types call this before `createCanvas` so the canvas reserves enough
|
|
43
|
+
* space for rotated labels to render within the SVG bounds.
|
|
44
|
+
*/
|
|
45
|
+
declare function resolveHorizontalAxisBottom(labels: string[], availableWidth: number, options?: {
|
|
46
|
+
labelRotation?: string;
|
|
47
|
+
numberFormat?: string | null;
|
|
48
|
+
labelPosition?: string;
|
|
49
|
+
tickFormat?: ((label: string) => string) | null;
|
|
50
|
+
}, defaultBottom?: number): number | undefined;
|
|
51
|
+
export declare class HorizontalAxisChart extends D3Blueprint<AxisDatum[]> {
|
|
52
|
+
initialize(): void;
|
|
53
|
+
private applyAxis;
|
|
54
|
+
postDraw(): void;
|
|
55
|
+
}
|
|
56
|
+
export declare function renderHorizontalAxis(chartArea: SVGGElement, scale: AnyXScale, height: number, options?: AxisOptions, priorAxisElement?: Element | null): SVGGElement;
|
|
57
|
+
export { thinLabels, buildTickFormatter, detectDates, willRotateLabels, estimateRotatedAxisHeight, resolveHorizontalAxisBottom, wrapLabel, };
|
|
58
|
+
export type { AnyXScale, DateGranularity };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { D3Blueprint } from 'd3-blueprint';
|
|
2
|
+
import { AxisOptions } from '../types';
|
|
3
|
+
import * as d3 from 'd3';
|
|
4
|
+
interface AxisDatum {
|
|
5
|
+
placeholder: true;
|
|
6
|
+
}
|
|
7
|
+
export declare class VerticalAxisChart extends D3Blueprint<AxisDatum[]> {
|
|
8
|
+
initialize(): void;
|
|
9
|
+
postDraw(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function renderVerticalAxis(chartArea: SVGGElement, scale: d3.ScaleLinear<number, number> | d3.ScaleLogarithmic<number, number> | d3.ScaleBand<string>, height: number, options?: AxisOptions, priorAxisElement?: Element | null): SVGGElement;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Margin } from '../types';
|
|
2
|
+
export interface CanvasElements {
|
|
3
|
+
svg: SVGSVGElement;
|
|
4
|
+
chartArea: SVGGElement;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
margin: Margin;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Compute the margin delta between a prior cached margin and the current one.
|
|
11
|
+
* In constrained mode, uses `stableTop` (renderer-only margin, excluding
|
|
12
|
+
* headerH) so the dy doesn't include header height changes. This prevents
|
|
13
|
+
* axes from sliding vertically when the header wraps differently.
|
|
14
|
+
*/
|
|
15
|
+
export declare function computeMarginDelta(priorMargin: Pick<Margin, 'top' | 'left'> | undefined, currentMargin: Margin): {
|
|
16
|
+
dx: number;
|
|
17
|
+
dy: number;
|
|
18
|
+
} | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Estimate the pixel width of the widest tick label for a vertical axis.
|
|
21
|
+
* Uses an offscreen canvas for measurement, falling back to character-count estimation.
|
|
22
|
+
*/
|
|
23
|
+
export declare function estimateVerticalLabelWidth(values: number[], range?: {
|
|
24
|
+
min?: number;
|
|
25
|
+
max?: number;
|
|
26
|
+
}, numberFormat?: string | null, scaleType?: string): number;
|
|
27
|
+
/**
|
|
28
|
+
* Estimate the pixel width of the widest string label (for band/category axes).
|
|
29
|
+
*/
|
|
30
|
+
export declare function estimateCategoryLabelWidth(labels: string[]): number;
|
|
31
|
+
/**
|
|
32
|
+
* Compute margin overrides based on axis label positions.
|
|
33
|
+
* When labels are inside or off, the corresponding margin is removed
|
|
34
|
+
* so the chart area is flush with the container edges.
|
|
35
|
+
* "auto" resolves based on available container width.
|
|
36
|
+
*/
|
|
37
|
+
export declare function labelPositionMargins(containerWidth: number, verticalLabelPosition?: string, horizontalLabelPosition?: string, verticalDirection?: string, verticalLabelWidth?: number, showHorizontalAxis?: boolean): Partial<Margin>;
|
|
38
|
+
/**
|
|
39
|
+
* Return the inner content dimensions of an element (excluding CSS padding).
|
|
40
|
+
*/
|
|
41
|
+
export declare function contentSize(el: HTMLElement): {
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
};
|
|
45
|
+
export declare function createCanvas(body: HTMLElement, margin?: Partial<Margin>): CanvasElements;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Vision Deficiency (CVD) simulation using Brettel/Viénot matrices.
|
|
3
|
+
* Creates SVG `<filter>` elements with `<feColorMatrix>` for live preview,
|
|
4
|
+
* and programmatic simulation for accessibility analysis.
|
|
5
|
+
*/
|
|
6
|
+
export type CvdType = 'protanopia' | 'deuteranopia' | 'tritanopia';
|
|
7
|
+
/**
|
|
8
|
+
* Returns the SVG filter element ID for a given CVD type.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getCvdFilterId(type: CvdType): string;
|
|
11
|
+
/**
|
|
12
|
+
* Creates an SVG `<filter>` element with an `<feColorMatrix>` for the given CVD type.
|
|
13
|
+
* The filter can be applied via CSS `filter: url(#<id>)`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createCvdSvgFilter(type: CvdType): SVGFilterElement;
|
|
16
|
+
/**
|
|
17
|
+
* Simulate how a color appears under a given CVD type.
|
|
18
|
+
* Returns a hex string.
|
|
19
|
+
*/
|
|
20
|
+
export declare function simulateCvdColor(hex: string, type: CvdType): string;
|
|
21
|
+
export interface CvdIssue {
|
|
22
|
+
type: CvdType;
|
|
23
|
+
label: string;
|
|
24
|
+
pairs: Array<{
|
|
25
|
+
a: string;
|
|
26
|
+
b: string;
|
|
27
|
+
deltaE: number;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check an array of colors for distinguishability under each CVD type.
|
|
32
|
+
* Returns issues only for types where at least one pair falls below the threshold.
|
|
33
|
+
*/
|
|
34
|
+
export declare function checkCvdColors(colors: string[]): CvdIssue[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns '#fff' or '#333' — whichever has better contrast against `bg`.
|
|
3
|
+
*/
|
|
4
|
+
export declare function contrastTextColor(bg: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Compute WCAG 2.1 contrast ratio between two colors.
|
|
7
|
+
* Returns a value between 1 and 21.
|
|
8
|
+
*/
|
|
9
|
+
export declare function wcagContrastRatio(fg: string, bg: string): number;
|
|
10
|
+
/**
|
|
11
|
+
* Determine WCAG conformance level from a contrast ratio.
|
|
12
|
+
* AAA ≥ 7, AA ≥ 4.5, otherwise Fail.
|
|
13
|
+
*/
|
|
14
|
+
export declare function wcagLevel(ratio: number): 'AAA' | 'AA' | 'Fail';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the effective background color of an element by walking up the DOM.
|
|
17
|
+
* Falls back to '#fff' when running outside a browser or when nothing is found.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveBackgroundColor(el?: Element | null): string;
|
|
20
|
+
/**
|
|
21
|
+
* Ensures `color` is readable against `bg`.
|
|
22
|
+
* Darkens or lightens the colour until the contrast ratio reaches MIN_CONTRAST.
|
|
23
|
+
* `bg` can be a CSS color string; defaults to '#fff'.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readableColor(color: string, bg?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Adjusts an array of colors so that:
|
|
28
|
+
* 1. Every color is readable against `bg` (WCAG contrast ratio >= 3).
|
|
29
|
+
* 2. Adjacent colors are perceptually distinguishable (deltaE >= 12).
|
|
30
|
+
*
|
|
31
|
+
* Only lightness is changed — hue and saturation are preserved.
|
|
32
|
+
*/
|
|
33
|
+
export declare function adjustColorsForBackground(colors: string[], bg: string): string[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type DateGranularity = 'year' | 'month' | 'day' | 'datetime';
|
|
2
|
+
export declare function parseDate(s: string): Date | null;
|
|
3
|
+
/**
|
|
4
|
+
* Parse a string as a date (returning epoch ms) or as a plain number.
|
|
5
|
+
* Date strings take precedence so that e.g. "2020" becomes epoch ms for
|
|
6
|
+
* Jan 1 2020 rather than the number 2020.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseDateOrNumber(s: string): number | undefined;
|
|
9
|
+
export declare function detectDates(labels: string[]): {
|
|
10
|
+
dates: Date[];
|
|
11
|
+
granularity: DateGranularity;
|
|
12
|
+
} | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ChartType } from '../../enums';
|
|
2
|
+
/**
|
|
3
|
+
* Asserts that a chart type's option default matches the expected value.
|
|
4
|
+
* Failure messages cite the wiki rule for traceability.
|
|
5
|
+
*/
|
|
6
|
+
export declare function expectDefault(chart: ChartType, optionKey: string, expected: unknown, rule: string): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ChartType } from '../../enums';
|
|
2
|
+
export declare const Concern: {
|
|
3
|
+
readonly DirectLabelling: "directLabelling";
|
|
4
|
+
readonly Legend: "legend";
|
|
5
|
+
readonly ValueLabels: "valueLabels";
|
|
6
|
+
readonly AxisLabels: "axisLabels";
|
|
7
|
+
readonly Gridlines: "gridlines";
|
|
8
|
+
readonly Ticks: "ticks";
|
|
9
|
+
readonly AxisLines: "axisLines";
|
|
10
|
+
readonly AxisScaleRange: "axisScaleRange";
|
|
11
|
+
readonly ColorPalette: "colorPalette";
|
|
12
|
+
readonly Crosshair: "crosshair";
|
|
13
|
+
readonly Tooltips: "tooltips";
|
|
14
|
+
readonly LineInterpolation: "lineInterpolation";
|
|
15
|
+
readonly LineSymbols: "lineSymbols";
|
|
16
|
+
readonly BarLayout: "barLayout";
|
|
17
|
+
readonly PieDonutLayout: "pieDonutLayout";
|
|
18
|
+
readonly Stacking: "stacking";
|
|
19
|
+
readonly Sort: "sort";
|
|
20
|
+
readonly RendererConstants: "rendererConstants";
|
|
21
|
+
};
|
|
22
|
+
export type Concern = typeof Concern[keyof typeof Concern];
|
|
23
|
+
export declare const ALL_CONCERNS: readonly Concern[];
|
|
24
|
+
export declare const AUDITED_CHART_TYPES: readonly ChartType[];
|
|
25
|
+
export interface AssertedCell {
|
|
26
|
+
status: 'asserted';
|
|
27
|
+
kind?: never;
|
|
28
|
+
optionKey: string;
|
|
29
|
+
target: unknown;
|
|
30
|
+
rule: string;
|
|
31
|
+
notes?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AssertedRendererCell {
|
|
34
|
+
status: 'asserted';
|
|
35
|
+
kind: 'rendererConstant';
|
|
36
|
+
importPath: string;
|
|
37
|
+
exportName: string;
|
|
38
|
+
target: unknown;
|
|
39
|
+
rule: string;
|
|
40
|
+
}
|
|
41
|
+
export interface TodoCell {
|
|
42
|
+
status: 'todo';
|
|
43
|
+
optionKey: string;
|
|
44
|
+
current: unknown;
|
|
45
|
+
target: unknown;
|
|
46
|
+
rule: string;
|
|
47
|
+
notes?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface NaCell {
|
|
50
|
+
status: 'na';
|
|
51
|
+
reason: string;
|
|
52
|
+
}
|
|
53
|
+
export interface OpenCell {
|
|
54
|
+
status: 'open';
|
|
55
|
+
optionKey?: string;
|
|
56
|
+
current?: unknown;
|
|
57
|
+
notes: string;
|
|
58
|
+
}
|
|
59
|
+
export type Cell = AssertedCell | AssertedRendererCell | TodoCell | NaCell | OpenCell;
|
|
60
|
+
export type ConcernMatrix = Partial<Record<ChartType, Cell>>;
|
|
61
|
+
export type Matrix = Record<Concern, ConcernMatrix>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ParsedNumberFormat {
|
|
2
|
+
prefix: string;
|
|
3
|
+
d3Spec: string;
|
|
4
|
+
suffix: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Fix legacy d3-format specifiers.
|
|
8
|
+
* Converts wrapping parens `(,.0f)` to d3-correct prefix-only `(,.0f`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function safeD3Spec(fmt: string): string;
|
|
11
|
+
/** @deprecated Use safeD3Spec instead */
|
|
12
|
+
export declare const safeFormat: typeof safeD3Spec;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a number format string into its components.
|
|
15
|
+
*
|
|
16
|
+
* Supports two formats:
|
|
17
|
+
* - Plain d3-format: `,.0f`, `(,.2f`
|
|
18
|
+
* - Pipe-delimited with prefix/suffix: `$|,.0f|`, `|,.0f|%`, `$|,.2f|M`
|
|
19
|
+
*
|
|
20
|
+
* Legacy paren format `(,.0f)` is auto-corrected to `(,.0f`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseNumberFormat(fmt: string): ParsedNumberFormat;
|
|
23
|
+
/**
|
|
24
|
+
* Build a tick formatter function from a number format string.
|
|
25
|
+
* Returns null if the format string is empty.
|
|
26
|
+
*
|
|
27
|
+
* Handles prefix/suffix via pipe syntax: `$|,.0f|M` → "$1,234M"
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildNumberFormatter(fmt: string): ((value: number | {
|
|
30
|
+
valueOf(): number;
|
|
31
|
+
}) => string) | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FrameOptions } from '../types';
|
|
2
|
+
export interface FrameElements {
|
|
3
|
+
wrapper: HTMLElement;
|
|
4
|
+
header: HTMLElement;
|
|
5
|
+
body: HTMLElement;
|
|
6
|
+
footer: HTMLElement;
|
|
7
|
+
}
|
|
8
|
+
export declare function createFrame(container: HTMLElement, options?: FrameOptions): FrameElements;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type { ChartData, ChartOptions, ChartRenderer, ChartOptionDef, ChartTypeOptions, ChartTypeOptionKey, LineStyle, ColorizeConfig, HighlightConfig, AxisOptions, FrameOptions, AreaFillConfig, AnnotationConfig, LineSymbolConfig, SeriesOverride, Margin, } from './types';
|
|
2
|
+
export { createFrame } from './frame/frame';
|
|
3
|
+
export type { FrameElements } from './frame/frame';
|
|
4
|
+
export { createCanvas } from './canvas/canvas';
|
|
5
|
+
export type { CanvasElements } from './canvas/canvas';
|
|
6
|
+
export { renderVerticalAxis } from './axis/vertical-axis';
|
|
7
|
+
export { renderHorizontalAxis } from './axis/horizontal-axis';
|
|
8
|
+
export { AxisService } from './axis/axis-service';
|
|
9
|
+
export type { AxisServiceConfig } from './axis/axis-service';
|
|
10
|
+
export { renderLegend } from './legend/legend';
|
|
11
|
+
export { registerChart, getChart, getChartOptions, listCharts } from './registry';
|
|
12
|
+
export { parseData, buildChartOptions } from './chart-helpers';
|
|
13
|
+
export { resolveSeriesColor, isSeriesHidden } from './series-helpers';
|
|
14
|
+
export { computeStack, computeStack100 } from './stack-helpers';
|
|
15
|
+
export { getDefaultTransitionMs, DEFAULT_TRANSITION_MS, snapshotForFadeOut, commitFadeOut, fadeIn } from './motion';
|
|
16
|
+
export { getCachedChart, setCachedChart, clearCachedChart } from './transition-cache';
|
|
17
|
+
export type { CachedChart } from './transition-cache';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function renderLegend(chartArea: SVGGElement, labels: string[], colors?: string[], yOffset?: number, position?: string, anchor?: string, chartWidth?: number, chartHeight?: number, xOffset?: number, valueSuffixes?: string[], frameInset?: {
|
|
2
|
+
left?: number;
|
|
3
|
+
right?: number;
|
|
4
|
+
}): SVGGElement;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LineSymbolConfig } from './types';
|
|
2
|
+
import * as d3 from 'd3';
|
|
3
|
+
export declare function shouldShowSymbol(index: number, total: number, showOn: LineSymbolConfig['showOn']): boolean;
|
|
4
|
+
export declare function renderLineSymbols(parent: d3.Selection<SVGGElement, unknown, null, undefined>, points: {
|
|
5
|
+
cx: number;
|
|
6
|
+
cy: number;
|
|
7
|
+
color: string;
|
|
8
|
+
index: number;
|
|
9
|
+
}[], total: number, config: LineSymbolConfig, transition?: boolean): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns 0 when the user prefers reduced motion, otherwise returns the input duration.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getTransitionDuration(ms: number): number;
|
|
5
|
+
export declare const DEFAULT_TRANSITION_MS = 500;
|
|
6
|
+
/**
|
|
7
|
+
* Call at the start of each render() function to control whether transitions play.
|
|
8
|
+
* Pass `true` for scene transitions, `false` (default) for initial / non-scene renders.
|
|
9
|
+
*/
|
|
10
|
+
export declare function setRenderTransition(enabled: boolean): void;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the current scene transition duration, respecting `prefers-reduced-motion`.
|
|
13
|
+
* Returns 0 when not in a scene transition (i.e. setRenderTransition(false) was last called).
|
|
14
|
+
*/
|
|
15
|
+
export declare function getDefaultTransitionMs(): number;
|
|
16
|
+
/**
|
|
17
|
+
* Reinsert prior elements into a parent, wrapping them in a compensating
|
|
18
|
+
* `<g translate(dx,dy)>` that transitions to identity over the default
|
|
19
|
+
* duration. This corrects for chartArea origin shifts (e.g. when legend
|
|
20
|
+
* toggles change margins) so that prior elements don't visually jump.
|
|
21
|
+
*
|
|
22
|
+
* When dx/dy are both 0, elements are appended directly without a wrapper.
|
|
23
|
+
*/
|
|
24
|
+
export declare function reinsertWithOffset(parent: Element, elements: Element[], dx: number, dy: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* Fade an element in using the Web Animations API.
|
|
27
|
+
* Respects `prefers-reduced-motion` via `getTransitionDuration`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function fadeIn(el: Element, ms?: number): void;
|
|
30
|
+
/**
|
|
31
|
+
* Capture a visual snapshot of the container's current content as a
|
|
32
|
+
* detached overlay element. Call this *before* clearing the container.
|
|
33
|
+
*
|
|
34
|
+
* After the new chart is rendered, append the returned overlay to the
|
|
35
|
+
* container via `commitFadeOut()` — it will sit on top and fade to
|
|
36
|
+
* transparent, then self-remove.
|
|
37
|
+
*
|
|
38
|
+
* Returns `null` when reduced-motion is active or the container is empty.
|
|
39
|
+
*/
|
|
40
|
+
export declare function snapshotForFadeOut(container: HTMLElement, ms?: number): HTMLElement | null;
|
|
41
|
+
/**
|
|
42
|
+
* Append a previously-created fade-out overlay to the container and
|
|
43
|
+
* start its opacity animation. The overlay removes itself on finish.
|
|
44
|
+
*/
|
|
45
|
+
export declare function commitFadeOut(container: HTMLElement, overlay: HTMLElement, ms?: number): void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AnnotationSnapshot } from './snapshots';
|
|
2
|
+
import type * as d3 from 'd3';
|
|
3
|
+
export interface AnnotationContext {
|
|
4
|
+
scaleX: d3.ScaleBand<string> | d3.ScalePoint<string> | d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>;
|
|
5
|
+
scaleY: d3.ScaleLinear<number, number> | d3.ScaleSymLog<number, number>;
|
|
6
|
+
data: {
|
|
7
|
+
label: string;
|
|
8
|
+
value: number;
|
|
9
|
+
}[];
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
backgroundColor?: string;
|
|
13
|
+
orientation?: 'horizontal';
|
|
14
|
+
transition?: boolean;
|
|
15
|
+
/** Pre-computed snapshots of old annotation positions (captured before DOM is cleared). */
|
|
16
|
+
priorAnnotations?: Map<string, AnnotationSnapshot>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CompassDirection } from '../../types';
|
|
2
|
+
export declare const DIRECTION_VECTORS: Record<CompassDirection, {
|
|
3
|
+
dx: number;
|
|
4
|
+
dy: number;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const RECT_ANCHOR: Record<CompassDirection, {
|
|
7
|
+
nx: number;
|
|
8
|
+
ny: number;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function computeDirectionOffset(direction: CompassDirection, distance: number): {
|
|
11
|
+
dx: number;
|
|
12
|
+
dy: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function rotateDirectionForHorizontal(dir: CompassDirection): CompassDirection;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AnnotationConfig } from '../../types';
|
|
2
|
+
import { AnnotationContext } from './context';
|
|
3
|
+
import * as d3 from 'd3';
|
|
4
|
+
export declare function renderFreeAnnotation(g: d3.Selection<SVGGElement, unknown, null, undefined>, ann: AnnotationConfig, ctx: AnnotationContext, index: number): void;
|