@peter.prib/renderengine 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/REFERENCE.md +85 -0
- package/dist/renderengine-workspace.umd.js +960 -147
- package/dist/renderengine.umd.js +960 -147
- package/package.json +2 -2
- package/src/chartCatalog.js +10 -0
- package/src/charting/ChartChooser.js +243 -0
- package/src/charting/PopupMenu.js +152 -150
- package/src/charting/charts/TableChart.js +98 -0
- package/src/charting/table/TableView.js +263 -0
- package/src/charting/table/TableViewChart.js +126 -0
- package/src/index.js +79 -1
package/REFERENCE.md
CHANGED
|
@@ -88,6 +88,7 @@ catalog `key` for you.
|
|
|
88
88
|
| `treemap` | `treemapChart(data, opts)` | `Array<{label, value?, children?}>` (hierarchical) | squarified layout, palette by top-level branch |
|
|
89
89
|
| `sunburst` | `sunburstChart(data, opts)` | same hierarchical shape as `treemap` | nested rings by depth |
|
|
90
90
|
| `outline` | `outlineChart(data, opts)` | same hierarchical shape as `treemap`/`sunburst` | `onNodeClick`; collapsible indented list |
|
|
91
|
+
| `table` | `tableChart(data, opts)` | `Array<object>` — a row per object, a column per key | `columns` (names or `{key, label?, align?}`), `maxRows`, `nullText` (`'—'`); values exact, numeric columns right-aligned; drawn with the renderer's primitives, so SVG or canvas |
|
|
91
92
|
| `gauge-dial` | `dialGauge(value, opts)` | `number`, `{value, target?}`, or `[{value, label?, color?}]` for a needle each (0–100 unless `min`/`max`) | the gauge options below; `cx`, `cy`, `r`, `thickness`, `startAngle`, `sweep`, `needleColors`; several needles get a legend, the first fills the arc |
|
|
92
93
|
| `gauge-bar` | `barGauge(value, opts)` | `number` or `{value, target?}` (0–100 unless `min`/`max`) | the gauge options below; `x`, `y`, `width`, `height`, `orientation: 'vertical'` |
|
|
93
94
|
| `gauge-arc` | `arcGauge(value, opts)` | `number` or `{value, target?}` | the gauge options below; `cx`, `cy`, `r`, `thickness`, `startAngle`, `sweep` (a half circle by default), `cap` |
|
|
@@ -1080,6 +1081,90 @@ this to `line`/`area`/`stackedBar`/etc. is the same three-line change: call
|
|
|
1080
1081
|
`this._drawYAxisTicks(x, y, width, height, rawMax)` before drawing marks, and scale against its
|
|
1081
1082
|
return value instead of the raw max — not done yet for the rest, tracked as a follow-up.
|
|
1082
1083
|
|
|
1084
|
+
### Choosing a chart for result rows — `ChartChooser`
|
|
1085
|
+
|
|
1086
|
+
`new ChartChooser().choose(rows, columns?, { complete? })` says which chart types fit a set of result rows (a query
|
|
1087
|
+
answer, a CSV), best first, each with the rows already shaped as that type's `dataShape` — so
|
|
1088
|
+
drawing the best one is `engine.renderChartType(best.key, best.data)`. A `table` always fits and is
|
|
1089
|
+
always offered, last.
|
|
1090
|
+
|
|
1091
|
+
```javascript
|
|
1092
|
+
import { RenderEngine, ChartChooser } from '@peter.prib/renderengine';
|
|
1093
|
+
|
|
1094
|
+
const rows = [{ Region: 'West', Revenue: 200 }, { Region: 'East', Revenue: 405 }];
|
|
1095
|
+
const choices = new ChartChooser().choose(rows, [{ name: 'Region' }, { name: 'Revenue', measure: 'additive' }]);
|
|
1096
|
+
// → bar, pie, donut, table — each { key, label, data, reason }
|
|
1097
|
+
const [best] = choices;
|
|
1098
|
+
new RenderEngine(container).renderChartType(best.key, best.data, { title: best.reason });
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
`columns` are optional hints, `{ name, kind?, measure? }`: `kind` is `'categorical'`, `'numeric'`
|
|
1102
|
+
or `'time'` (without a hint, a column whose values are all numbers is numeric, else categorical);
|
|
1103
|
+
`measure` is the data model's measure kind (`'additive'`, `'semi-additive'`, `'non-additive'`).
|
|
1104
|
+
`complete: false` says the rows are only part of the answer (a top N, a first page).
|
|
1105
|
+
|
|
1106
|
+
| Rows look like | Offered, best first |
|
|
1107
|
+
|---|---|
|
|
1108
|
+
| one number, one row | `kpi-tile` |
|
|
1109
|
+
| one category, one number | `bar`; also `pie`, `donut` when the measure is additive, the rows are complete, no value is negative and there are 2–8 categories |
|
|
1110
|
+
| one time column, one number | `line`, `area`, `bar` — in time order |
|
|
1111
|
+
| one category, several numbers | `groupedBar`, `line` (a series per number); with time, `line` first |
|
|
1112
|
+
| two categories, one number | `groupedBar`, `heatmap`; with a time column, `line` (a line per category) first |
|
|
1113
|
+
| anything else | `table` only |
|
|
1114
|
+
|
|
1115
|
+
A chart is of **one value per category**: rows that repeat a category (orders, not totals per
|
|
1116
|
+
region) get no chart — group them in the query first — since a bar per row would repeat its label,
|
|
1117
|
+
and a repeated pair of categories would replace another's value unseen.
|
|
1118
|
+
|
|
1119
|
+
Three rules keep a choice from misleading: only an **additive** measure is offered as shares of a
|
|
1120
|
+
whole (a slice of an average or a balance means nothing); only **complete** rows are (three
|
|
1121
|
+
customers' slices of a top 3 would claim to be the whole); and a **missing value is never drawn as
|
|
1122
|
+
0** — a result with a hole in a series is not offered as series charts (the heatmap, which draws
|
|
1123
|
+
only the cells present, still is), and a bar chart simply has no bar for a null.
|
|
1124
|
+
|
|
1125
|
+
A table has no axes, so it takes none of a chart's axis margins. `TableChart.heightFor(rowCount,
|
|
1126
|
+
{ title?, maxRows? })` is the height it will draw, for sizing its container first.
|
|
1127
|
+
|
|
1128
|
+
### One output for a result — `resultView`
|
|
1129
|
+
|
|
1130
|
+
`engine.resultView(rows, options)` shows result rows as an **interactive table** whose own menu
|
|
1131
|
+
can show them as any chart that fits — table or chart, one output. It returns the table's state, a
|
|
1132
|
+
`TableView`.
|
|
1133
|
+
|
|
1134
|
+
```javascript
|
|
1135
|
+
const view = new RenderEngine(container, { rendererType: 'svg' }).resultView(rows, {
|
|
1136
|
+
columns: [{ name: 'Day', kind: 'time' }, { name: 'Revenue', measure: 'additive' }], // ChartChooser hints
|
|
1137
|
+
complete: true, // false when the rows are only part of the answer (a top N)
|
|
1138
|
+
pageSize: 50,
|
|
1139
|
+
menus: { row: ({ row }) => [{ label: 'Open order', action: () => open(row.id) }] },
|
|
1140
|
+
});
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
| Click | Does |
|
|
1144
|
+
|---|---|
|
|
1145
|
+
| a column header | sorts: ascending, descending, unsorted (nulls always last; equal values keep their order) |
|
|
1146
|
+
| a header's ▾ | the column menu: sort, **Filter to** one of its values (up to 20 listed), clear its filters, hide it, copy it |
|
|
1147
|
+
| a cell | the cell menu: only / exclude rows with this value (or with an empty one); for a number, only rows above / below it; copy the value |
|
|
1148
|
+
| a row number | the row menu: copy the row (tab-separated, or as JSON) |
|
|
1149
|
+
| the corner ⋮ | the table menu: **Show as** (the chart types ChartChooser says fit what is showing), clear all filters, show hidden columns, copy the table |
|
|
1150
|
+
| the footer's ‹ › | pages; the footer says "1–50 of 120 rows (filtered from 300: Region = West)" |
|
|
1151
|
+
|
|
1152
|
+
Filtering is by choosing values in the table, never by typing. A filter, a sort or a hidden column
|
|
1153
|
+
carries into **Show as**: the chart is drawn from the rows and columns showing, in their order, and
|
|
1154
|
+
filtered rows are never offered as shares of a whole. A chart drawn that way has a **◂ Table** link
|
|
1155
|
+
back to the table as it was left. The container's height follows what is drawn (the table's rows,
|
|
1156
|
+
or `chartHeight`, 360); pass `fitHeight: false` to size it yourself. A host adds its own items to
|
|
1157
|
+
any menu with `menus: { cell, row, column, table }`, each `(context) → PopupMenu items`, shown after
|
|
1158
|
+
a separator.
|
|
1159
|
+
|
|
1160
|
+
Interaction needs the SVG renderer (its shapes take clicks); on canvas the same table is drawn
|
|
1161
|
+
without it. `TableView` (`src/charting/table/TableView.js`) holds all of the state and builds every
|
|
1162
|
+
menu as data, so it can be driven and tested without a DOM; `TableViewChart` draws it.
|
|
1163
|
+
|
|
1164
|
+
Every suggestion is checked against the registry the chooser is given (`chartRegistry` by default):
|
|
1165
|
+
a type is offered only if the catalog has it and every axis it marks `required` is one the result's
|
|
1166
|
+
shape provides, so the catalog stays the single source of truth for what each chart needs.
|
|
1167
|
+
|
|
1083
1168
|
## Common options
|
|
1084
1169
|
|
|
1085
1170
|
Not every method takes every option below — the table above calls out what's notable per type —
|