@astrato-io/visualizations 0.0.0-stage → 0.6.5
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/CHANGELOG.md +23 -0
- package/LICENSE +93 -0
- package/README.md +843 -2
- package/THIRD_PARTY_NOTICES.md +8477 -0
- package/VISUALIZATION_DEFINITIONS.md +2378 -0
- package/chunks/ClickAwayListener-BbeNMAvj.js +52 -0
- package/chunks/LinearProgress-B1FeWaen.js +253 -0
- package/chunks/accessors-DemrDevR.js +128 -0
- package/chunks/app-filter-bar.compiler-BGJ7HAbr.js +64 -0
- package/chunks/bar.compiler-CT0ZbQKc.js +374 -0
- package/chunks/builder-B6dWSIdD.js +12289 -0
- package/chunks/color-settings-ZIvgNTq1.js +10 -0
- package/chunks/coloring-B1XAfg6b.js +664 -0
- package/chunks/debounce-fn-CUixuz45.js +7 -0
- package/chunks/definitions-D3OVqmXl.js +2102 -0
- package/chunks/escobar-eDjtGpkC.js +34606 -0
- package/chunks/events-WZut5Ow6.js +4 -0
- package/chunks/extend-BKUkc4_i.js +37 -0
- package/chunks/filter.compiler-DBsyRBJt.js +70 -0
- package/chunks/filtering-tqjAyJH5.js +1072 -0
- package/chunks/grouping-type-On4s9Thj.js +3 -0
- package/chunks/handlers-VTBfIZYZ.js +13072 -0
- package/chunks/isEqual-BDxAhUo8.js +7514 -0
- package/chunks/line.compiler-CzdM5Ld0.js +198 -0
- package/chunks/metadata-BGElBy5Z.js +28 -0
- package/chunks/number.compiler-G-R7y16P.js +53 -0
- package/chunks/operations-CTNUX6Sy.js +26249 -0
- package/chunks/range-CiwTbMig.js +22 -0
- package/chunks/registry-CsQQzukD.js +920 -0
- package/chunks/requirements-DYjZCFyf.js +6 -0
- package/chunks/rolldown-runtime-DleVn1XH.js +28 -0
- package/chunks/set-coloring-datafield-B3uIS1Pe.js +8 -0
- package/chunks/shared-CBvcC5YV.js +1218 -0
- package/chunks/src-BOS6SqkZ.js +67 -0
- package/chunks/src-D9XogOrc.js +422 -0
- package/chunks/standalone-0M4HlmDW2.js +3944 -0
- package/chunks/standalone-0ashe9w1.js +411 -0
- package/chunks/standalone-B7jax8wa.js +339 -0
- package/chunks/standalone-BK0VYU-l.js +463 -0
- package/chunks/standalone-BMIbT1b2.js +4619 -0
- package/chunks/standalone-BZV5vOwA.js +6 -0
- package/chunks/standalone-BhDrWj4p.js +1980 -0
- package/chunks/standalone-BtSHCp2U2.js +673 -0
- package/chunks/standalone-BvaKdky9.js +344 -0
- package/chunks/standalone-BwtM31-f.js +2 -0
- package/chunks/standalone-C3gg736V.js +1129 -0
- package/chunks/standalone-CC1VUjO32.js +299 -0
- package/chunks/standalone-C_rYnZ0N.js +741 -0
- package/chunks/standalone-CoLrAxRV.js +13198 -0
- package/chunks/standalone-DC-aUgXC.js +3855 -0
- package/chunks/standalone-DCtRoTWg.js +675 -0
- package/chunks/standalone-DUDFTBqL.js +833 -0
- package/chunks/standalone-DhZkX9Td.js +2 -0
- package/chunks/standalone-DtLElfuM.js +512 -0
- package/chunks/standalone-G9Q4Uczu.js +726 -0
- package/chunks/standalone-JuLF-OoH.js +1762 -0
- package/chunks/standalone-_DeX21JJ.js +383 -0
- package/chunks/standalone-gFhKZh8m.js +179 -0
- package/chunks/standalone-tDNy-SFH.js +281 -0
- package/chunks/standalone-v1oxfU20.js +68 -0
- package/chunks/standalone-vzBY6q0I2.js +140 -0
- package/chunks/stroke-dash-UgMEcCS4.js +6 -0
- package/chunks/table.compiler-tb914oj3.js +222 -0
- package/chunks/typeof-CJDtcySz.js +13 -0
- package/chunks/ui-DQWtv2iM.js +63551 -0
- package/chunks/url-utils-B17gj_mr.js +5501 -0
- package/chunks/useFieldName-BvdcoJRl.js +7 -0
- package/chunks/utils-Bg7K-t6K.js +32379 -0
- package/chunks/view-Bn83C8d9.js +12466 -0
- package/definitions.js +3 -0
- package/docs/operations/astrato-app-filter-bar.md +161 -0
- package/docs/operations/bar.md +6968 -0
- package/docs/operations/combo.md +5804 -0
- package/docs/operations/date-picker.md +644 -0
- package/docs/operations/distribution-gauge.md +3082 -0
- package/docs/operations/dot.md +5570 -0
- package/docs/operations/filter.md +1483 -0
- package/docs/operations/gauge.md +3316 -0
- package/docs/operations/heatMap.md +5944 -0
- package/docs/operations/histogram.md +1856 -0
- package/docs/operations/iframe.md +56 -0
- package/docs/operations/image.md +177 -0
- package/docs/operations/index.md +46 -0
- package/docs/operations/line.md +6391 -0
- package/docs/operations/number.md +3903 -0
- package/docs/operations/pie.md +5956 -0
- package/docs/operations/radar.md +4566 -0
- package/docs/operations/sankey.md +3088 -0
- package/docs/operations/scatter.md +5969 -0
- package/docs/operations/shape.md +315 -0
- package/docs/operations/simpleTextObject.md +699 -0
- package/docs/operations/slider.md +220 -0
- package/docs/operations/table.md +8800 -0
- package/docs/operations/tree.md +2867 -0
- package/docs/operations/treemap.md +3527 -0
- package/docs/operations/waterfall.md +2928 -0
- package/docs/operations/word-cloud.md +3000 -0
- package/getters.js +18 -0
- package/index.js +1183 -0
- package/metadata.js +20 -0
- package/operations.js +64 -0
- package/package.json +185 -4
- package/src/definitions/index.d.ts +2 -0
- package/src/definitions/model/definitions/available-fields.d.ts +35 -0
- package/src/definitions/model/definitions/compilers/compile.d.ts +7 -0
- package/src/definitions/model/definitions/data-item-resolution.d.ts +19 -0
- package/src/definitions/model/definitions/descriptors/descriptor-metadata.d.ts +1341 -0
- package/src/definitions/model/definitions/descriptors/json-schema.d.ts +2 -0
- package/src/definitions/model/definitions/diagnostics.d.ts +5 -0
- package/src/definitions/model/definitions/field-suggestions.d.ts +2 -0
- package/src/definitions/model/definitions/index.d.ts +23 -0
- package/src/definitions/model/definitions/registry/compile.d.ts +2 -0
- package/src/definitions/model/definitions/registry/descriptor-registry.d.ts +3 -0
- package/src/definitions/model/definitions/schema-registry.d.ts +660 -0
- package/src/definitions/model/definitions/schemas/app-filter-bar.schema.d.ts +22 -0
- package/src/definitions/model/definitions/schemas/bar.schema.d.ts +73 -0
- package/src/definitions/model/definitions/schemas/broad-chart.schema.d.ts +68 -0
- package/src/definitions/model/definitions/schemas/common.schema.d.ts +303 -0
- package/src/definitions/model/definitions/schemas/filter.schema.d.ts +22 -0
- package/src/definitions/model/definitions/schemas/index.d.ts +9 -0
- package/src/definitions/model/definitions/schemas/line.schema.d.ts +72 -0
- package/src/definitions/model/definitions/schemas/number.schema.d.ts +21 -0
- package/src/definitions/model/definitions/schemas/object.schema.d.ts +215 -0
- package/src/definitions/model/definitions/schemas/table.schema.d.ts +458 -0
- package/src/definitions/model/definitions/types/compilation.types.d.ts +36 -0
- package/src/definitions/model/definitions/types/definition.types.d.ts +2 -0
- package/src/definitions/model/definitions/types/descriptor.types.d.ts +39 -0
- package/src/definitions/model/definitions/types/index.d.ts +3 -0
- package/src/definitions/model/definitions/validation.d.ts +3 -0
- package/src/getters/index.d.ts +30 -0
- package/src/index.d.ts +4 -0
- package/src/metadata/index.d.ts +4 -0
- package/src/operations/index.d.ts +30 -0
- package/src/registry/index.d.ts +6 -0
- package/src/runtime/index.d.ts +2 -0
- package/src/types.d.ts +307 -0
- package/src/visualization-catalog.d.ts +82 -0
- package/src/web-components/index.d.ts +12 -0
- package/styles.css +2 -0
package/README.md
CHANGED
|
@@ -1,3 +1,844 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @astrato-io/visualizations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-neutral browser package for rendering Astrato visualizations in custom applications.
|
|
4
|
+
|
|
5
|
+
The package provides a visualization registry, runtime-owned instances, web components, direct mounting, vSpec operations and getters, metadata discovery, and lazy-loaded visualization implementations. Platform access is provided by `@astrato-io/sdk`.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @astrato-io/sdk @astrato-io/visualizations
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
RxJS and Zod are installed as runtime dependencies.
|
|
14
|
+
|
|
15
|
+
Import the package stylesheet once in the application:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import '@astrato-io/visualizations/styles.css';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Supported Visualizations
|
|
22
|
+
|
|
23
|
+
Use these exact visualization IDs:
|
|
24
|
+
|
|
25
|
+
| ID | Family |
|
|
26
|
+
| ------------------------ | ------ |
|
|
27
|
+
| `bar` | Chart |
|
|
28
|
+
| `combo` | Chart |
|
|
29
|
+
| `distribution-gauge` | Chart |
|
|
30
|
+
| `dot` | Chart |
|
|
31
|
+
| `gauge` | Chart |
|
|
32
|
+
| `heatMap` | Chart |
|
|
33
|
+
| `histogram` | Chart |
|
|
34
|
+
| `line` | Chart |
|
|
35
|
+
| `pie` | Chart |
|
|
36
|
+
| `radar` | Chart |
|
|
37
|
+
| `sankey` | Chart |
|
|
38
|
+
| `scatter` | Chart |
|
|
39
|
+
| `table` | Chart |
|
|
40
|
+
| `tree` | Chart |
|
|
41
|
+
| `treemap` | Chart |
|
|
42
|
+
| `waterfall` | Chart |
|
|
43
|
+
| `word-cloud` | Chart |
|
|
44
|
+
| `date-picker` | Filter |
|
|
45
|
+
| `astrato-app-filter-bar` | Filter |
|
|
46
|
+
| `filter` | Filter |
|
|
47
|
+
| `slider` | Filter |
|
|
48
|
+
| `iframe` | Object |
|
|
49
|
+
| `image` | Object |
|
|
50
|
+
| `number` | Object |
|
|
51
|
+
| `shape` | Object |
|
|
52
|
+
| `simpleTextObject` | Object |
|
|
53
|
+
|
|
54
|
+
Astrato-specific panels are not part of this package.
|
|
55
|
+
|
|
56
|
+
Implementations are loaded lazily when an instance is mounted.
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
Create one SDK client and one visualization runtime for the host application:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { createAstratoClient } from '@astrato-io/sdk';
|
|
64
|
+
import { createVisualizationRuntime, registerAstratoElements, registry } from '@astrato-io/visualizations';
|
|
65
|
+
import '@astrato-io/visualizations/styles.css';
|
|
66
|
+
|
|
67
|
+
const client = createAstratoClient({
|
|
68
|
+
baseUrl: 'https://your-astrato-instance.example/',
|
|
69
|
+
tenantId: 'tenant-id',
|
|
70
|
+
auth: { token: 'personal-access-token' },
|
|
71
|
+
visualizationEngine: true,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const runtime = createVisualizationRuntime({
|
|
75
|
+
client,
|
|
76
|
+
registry,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
runtime.createInstance({
|
|
80
|
+
id: 'sales-by-manufacturer',
|
|
81
|
+
type: 'bar',
|
|
82
|
+
groupId: 'dashboard',
|
|
83
|
+
dataBinding: {
|
|
84
|
+
tenantId: 'tenant-id',
|
|
85
|
+
semanticLayerId: 'semantic-layer-id',
|
|
86
|
+
datasourceType: 'snowflake',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
registerAstratoElements({ runtime });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add the visualization to the page:
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<astrato-visualization instance-id="sales-by-manufacturer"></astrato-visualization>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Every mount container must have non-zero dimensions. The visualization measures its own element and fills the available space:
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
astrato-visualization {
|
|
103
|
+
display: block;
|
|
104
|
+
width: 100%;
|
|
105
|
+
height: 400px;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## App Filter Bar
|
|
110
|
+
|
|
111
|
+
`astrato-app-filter-bar` provides filter chips and editors for applications using the standalone library. It has its own vSpec and no property panel. The existing Astrato `filter-pane` object is unchanged.
|
|
112
|
+
|
|
113
|
+
Create it in the same selection group and with the same data binding as the charts it controls:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
const chart = runtime.getInstance('sales-by-manufacturer');
|
|
117
|
+
runtime.createInstance({
|
|
118
|
+
id: 'dashboard-filters',
|
|
119
|
+
type: 'astrato-app-filter-bar',
|
|
120
|
+
groupId: chart.groupId,
|
|
121
|
+
dataBinding: chart.dataBinding,
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<astrato-visualization class="app-filters" instance-id="dashboard-filters"></astrato-visualization>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
.app-filters {
|
|
131
|
+
display: block;
|
|
132
|
+
width: 100%;
|
|
133
|
+
height: auto;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The bar reads applied and pending filters from the selection service, including selections made by other charts. **New filter** searches engine field metadata. Empty new filters stay local until values are chosen. Manual edits show **Apply** and **Cancel**; auto edits apply immediately. **Clear all** clears the entire selection group, including filters outside the list of fields allowed for creation. Locking and single-select policies remain owned by the selection service.
|
|
138
|
+
|
|
139
|
+
This object is standalone-only: it has no Astrato workbook registration, property panel, Actions manifests, or `build-astrato` target. Its operations and getters are available through the standalone API and AI metadata. The private `@astrato/objects-app-filter-bar` source workspace can be versioned by Changesets, but is distributed through `@astrato-io/visualizations`, not published as an Astrato component.
|
|
140
|
+
|
|
141
|
+
Settings live in `vSpec.appFilterBarSettings` and are also available through [operations and getters](./docs/operations/astrato-app-filter-bar.md):
|
|
142
|
+
|
|
143
|
+
| Setting | Default | Meaning |
|
|
144
|
+
| ------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
145
|
+
| `overflow` | `"wrap"` | Wrap chips, collapse behind **+N**, use a **Filters (N)** modal button, or switch responsively between these modes. |
|
|
146
|
+
| `orientation` | `horizontal` | Horizontal bar or vertical sidebar with stacked filter rows. |
|
|
147
|
+
| `selectionMode` | `"inherit"` | `inherit`, `auto`, or `manual`. A bar override affects only edits made by that bar; it does not change the host service's mode. |
|
|
148
|
+
| `enableAddingNewFilters` | `true` | Show the field picker. |
|
|
149
|
+
| `enableAssociativeFilter` | `true` | Allow associative filter creation when the runtime supports it and eligible fields exist. Set `false` to hide creation. |
|
|
150
|
+
| `showClearAll` | `true` | Show the group-wide clear action. |
|
|
151
|
+
| `showChartBreakdown` | `false` | Opt in to **Chart breakdown** for apps using dimension groups. Only shown when a group has at least two available fields. |
|
|
152
|
+
| `selectableFieldKeys` | unrestricted | Limit fields available for creating filters. Omitted or empty means all fields; existing selections are always visible. |
|
|
153
|
+
|
|
154
|
+
The bar supports value lists with search and paging, available and excluded values, text matching, numeric and date ranges, relative date periods, associative conditions, and dimension group switching. It uses the engine's configured time zone for timestamp editing. The value editor keeps search, sort, and the selection count above its scrollable list. **Select all** affects loaded values; **Actions** exposes deselect, invert, select available, and clear. Pending selections can be applied or cancelled from the bar or the editor footer.
|
|
155
|
+
|
|
156
|
+
Host integration requires the existing synchronous field metadata getters (or `dataBinding.fieldMetadata`), `engine.getData` or `data.query`, and selection services including `getSelection`, `setNewSelectionState`, pending apply/cancel, and clear-all. Provide the selection change observable so changes made elsewhere appear immediately. `getSelectionMode(groupId)` or the host's `selectionMode` supplies inherited behavior; the standalone adapter defaults to manual when neither is provided. Field locking is offered when `toggleFieldLocked` or `setFieldLocked` is available.
|
|
157
|
+
|
|
158
|
+
Associative filter creation requires an explicit `hostServices.engine.capabilities.associativeFiltering: true`. This capability defaults to `false`; advertise it only when the host integration supports both association discovery and executing associative selections. A discovery method's presence, ordinary field connectivity, or `enableAssociativeFilter: true` alone does not establish support. The app setting can disable creation but cannot override missing runtime support.
|
|
159
|
+
|
|
160
|
+
When an enabled field picker opens, the bar discovers eligible targets using `hostServices.engine.getAssociatedViews(fieldKey, dataBinding)`. Otherwise the adapter reads `viewStates` from a one-row engine query, using `alfStatus` or compatibility flags. Hosts that omit this query metadata must supply the explicit discovery method before opting in. Discovery checks at most four fields concurrently, stops scheduling when the picker closes, and retries on the next opening. The option appears only if a target has an associated view containing an allowed condition field; empty or failed lookups never make a target eligible. No discovery runs on mount or when the feature is disabled or unsupported.
|
|
161
|
+
|
|
162
|
+
Existing associative chips remain visible and removable (subject to locking and single-select policies). Disabling creation does not prevent editing existing filters on a capable host. Without runtime support, opening a chip explains that editing is unavailable instead of launching a broken editor.
|
|
163
|
+
|
|
164
|
+
Dimension group changes are shared with mounted visualizations in the same runtime group and retained for later mounts. Apps that use those groups can expose **Chart breakdown** with `settings.showChartBreakdown: true` in their visualization definition, or the `setAppFilterBarChartBreakdownEnabled` operation. The control is hidden by default and when no group offers multiple available fields.
|
|
165
|
+
|
|
166
|
+
### Wrapping Above the Charts
|
|
167
|
+
|
|
168
|
+
In `"wrap"` mode, put the bar in an auto-height section above the chart area. Extra chip rows increase the section height and move the charts down. The app owns the mount container and surrounding layout; a fixed-height or absolutely positioned header cannot grow with the bar.
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<section class="dashboard-filter-section">
|
|
172
|
+
<astrato-visualization class="app-filters" instance-id="dashboard-filters"></astrato-visualization>
|
|
173
|
+
</section>
|
|
174
|
+
<section class="dashboard-charts">…</section>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
.dashboard-filter-section {
|
|
179
|
+
position: static;
|
|
180
|
+
flex: 0 0 auto;
|
|
181
|
+
}
|
|
182
|
+
.dashboard-filter-section .app-filters {
|
|
183
|
+
display: block;
|
|
184
|
+
width: 100%;
|
|
185
|
+
height: auto;
|
|
186
|
+
}
|
|
187
|
+
.dashboard-charts {
|
|
188
|
+
margin-top: 12px;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Place the filter section and charts in normal document flow. Apps switching overflow modes should also switch the mount container between `height: auto` for wrap and the configured fixed height for collapse or button.
|
|
193
|
+
|
|
194
|
+
### Header Overflow
|
|
195
|
+
|
|
196
|
+
For a fixed-height header, use the `setAppFilterBarOverflow` operation with payload `"collapse"`. `getAppFilterBarOverflow` returns the configured mode. The default `"wrap"` preserves existing layouts. Set the mode through the standalone operations API after creating the instance; the visualization definition's settings retain their existing fields.
|
|
197
|
+
|
|
198
|
+
Collapse mode displays as many chips as fit, then **+N** for the hidden filters. Clicking **+N** opens a scrollable list of all filters, where each can be edited or removed under the same lock and single-select policies. Editors opened from that list offer **All filters** to return. Apply and Cancel work from the bar, list, or editor. Pending hidden filters give **+N** a dashed border and badge, with an accessible pending-changes label. The popover traps Tab focus, Escape closes it, and closing restores focus to the trigger (or a visible bar control if the trigger disappeared).
|
|
199
|
+
|
|
200
|
+
`"collapse"` keeps the action buttons on the row and uses `--afb-height` as the fixed bar height. For a 40px header:
|
|
201
|
+
|
|
202
|
+
```css
|
|
203
|
+
.app-filters {
|
|
204
|
+
display: block;
|
|
205
|
+
width: 100%;
|
|
206
|
+
height: 40px;
|
|
207
|
+
--afb-height: 40px;
|
|
208
|
+
--afb-padding: 3px 8px;
|
|
209
|
+
--afb-control-height: 32px;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Allow enough header width for New filter, optional Chart breakdown, the action buttons, and **+N**; disabling optional controls can help compact headers. Vertical orientation keeps stacked rows for wrap and collapse. The button mode applies in both orientations.
|
|
214
|
+
|
|
215
|
+
Use payload `"button"` for a fully collapsed **Filters (N)** control. The control fills the available width, with no surrounding well, border, or padding. It opens the complete filter bar in a native modal with a stacked list, New filter, optional Chart breakdown, and Apply / Cancel / Clear all. Pending selections are indicated on the button. The modal makes the rest of the page inert, traps keyboard focus, closes on Escape or a backdrop click, and restores focus to the button. Editors open inside the modal's top layer; closing an editor returns to the expanded bar. This mode also works with no selections so users can add their first filter.
|
|
216
|
+
|
|
217
|
+
Use payload `"collapse-button"` to show the single row with **+N** at wider widths and the **Filters (N)** button below 480px. Use `"wrap-collapse-button"` to wrap at 960px and above, collapse from 480px to below 960px, and show the button below 480px. These modes use the filter bar's width, rather than the viewport. Override `--afb-button-breakpoint: 480px` and `--afb-collapse-breakpoint: 960px` on the host to customize the transitions. Keep the mount container at `height: auto` for responsive modes so wrapping pushes the charts down. Responsive modes apply to horizontal bars; vertical bars retain their stacked layout. Resizing out of button mode closes the modal.
|
|
218
|
+
|
|
219
|
+
The new controls share the existing button hover, keyboard focus, disabled, chip pending, locked, and excluded styles. The modal and overflow popover inherit the popup surface, border, radius, padding, shadow, font, and text tokens. The list leaves space for focus rings; all scrolling overflow surfaces use thin, theme-colored scrollbars and contain scrolling at their boundaries. The pending badge follows the inline end in either text direction and uses system colors in forced-color mode.
|
|
220
|
+
|
|
221
|
+
| Token | Default / fallback | Applies to |
|
|
222
|
+
| ----------------------------- | ------------------------------------------------------- | -------------------------------------------- |
|
|
223
|
+
| `--afb-overflow-surface` | `--afb-chip-surface`, `#f4f4f5` | **+N** and **Filters (N)** backgrounds |
|
|
224
|
+
| `--afb-overflow-text` | `--afb-text`, `#27272a` | Control text and icons |
|
|
225
|
+
| `--afb-overflow-border` | `--afb-chip-border`, `#e4e4e7` | Control borders |
|
|
226
|
+
| `--afb-overflow-radius` | `--afb-chip-radius`, `8px` | Control corners |
|
|
227
|
+
| `--afb-overflow-hover` | `--afb-hover`, `#f4f4f5` | Hovered controls |
|
|
228
|
+
| `--afb-overflow-open-surface` | `--afb-selected-surface`, then `--afb-hover`, `#f4f4f5` | Controls with an open list or modal |
|
|
229
|
+
| `--afb-overflow-badge-size` | `6px` | Pending badge; color uses `--afb-pending` |
|
|
230
|
+
| `--afb-overflow-list-height` | `--afb-list-height`, `260px` | Scrolling filter list |
|
|
231
|
+
| `--afb-modal-width` | `560px` | Modal width, constrained to the viewport |
|
|
232
|
+
| `--afb-modal-backdrop` | `#0006` | Modal backdrop |
|
|
233
|
+
| `--afb-scrollbar-thumb` | `--afb-border`, `#e4e4e7` | Overflow list, popover, and modal scrollbars |
|
|
234
|
+
| `--afb-scrollbar-track` | `transparent` | Scrolling surface tracks |
|
|
235
|
+
| `--afb-button-breakpoint` | `480px` | Responsive transition to button |
|
|
236
|
+
| `--afb-collapse-breakpoint` | `960px` | Responsive transition from wrap to collapse |
|
|
237
|
+
|
|
238
|
+
The full-width button has the stable `__trigger` class and its own optional overrides. `--afb-trigger-surface`, `--afb-trigger-text`, `--afb-trigger-border`, `--afb-trigger-radius`, `--afb-trigger-hover`, and `--afb-trigger-open-surface` fall back to their corresponding overflow tokens. Size and layout use `--afb-trigger-height` (falls back to `--afb-height`, 48px), `--afb-trigger-padding` (falls back to `--afb-button-padding`, `5px 10px`), `--afb-trigger-align` (`center`), `--afb-trigger-gap` (`6px`), `--afb-trigger-font-weight` (`500`), `--afb-trigger-border-width` (`1px`), and `--afb-trigger-shadow` (`none`). These apply to explicit button mode and the button phase of responsive modes. Pending borders and badges still use `--afb-pending`.
|
|
239
|
+
|
|
240
|
+
```css
|
|
241
|
+
.app-filter-host {
|
|
242
|
+
--afb-trigger-surface: #2563eb;
|
|
243
|
+
--afb-trigger-text: #fff;
|
|
244
|
+
--afb-trigger-hover: #1d4ed8;
|
|
245
|
+
--afb-trigger-open-surface: #1e40af;
|
|
246
|
+
--afb-trigger-border: #2563eb;
|
|
247
|
+
--afb-trigger-radius: 8px;
|
|
248
|
+
--afb-trigger-height: 40px;
|
|
249
|
+
--afb-trigger-padding: 8px 16px;
|
|
250
|
+
--afb-trigger-align: flex-start;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Use the stable `__overflow`, `__overflow-popover`, `__overflow-list`, and `__modal` classes for structural overrides. `[data-overflow="wrap"]`, `[data-overflow="collapse"]`, and `[data-overflow="button"]` reflect the currently rendered mode, including responsive transitions.
|
|
255
|
+
|
|
256
|
+
### Vertical Sidebar
|
|
257
|
+
|
|
258
|
+
Set `settings.orientation` to `"vertical"` in the visualization definition (or use `setAppFilterBarOrientation` at runtime):
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"version": 1,
|
|
263
|
+
"type": "astrato-app-filter-bar",
|
|
264
|
+
"settings": { "orientation": "vertical", "selectionMode": "manual" }
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Give the host a sidebar width and let its height follow its contents, for example `width: 280px; max-width: 100%; height: auto`. Filters become full-width rows with their values below the field name. Editors open to the right, flip left when necessary, and fall back above or below on narrow screens. Apply, Cancel, Clear all, and the selection group behave identically in both orientations. Horizontal remains the default for existing definitions.
|
|
269
|
+
|
|
270
|
+
Both layouts use the same styling tokens. Target `[data-orientation="vertical"]` for sidebar-specific overrides, and use `--afb-vertical-chip-padding` (9px 10px) to adjust row spacing. The stable `__chip-summary` class styles the value preview.
|
|
271
|
+
|
|
272
|
+
### Styling the Bar and Its Editors
|
|
273
|
+
|
|
274
|
+
The bar uses neutral defaults and inherits CSS custom properties from its mount container. Popups keep their DOM ancestry while using the browser's top layer, so the same tokens apply to editors. Styles do not depend on generated Emotion class names.
|
|
275
|
+
|
|
276
|
+
```css
|
|
277
|
+
.app-filters {
|
|
278
|
+
--afb-font-family: Inter, system-ui, sans-serif;
|
|
279
|
+
--afb-font-size: 13px;
|
|
280
|
+
--afb-surface: #ffffff;
|
|
281
|
+
--afb-text: #172554;
|
|
282
|
+
--afb-muted: #64748b;
|
|
283
|
+
--afb-border: #dbeafe;
|
|
284
|
+
--afb-accent: #2563eb;
|
|
285
|
+
--afb-on-accent: #ffffff;
|
|
286
|
+
--afb-focus: #60a5fa;
|
|
287
|
+
--afb-chip-surface: #eff6ff;
|
|
288
|
+
--afb-chip-border: #bfdbfe;
|
|
289
|
+
--afb-radius: 12px;
|
|
290
|
+
--afb-control-radius: 8px;
|
|
291
|
+
--afb-popup-width: 400px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.dark-app .app-filters {
|
|
295
|
+
--afb-surface: #18181b;
|
|
296
|
+
--afb-popup-surface: #27272a;
|
|
297
|
+
--afb-control-surface: #27272a;
|
|
298
|
+
--afb-text: #fafafa;
|
|
299
|
+
--afb-muted: #a1a1aa;
|
|
300
|
+
--afb-border: #3f3f46;
|
|
301
|
+
--afb-hover: #3f3f46;
|
|
302
|
+
--afb-chip-surface: #27272a;
|
|
303
|
+
--afb-chip-border: #52525b;
|
|
304
|
+
--afb-selected-surface: #3f3f46;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Additional tokens include `--afb-padding`, `--afb-gap`, `--afb-height`, `--afb-border-width`, `--afb-control-height`, `--afb-button-padding`, `--afb-chip-radius`, `--afb-chip-max-width`, `--afb-pending`, `--afb-excluded`, `--afb-error`, `--afb-popup-padding`, `--afb-popup-radius`, `--afb-popup-shadow`, `--afb-list-height`, and `--afb-z-index` (fallback for browsers without the Popover API).
|
|
309
|
+
|
|
310
|
+
Primary buttons darken the accent background by 10% on hover, keeping their text color unchanged. Override `--afb-accent-hover` to provide a custom hover background.
|
|
311
|
+
|
|
312
|
+
The field picker uses compact rows with the source view beside the field name. Its defaults are a 340px popup, 12px padding, and a 224px scrolling list; the existing popup and list tokens override these. Use `--afb-field-row-height` (36px) and `--afb-field-icon-size` (24px) to adjust field density. The stable `__field-picker` and `__field-label` classes allow targeted layout overrides; full names remain available to assistive technology and on hover when truncated.
|
|
313
|
+
|
|
314
|
+
The value editor has a direct mode button: click the list icon to switch to text matching, and the text icon to return to values. Numeric and date fields cycle through their additional range mode. The icon indicates the current mode; its tooltip and accessible label also name the next mode. Search or text matching shares a compact row with the mode button and Exclude, while sorting sits beside the selection actions. Target the stable `__mode-toggle`, `__mode-label`, and `__text-query` classes to customize this toolbar. The secondary Actions menu retains `--afb-menu-width` (220px) and the `__menu-label` class.
|
|
315
|
+
|
|
316
|
+
The values area reserves `--afb-list-height` (260px) through loading, results, and empty states. Values load in pages of 100, with the next page requested automatically within 120px of the bottom. Existing rows remain selectable during pagination, with a small spinner at the bottom; failed page requests offer a retry without discarding loaded values. Search is debounced by 300ms and resets pagination, as do sorting and changes to the applied connected-filter context. "Select all" selects the currently loaded values.
|
|
317
|
+
|
|
318
|
+
A centered spinner keeps existing rows visible but disabled during full refreshes. Loading indicators announce progress to screen readers and respect reduced motion. Customize them with `--afb-spinner-size` (16px), `--afb-spinner-color` (defaults to the muted text color), or the stable `__loader`, `__spinner`, and `__next-page` classes.
|
|
319
|
+
|
|
320
|
+
For structural overrides, use `.astrato-app-filter-bar` and its stable `__chips`, `__chip`, `__chip-label`, `__actions`, `__button`, `__input`, `__select`, `__popover`, `__popover-header`, `__heading`, `__heading-icon`, `__editor`, `__editor-options`, `__editor-footer`, `__search`, `__search-row`, `__selection-toolbar`, `__menu`, `__menu-items`, `__field-option`, `__field-icon`, `__field-name`, `__value-list`, `__toolbar`, `__row`, `__field`, `__values`, `__value`, `__group`, `__muted`, and `__error` classes. Buttons expose `data-variant="ghost"`, `data-icon-only`, and `data-primary` for appearance overrides; icons inherit the text color. Chips expose `data-pending`, `data-excluded`, and `data-locked`; value rows expose `data-selected` and `data-excluded`.
|
|
321
|
+
|
|
322
|
+
## Visualization Instances
|
|
323
|
+
|
|
324
|
+
The runtime owns visualization configuration and lifecycle. A `VisualizationInstance` contains:
|
|
325
|
+
|
|
326
|
+
| Property | Purpose |
|
|
327
|
+
| ------------- | ------------------------------------------------------------- |
|
|
328
|
+
| `id` | Stable runtime identifier |
|
|
329
|
+
| `type` | Visualization ID from the registry |
|
|
330
|
+
| `vSpec` | Visualization configuration |
|
|
331
|
+
| `preset` | Optional preset used during initialization |
|
|
332
|
+
| `groupId` | Selection and filter interaction scope |
|
|
333
|
+
| `dataBinding` | Astrato tenant, semantic layer, datasource, and query context |
|
|
334
|
+
|
|
335
|
+
If `vSpec` is omitted, the runtime creates a fresh default vSpec for the selected type. Requirement metadata is advisory: an empty visualization can mount before dimensions or measures are configured.
|
|
336
|
+
|
|
337
|
+
The runtime exposes:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
runtime.createInstance(instance);
|
|
341
|
+
runtime.updateInstance(instanceId, update);
|
|
342
|
+
runtime.getInstance(instanceId);
|
|
343
|
+
runtime.listInstances();
|
|
344
|
+
runtime.removeInstance(instanceId);
|
|
345
|
+
runtime.validateInstanceRequirements(instanceId);
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Creating A Configured Visualization
|
|
349
|
+
|
|
350
|
+
Use a `VisualizationDefinition` to create the initial vSpec from exact engine `fieldKey` values. Each supported type has
|
|
351
|
+
a strict schema; see the [Visualization Definition Reference](./VISUALIZATION_DEFINITIONS.md) for its fields,
|
|
352
|
+
constraints, and example. The Markdown reference is also available through the package export
|
|
353
|
+
`@astrato-io/visualizations/VISUALIZATION_DEFINITIONS.md`.
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
import {
|
|
357
|
+
compileVisualizationDefinition,
|
|
358
|
+
createVisualizationAvailableFields,
|
|
359
|
+
type VisualizationDefinition,
|
|
360
|
+
} from '@astrato-io/visualizations/definitions';
|
|
361
|
+
import { registry } from '@astrato-io/visualizations';
|
|
362
|
+
|
|
363
|
+
const metadata = await client.hostServices.engine.fields.getFieldMetadata?.({
|
|
364
|
+
tenantId: 'tenant-id',
|
|
365
|
+
semanticLayerId: 'semantic-layer-id',
|
|
366
|
+
datasourceType: 'snowflake',
|
|
367
|
+
});
|
|
368
|
+
const availableFields = createVisualizationAvailableFields(metadata ?? {});
|
|
369
|
+
|
|
370
|
+
const definition: Extract<VisualizationDefinition, { type: 'bar' }> = {
|
|
371
|
+
version: 1,
|
|
372
|
+
type: 'bar',
|
|
373
|
+
data: {
|
|
374
|
+
dimensions: [{ ref: 'manufacturer', fieldKey: '[Cars].[Manufacturer]' }],
|
|
375
|
+
measures: [
|
|
376
|
+
{
|
|
377
|
+
ref: 'sales',
|
|
378
|
+
fieldKey: '[Cars].[Sales In Thousands]',
|
|
379
|
+
aggregation: 'SUM',
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
sorting: [{ by: 'sales', direction: 'desc' }],
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const compilation = await compileVisualizationDefinition({
|
|
387
|
+
definition,
|
|
388
|
+
availableFields,
|
|
389
|
+
baseVSpec: registry.bar.createDefaultVSpec(),
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
if (!compilation.success) {
|
|
393
|
+
throw new Error(JSON.stringify(compilation.issues));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
runtime.createInstance({
|
|
397
|
+
id: 'sales-by-manufacturer',
|
|
398
|
+
type: 'bar',
|
|
399
|
+
vSpec: compilation.vSpec,
|
|
400
|
+
dataBinding: {
|
|
401
|
+
tenantId: 'tenant-id',
|
|
402
|
+
semanticLayerId: 'semantic-layer-id',
|
|
403
|
+
datasourceType: 'snowflake',
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Compilation requires a fresh default or preset vSpec and returns either a complete vSpec or structured issues. The
|
|
409
|
+
caller must supply fields compatible with the current semantic-layer context. Raw fields used as measures require an
|
|
410
|
+
aggregation; semantic measures and calculations keep their engine-defined behavior.
|
|
411
|
+
|
|
412
|
+
Use `getVisualizationDefinitionDescriptor(type)` for the selected type's JSON Schema, documentation, examples, and
|
|
413
|
+
feature metadata. `listVisualizationDefinitionDescriptors()` returns discovery metadata for all supported types. AI
|
|
414
|
+
integrations should give the selected descriptor and compatible field catalog to the model, compile its response, and
|
|
415
|
+
return structured issues for correction.
|
|
416
|
+
|
|
417
|
+
A definition covers a subset of each type's operations. To set anything else, apply operations to `compilation.vSpec`
|
|
418
|
+
with `applyOperations` in one batch before calling `createInstance`; see
|
|
419
|
+
[Transforming A vSpec Without A Runtime](#transforming-a-vspec-without-a-runtime). Do not finish a chart by applying
|
|
420
|
+
operations one at a time after it is mounted: each vSpec change on a mounted instance can trigger a new data request.
|
|
421
|
+
|
|
422
|
+
VSpec-only instance updates are applied to connected elements in place. Changes to the visualization type, preset,
|
|
423
|
+
selection group, or data binding remount connected web components. Removing an instance unmounts it and discards its
|
|
424
|
+
in-memory state.
|
|
425
|
+
|
|
426
|
+
## Web Components
|
|
427
|
+
|
|
428
|
+
`registerAstratoElements()` registers `astrato-visualization` by default. Registration is idempotent for a given custom-element registry.
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
registerAstratoElements({ runtime });
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
A custom tag name can be used when required by the host application:
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
registerAstratoElements({
|
|
438
|
+
runtime,
|
|
439
|
+
tagName: 'customer-visualization',
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
The element can also receive a runtime and instance ID through JavaScript:
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
import type { AstratoVisualizationElement } from '@astrato-io/visualizations';
|
|
447
|
+
|
|
448
|
+
const element = document.createElement('astrato-visualization') as AstratoVisualizationElement;
|
|
449
|
+
|
|
450
|
+
element.runtime = runtime;
|
|
451
|
+
element.instanceId = 'sales-by-manufacturer';
|
|
452
|
+
container.appendChild(element);
|
|
453
|
+
|
|
454
|
+
const renderResult = await element.ready;
|
|
455
|
+
console.log(renderResult?.status);
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
The element mounts when connected, applies vSpec-only runtime changes in place, remounts when `instance-id` or
|
|
459
|
+
structural runtime instance state changes, and unmounts when disconnected.
|
|
460
|
+
`element.ready` uses the same render deadline as direct mounting: it resolves to `rendered`, `error`, `unmounted`, or
|
|
461
|
+
`timeout`.
|
|
462
|
+
|
|
463
|
+
## Direct Mounting
|
|
464
|
+
|
|
465
|
+
Applications that own DOM lifecycle directly can mount without the public web component:
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
const container = document.getElementById('chart-slot');
|
|
469
|
+
|
|
470
|
+
if (!container) {
|
|
471
|
+
throw new Error('Missing chart container.');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const handle = await runtime.mount(container, 'sales-by-manufacturer');
|
|
475
|
+
|
|
476
|
+
console.log(handle.status);
|
|
477
|
+
console.log(handle.requirements);
|
|
478
|
+
|
|
479
|
+
const renderResult = await handle.ready;
|
|
480
|
+
console.log(renderResult.status);
|
|
481
|
+
|
|
482
|
+
handle.unmount();
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Direct mounting and web-component mounting use the same runtime, instance state, SDK client, and visualization implementation.
|
|
486
|
+
`runtime.mount()` reports structural mounting through `handle.status`; `handle.ready` is the separate render-completion signal.
|
|
487
|
+
|
|
488
|
+
Readiness waits for the chart's existing render-completion or error event, with a default deadline of **40 seconds**.
|
|
489
|
+
Set `readyTimeoutMs` when creating the runtime to customize that deadline for all direct and web-component mounts:
|
|
490
|
+
|
|
491
|
+
```ts
|
|
492
|
+
const runtime = createVisualizationRuntime({
|
|
493
|
+
client,
|
|
494
|
+
registry,
|
|
495
|
+
readyTimeoutMs: 60_000, // optional; defaults to 40_000
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
The value must be an integer from 1 to 2,147,483,647 milliseconds. The deadline starts when chart initialization begins,
|
|
500
|
+
after metadata preloading and lazy module loading; it does not bound those preparatory steps of `runtime.mount()`.
|
|
501
|
+
If no terminal event arrives in time, readiness resolves with `{ instanceId, status: 'timeout' }`. The chart remains
|
|
502
|
+
mounted and may finish rendering later, but that readiness result stays `timeout`. Check for `status === 'rendered'`
|
|
503
|
+
before treating a chart as ready. Unmounting before the deadline resolves readiness as `unmounted`.
|
|
504
|
+
|
|
505
|
+
## Fonts And Icons
|
|
506
|
+
|
|
507
|
+
Charts draw axis labels and legends on `<canvas>`, which only uses fonts that have finished loading. The runtime picks
|
|
508
|
+
the chart font for you, so no host CSS is needed:
|
|
509
|
+
|
|
510
|
+
1. `createVisualizationRuntime({ theme: { fontFamily } })`, when set.
|
|
511
|
+
2. Otherwise the host page's font: `--astrato-font-family`, then `--font-family` (both read from `:root`), then the
|
|
512
|
+
`font-family` of `body`.
|
|
513
|
+
|
|
514
|
+
The runtime adds `system-ui, sans-serif` when the selected stack has no sans-serif fallback. It preserves your font
|
|
515
|
+
choices, including an explicitly selected serif family. Declare your webfont (for example with a `<link>` or
|
|
516
|
+
`@font-face`) before calling `runtime.mount()`. The runtime waits up to 3 seconds for the first registered webfont
|
|
517
|
+
in the stack, skipping unavailable families. Mounts in the same document share that preparation. The initial load
|
|
518
|
+
uses Latin sample text; other scripts and weights may load when chart text first uses them. Mounted charts redraw
|
|
519
|
+
when a face in their selected stack finishes loading, including after the initial wait times out. Unmounting removes
|
|
520
|
+
the font listener.
|
|
521
|
+
|
|
522
|
+
```ts
|
|
523
|
+
const runtime = createVisualizationRuntime({
|
|
524
|
+
client,
|
|
525
|
+
registry,
|
|
526
|
+
theme: { fontFamily: 'Inter' }, // optional; defaults to the page font
|
|
527
|
+
});
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
All supported table indicator icons render as inline SVG through the shared icon catalog, including legacy aliases.
|
|
531
|
+
They need no icon font and are not affected by host `font-family` rules. The package includes the Material Icons
|
|
532
|
+
license in `THIRD_PARTY_NOTICES.md`.
|
|
533
|
+
|
|
534
|
+
## Exporting A Chart's Data
|
|
535
|
+
|
|
536
|
+
A mounted chart exposes the query it runs, so an app can offer show-as-table or CSV/Excel export that matches the
|
|
537
|
+
chart. The query is the chart's own: it keeps Top N, sorting, grouping and the chart's filters, without pagination.
|
|
538
|
+
It runs through the same data service as the chart, so the group's selections apply to it the same way.
|
|
539
|
+
|
|
540
|
+
```ts
|
|
541
|
+
const handle = await runtime.mount(container, 'sales-by-manufacturer');
|
|
542
|
+
await handle.ready;
|
|
543
|
+
|
|
544
|
+
const exportQuery = await handle.getExportQuery(); // { instanceId, query, config } or null
|
|
545
|
+
const result = await handle.getData({ limit: 5000 }); // { instanceId, query, config, data } or null
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`getData()` runs the export query through the same `engine.getData` or `data.query` service the chart uses, and `data`
|
|
549
|
+
is that service's response. `config` carries the chart's export settings (`limit`, `nullAs`, `csvFormatValues`, and
|
|
550
|
+
`pivotConfig` for pivot tables). The row limit defaults to the chart's export limit, or 1,000, and is capped at 100,000.
|
|
551
|
+
|
|
552
|
+
Both resolve to `null` when the chart has nothing to export, for example when its requirements are not met, and when
|
|
553
|
+
the instance is unmounted. Call them after `handle.ready`: while the chart is fetching, they wait for that fetch's query.
|
|
554
|
+
Apps using the web component can call `runtime.getExportQuery(instanceId)` and `runtime.getData(instanceId, options)`.
|
|
555
|
+
|
|
556
|
+
## Updating vSpec With Operations
|
|
557
|
+
|
|
558
|
+
The [Operations Reference](./docs/operations/index.md) lists the complete standalone operation catalog by visualization
|
|
559
|
+
type, with descriptions and payload schemas. It is generated from the same manifests as runtime metadata and shipped
|
|
560
|
+
inside this package. Humans and agents can read `node_modules/@astrato-io/visualizations/docs/operations/index.md` without
|
|
561
|
+
loading a chart or importing browser JavaScript. Use the bundled reference to match your installed package version.
|
|
562
|
+
Enum values are part of each payload schema. Breaking changes per version are in [CHANGELOG.md](./CHANGELOG.md).
|
|
563
|
+
|
|
564
|
+
Use a visualization definition once to create the initial configured vSpec. After `runtime.createInstance()`, keep that
|
|
565
|
+
runtime instance and use operations for incremental changes. Do not repeatedly compile definitions or replace the
|
|
566
|
+
complete vSpec with a host-side copy: that can discard chart-originated state such as table column widths and sorting.
|
|
567
|
+
|
|
568
|
+
### Choosing An Operations API
|
|
569
|
+
|
|
570
|
+
The operations package exposes two levels of API:
|
|
571
|
+
|
|
572
|
+
| API | State ownership | Concurrency protection | Recommended use |
|
|
573
|
+
| ------------------------ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
574
|
+
| `applyRuntimeOperations` | Reads and updates a runtime instance | Serializes calls per instance and retries after concurrent local vSpec changes | Normal SDK and browser integrations |
|
|
575
|
+
| `applyOperations` | Transforms the explicitly supplied instance and only returns the result | None across separate calls | Tests, previews, server-side/offline transformation, or custom state adapters |
|
|
576
|
+
|
|
577
|
+
Use `applyRuntimeOperations` unless the application deliberately owns vSpec state without the visualization runtime.
|
|
578
|
+
|
|
579
|
+
### Applying Operations To A Runtime Instance
|
|
580
|
+
|
|
581
|
+
`applyRuntimeOperations` reads the latest runtime-owned vSpec, applies the requests, and writes the resulting vSpec back
|
|
582
|
+
to the same instance. If the instance is mounted, the connected visualization receives the update in place. Operations
|
|
583
|
+
also work while the instance is unmounted; a later mount uses the updated runtime vSpec.
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
import { applyRuntimeOperations } from '@astrato-io/visualizations/operations';
|
|
587
|
+
|
|
588
|
+
const result = await applyRuntimeOperations({
|
|
589
|
+
runtime,
|
|
590
|
+
instanceId: 'sales-by-manufacturer',
|
|
591
|
+
availableFields,
|
|
592
|
+
operationRequests: [
|
|
593
|
+
{
|
|
594
|
+
id: 'add-dimension',
|
|
595
|
+
name: 'addDimension',
|
|
596
|
+
payload: { key: '[Cars].[Manufacturer]' },
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
id: 'add-measure',
|
|
600
|
+
name: 'addMeasure',
|
|
601
|
+
payload: {
|
|
602
|
+
aggregation: 'SUM',
|
|
603
|
+
key: '[Cars].[Sales In Thousands]',
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
console.log(result.results);
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
For one runtime instance, this API:
|
|
613
|
+
|
|
614
|
+
- serializes separate calls so that concurrent callers cannot overwrite each other's results;
|
|
615
|
+
- starts every call from the latest runtime vSpec;
|
|
616
|
+
- retries if the chart changes its local vSpec, for example after sorting or resizing a table column, while an operation
|
|
617
|
+
is running; and
|
|
618
|
+
- rejects a stale result if the instance is removed, recreated, or structurally replaced while work is pending.
|
|
619
|
+
|
|
620
|
+
Calls for different instances are independent and may run concurrently.
|
|
621
|
+
|
|
622
|
+
Supply `availableFields` for operations that add or replace dimensions, measures, calculations, or raw fields. The
|
|
623
|
+
catalog must belong to the same semantic-layer context as the instance. Operations that only modify existing visual
|
|
624
|
+
properties may not require it. Most integrations do not need the advanced `variables`, `vTheme`, `changesQueue`, or
|
|
625
|
+
custom `registry` inputs.
|
|
626
|
+
|
|
627
|
+
### Batches, Results, And Errors
|
|
628
|
+
|
|
629
|
+
`operationRequests` is a batch. Requests in one batch execute sequentially, and each request sees the successful vSpec
|
|
630
|
+
changes produced by earlier requests in that batch. A batch is not transactional: one request may fail while later
|
|
631
|
+
requests continue. Provide a stable `id` for every request so its response is easy to correlate. If it is omitted, the
|
|
632
|
+
operations engine generates an ID and returns it in the result.
|
|
633
|
+
|
|
634
|
+
The returned `results` object contains one result per request ID, while `vSpec` contains the final transformed vSpec.
|
|
635
|
+
Invalid payloads and operation-specific failures are normally reported as `{ success: false, error: ... }` entries.
|
|
636
|
+
The returned promise rejects for call-level failures, such as an unknown instance, an unsupported operation name, a
|
|
637
|
+
missing source vSpec, or an instance lifecycle change that makes the pending result stale.
|
|
638
|
+
|
|
639
|
+
Use visualization metadata to discover operation names and payload schemas instead of importing internal Astrato
|
|
640
|
+
operation packages:
|
|
641
|
+
|
|
642
|
+
```ts
|
|
643
|
+
import { getVisualizationMetadata } from '@astrato-io/visualizations/metadata';
|
|
644
|
+
|
|
645
|
+
const tableOperations = getVisualizationMetadata('table').operations;
|
|
646
|
+
|
|
647
|
+
console.log(tableOperations.names);
|
|
648
|
+
console.log(tableOperations.items);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
### Transforming A vSpec Without A Runtime
|
|
652
|
+
|
|
653
|
+
`applyOperations` is the lower-level, state-independent operation engine. It accepts an explicit instance and returns a
|
|
654
|
+
new vSpec without updating a runtime, mounted element, or external store:
|
|
655
|
+
|
|
656
|
+
```ts
|
|
657
|
+
import { applyOperations } from '@astrato-io/visualizations/operations';
|
|
658
|
+
|
|
659
|
+
const transformed = await applyOperations({
|
|
660
|
+
instance,
|
|
661
|
+
availableFields,
|
|
662
|
+
operationRequests: [
|
|
663
|
+
{
|
|
664
|
+
id: 'add-manufacturer',
|
|
665
|
+
name: 'addDimension',
|
|
666
|
+
payload: { key: '[Cars].[Manufacturer]' },
|
|
667
|
+
},
|
|
668
|
+
],
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
console.log(transformed.vSpec);
|
|
672
|
+
console.log(transformed.results);
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
This is the supported way to finish a compiled `VisualizationDefinition` before mounting: pass
|
|
676
|
+
`{ id, type, vSpec: compilation.vSpec }` as the instance and use `compilation.resolvedRefs` for the data-item identity of
|
|
677
|
+
each definition `ref`. It runs in memory and makes no engine requests. It is also useful when validating a vSpec,
|
|
678
|
+
running operations in tests, or building an adapter with intentional custom state ownership. It does not serialize separate calls or protect against a
|
|
679
|
+
newer runtime/chart vSpec. Avoid applying its result to a live runtime from an older instance snapshot; use
|
|
680
|
+
`applyRuntimeOperations` for that case.
|
|
681
|
+
|
|
682
|
+
### Table Column Operations
|
|
683
|
+
|
|
684
|
+
For tables, create the configured table once and then keep the same runtime instance while adding, removing, or
|
|
685
|
+
reordering columns:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
await applyRuntimeOperations({
|
|
689
|
+
runtime,
|
|
690
|
+
instanceId: 'sales-table',
|
|
691
|
+
availableFields,
|
|
692
|
+
operationRequests: [
|
|
693
|
+
{
|
|
694
|
+
id: 'add-sales-column',
|
|
695
|
+
name: 'addColumn',
|
|
696
|
+
payload: {
|
|
697
|
+
columnType: 'measure',
|
|
698
|
+
sourceKind: 'field',
|
|
699
|
+
key: '[Cars].[Sales In Thousands]',
|
|
700
|
+
aggregation: 'SUM',
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
await applyRuntimeOperations({
|
|
707
|
+
runtime,
|
|
708
|
+
instanceId: 'sales-table',
|
|
709
|
+
operationRequests: [
|
|
710
|
+
{
|
|
711
|
+
id: 'remove-manufacturer-column',
|
|
712
|
+
name: 'removeColumn',
|
|
713
|
+
payload: {
|
|
714
|
+
columnType: 'dimension',
|
|
715
|
+
key: '[Cars].[Manufacturer]',
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
],
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
await applyRuntimeOperations({
|
|
722
|
+
runtime,
|
|
723
|
+
instanceId: 'sales-table',
|
|
724
|
+
operationRequests: [
|
|
725
|
+
{
|
|
726
|
+
id: 'move-model-column',
|
|
727
|
+
name: 'reorderColumn',
|
|
728
|
+
payload: {
|
|
729
|
+
source: { columnType: 'dimension', key: '[Cars].[Model]' },
|
|
730
|
+
target: { columnType: 'dimension', key: '[Cars].[Manufacturer]' },
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
],
|
|
734
|
+
});
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
Engine-key selectors use `match: 'only'` by default: they match exactly one column and fail rather than guessing when
|
|
738
|
+
duplicates exist. Table `removeColumn` also accepts `match: 'all'` for intentional bulk removal. Raw field measures
|
|
739
|
+
include their aggregation; predefined measures and calculations include `sourceKind`. Pivot dimensions may include
|
|
740
|
+
`topDimension`. The existing internal-key selector remains available for integrations that already have exact vSpec
|
|
741
|
+
identifiers.
|
|
742
|
+
|
|
743
|
+
Operations are called against the runtime or an explicit instance, not against the `astrato-visualization` element.
|
|
744
|
+
Do not use the internal Astrato `VISUALIZATION_OPERATIONS_REQUESTED` event as a standalone integration API; it is tied
|
|
745
|
+
to Astrato's wrapper transport and persistence lifecycle. Similarly, reserve `runtime.updateInstance(instanceId,
|
|
746
|
+
{ vSpec })` for an intentional complete vSpec replacement, not ordinary incremental changes.
|
|
747
|
+
|
|
748
|
+
## Reading vSpec With Getters
|
|
749
|
+
|
|
750
|
+
```ts
|
|
751
|
+
import { processRuntimeGetterRequests } from '@astrato-io/visualizations/getters';
|
|
752
|
+
|
|
753
|
+
const result = processRuntimeGetterRequests({
|
|
754
|
+
runtime,
|
|
755
|
+
instanceId: 'sales-by-manufacturer',
|
|
756
|
+
getterRequests: [{ name: 'getOrientation' }],
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
console.log(result.results);
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
Getter names and result schemas are available from visualization metadata. Unsupported operations and getters fail with an explicit error.
|
|
763
|
+
|
|
764
|
+
## Metadata And Registry
|
|
765
|
+
|
|
766
|
+
Metadata describes visualization types, presets, requirements, vSpec schemas, operations, and getters:
|
|
767
|
+
|
|
768
|
+
```ts
|
|
769
|
+
import { getVisualizationMetadata, visualizationMetadata } from '@astrato-io/visualizations/metadata';
|
|
770
|
+
|
|
771
|
+
console.log(visualizationMetadata);
|
|
772
|
+
console.log(getVisualizationMetadata('bar'));
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
Registry helpers are available from the root package:
|
|
776
|
+
|
|
777
|
+
```ts
|
|
778
|
+
import {
|
|
779
|
+
createDefaultVSpec,
|
|
780
|
+
getVisualizationRegistryEntry,
|
|
781
|
+
listVisualizationRegistryEntries,
|
|
782
|
+
} from '@astrato-io/visualizations';
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
## Selection Groups
|
|
786
|
+
|
|
787
|
+
Instances with the same `groupId` share SDK selection and filter state. Instances without a group use `default`.
|
|
788
|
+
|
|
789
|
+
```ts
|
|
790
|
+
runtime.createInstance({
|
|
791
|
+
id: 'country-filter',
|
|
792
|
+
type: 'filter',
|
|
793
|
+
groupId: 'dashboard',
|
|
794
|
+
dataBinding,
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
runtime.createInstance({
|
|
798
|
+
id: 'sales-chart',
|
|
799
|
+
type: 'bar',
|
|
800
|
+
groupId: 'dashboard',
|
|
801
|
+
dataBinding,
|
|
802
|
+
});
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
Selection identity is based on engine `fieldKey` values.
|
|
806
|
+
|
|
807
|
+
### Brushing Without Selecting
|
|
808
|
+
|
|
809
|
+
`brush` highlights values across every instance of a group without selecting them: the brushed values keep their
|
|
810
|
+
look and every other value takes the chart's inactive style, exactly as a selection is drawn. A brush never becomes a
|
|
811
|
+
pending or applied selection, never shows as a filter, and sends no query.
|
|
812
|
+
|
|
813
|
+
```ts
|
|
814
|
+
runtime.brush('dashboard', [{ fieldKey: growthGroupFieldKey, values: ['Rocket Ship'] }]);
|
|
815
|
+
|
|
816
|
+
runtime.clearBrush('dashboard');
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
Each call replaces the group's previous brush. Instances mounted into the group later show the current brush. A chart
|
|
820
|
+
shows a brush only for fields it has bound as dimensions; a line chart dims by its series dimension, so brushing an
|
|
821
|
+
axis value does not fade a line.
|
|
822
|
+
|
|
823
|
+
## Runtime State And Persistence
|
|
824
|
+
|
|
825
|
+
The runtime keeps one current vSpec for each live instance. Chart-originated local changes, including table column
|
|
826
|
+
widths, update that in-memory vSpec so later operations preserve them. This synchronization belongs to the
|
|
827
|
+
visualization runtime and does not make the vSpec durable.
|
|
828
|
+
|
|
829
|
+
Create the SDK client and visualization runtime at application scope, create each visualization instance once, and use
|
|
830
|
+
operations after initialization. Do not repeatedly compile definitions or replace the full vSpec with an older host
|
|
831
|
+
copy. Unmounting may retain an instance for a later remount; `removeInstance`, runtime recreation, and page reload
|
|
832
|
+
discard its state. The default SDK model save hooks remain no-ops, and the package does not write visualization state
|
|
833
|
+
to browser storage.
|
|
834
|
+
|
|
835
|
+
## Package Exports
|
|
836
|
+
|
|
837
|
+
| Export | Contents |
|
|
838
|
+
| ---------------------------------------- | -------------------------------------------------------------------- |
|
|
839
|
+
| `@astrato-io/visualizations` | Runtime, registry, web-component bootstrap, and shared runtime types |
|
|
840
|
+
| `@astrato-io/visualizations/operations` | Runtime-managed and low-level vSpec operation execution |
|
|
841
|
+
| `@astrato-io/visualizations/getters` | Optional vSpec getter execution |
|
|
842
|
+
| `@astrato-io/visualizations/metadata` | Optional serializable visualization metadata |
|
|
843
|
+
| `@astrato-io/visualizations/definitions` | Optional initial-creation schemas and compiler |
|
|
844
|
+
| `@astrato-io/visualizations/styles.css` | Required package styles |
|