@ifc-lite/charts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/dist/aggregate.d.ts +48 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +306 -0
- package/dist/aggregate.js.map +1 -0
- package/dist/echarts-option.d.ts +41 -0
- package/dist/echarts-option.d.ts.map +1 -0
- package/dist/echarts-option.js +142 -0
- package/dist/echarts-option.js.map +1 -0
- package/dist/elements-dataset.d.ts +40 -0
- package/dist/elements-dataset.d.ts.map +1 -0
- package/dist/elements-dataset.js +76 -0
- package/dist/elements-dataset.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/palette.d.ts +18 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +42 -0
- package/dist/palette.js.map +1 -0
- package/dist/render-svg.d.ts +9 -0
- package/dist/render-svg.d.ts.map +1 -0
- package/dist/render-svg.js +38 -0
- package/dist/render-svg.js.map +1 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +18 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +140 -0
- package/dist/validate.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @ifc-lite/charts
|
|
2
|
+
|
|
3
|
+
Headless chart data binding for IFC models. A chart is a **dataset** (rows that each carry the renderer ids of the elements they stand for) plus a **spec** (what to bucket by, what to measure). `aggregate` keeps every bucket's member ids, which is what makes a chart bidirectional with a 3D view: a bar is a set of element ids, and a 3D selection is a set of buckets. Rendering is Apache ECharts — an option builder for an on-screen chart and an SVG renderer that runs without a DOM (Node, CLI, PDF export).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ifc-lite/charts
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { aggregate, elementsDataset, idsForCategories, categoriesForIds, renderChartSvg } from '@ifc-lite/charts';
|
|
15
|
+
import type { ChartSpec } from '@ifc-lite/charts';
|
|
16
|
+
|
|
17
|
+
// One row per element instance with IfcType / Storey / Model / Name, straight
|
|
18
|
+
// off the columnar entity table; `toGlobalId` is the host's own local → renderer id resolver.
|
|
19
|
+
const dataset = elementsDataset([{ store, toGlobalId: (id) => id, name: 'office.ifc' }]);
|
|
20
|
+
|
|
21
|
+
const spec: ChartSpec = {
|
|
22
|
+
id: 'by-type', title: 'Elements by type', source: 'elements', type: 'bar',
|
|
23
|
+
dimension: 'IfcType', measure: { agg: 'count' }, topN: 12,
|
|
24
|
+
};
|
|
25
|
+
const agg = aggregate(spec, dataset);
|
|
26
|
+
agg.categories; // buckets, largest first, each with `ids: Uint32Array` and a stable colour
|
|
27
|
+
idsForCategories(agg, [0]); // chart click → the element ids to select / isolate / ghost in 3D
|
|
28
|
+
categoriesForIds(agg, selectedIds); // 3D selection → { full, partial } bucket indices to highlight in the chart
|
|
29
|
+
|
|
30
|
+
const svg = renderChartSvg({ aggregation: agg, width: 640, height: 400 }); // vector, for a PDF report
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- `aggregate(spec, dataset, { slice, palette })`: count / sum by one dimension, optionally stacked by a second; `topN` + `Other`; histogram bins (Sturges default); ISO-week `timeline` for date columns; a `slice` of ids to cross-filter one chart by another; colours assigned by label and kept across re-aggregations
|
|
36
|
+
- `elementsDataset(models)`: the elements source without a query engine — one typed-array pass over the entity table and spatial hierarchy
|
|
37
|
+
- `buildEChartsOption` / `renderChartSvg`: ECharts options with persistent multi-select and emphasis blur, and SSR SVG output
|
|
38
|
+
- `validateDashboardSpec` / `isDashboardSpec` / `isReportSpec`: structural validation of saved dashboards and report templates (`DashboardSpec`, `ReportSpec`)
|
|
39
|
+
|
|
40
|
+
Part of the [ifc-lite](https://github.com/LTplus-AG/ifc-lite) monorepo. Licensed under MPL-2.0.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bucket a dataset by a spec. One typed-array-friendly pass over the rows;
|
|
3
|
+
* no query engine — count/sum by one or two keys over a million
|
|
4
|
+
* dictionary-encoded rows is tens of milliseconds, and keeping the member
|
|
5
|
+
* ids per bucket is what a chart library cannot do for us.
|
|
6
|
+
*
|
|
7
|
+
* `slice` restricts the rows to those whose ids intersect it — that is how
|
|
8
|
+
* one chart's selection re-aggregates every other chart on a dashboard.
|
|
9
|
+
*/
|
|
10
|
+
import { type PaletteAssignment } from './palette.js';
|
|
11
|
+
import type { Aggregation, ChartDataset, ChartItem, ChartSpec } from './types.js';
|
|
12
|
+
export interface AggregateOptions {
|
|
13
|
+
/** Only rows with at least one id in the slice count. */
|
|
14
|
+
slice?: ReadonlySet<number> | null;
|
|
15
|
+
/** Colours from the previous aggregation, kept by label. */
|
|
16
|
+
palette?: PaletteAssignment;
|
|
17
|
+
}
|
|
18
|
+
export interface AggregateResult extends Aggregation {
|
|
19
|
+
palette: PaletteAssignment;
|
|
20
|
+
}
|
|
21
|
+
/** ISO week key (`2026-W37`) for a date value; weeks start on Monday. */
|
|
22
|
+
export declare function isoWeekKey(ms: number): string;
|
|
23
|
+
/** Sturges' rule, the spreadsheet default: ⌈log2 n⌉ + 1 bins, at least 1. */
|
|
24
|
+
export declare function sturgesBins(n: number): number;
|
|
25
|
+
export declare function aggregate(spec: ChartSpec, dataset: ChartDataset, options?: AggregateOptions): AggregateResult;
|
|
26
|
+
/** The element ids behind a set of category indices — what a chart click selects in 3D. */
|
|
27
|
+
export declare function idsForCategories(aggregation: Aggregation, indices: Iterable<number>): Set<number>;
|
|
28
|
+
/**
|
|
29
|
+
* The category indices a 3D selection touches, with how much of each bucket
|
|
30
|
+
* is selected — `full` buckets are what a chart marks selected, `partial`
|
|
31
|
+
* ones what it emphasises.
|
|
32
|
+
*/
|
|
33
|
+
export declare function categoriesForIds(aggregation: Aggregation, ids: Iterable<number>): {
|
|
34
|
+
full: number[];
|
|
35
|
+
partial: number[];
|
|
36
|
+
};
|
|
37
|
+
/** The element ids behind a set of chart items: a stacked segment selects only its own series' share of the category. */
|
|
38
|
+
export declare function idsForItems(aggregation: Aggregation, items: Iterable<ChartItem>): Set<number>;
|
|
39
|
+
/**
|
|
40
|
+
* The chart items a 3D selection touches, per series: `full` items have every
|
|
41
|
+
* id selected, `partial` ones some. For a single-series chart this is
|
|
42
|
+
* {@link categoriesForIds} with `seriesIndex: 0`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function itemsForIds(aggregation: Aggregation, ids: Iterable<number>): {
|
|
45
|
+
full: ChartItem[];
|
|
46
|
+
partial: ChartItem[];
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,OAAO,EAAsD,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,KAAK,EACV,WAAW,EAIX,YAAY,EAEZ,SAAS,EACT,SAAS,EACV,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACnC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAiCD,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAQ7C;AAeD,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;AA2ED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAsGjH;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAQjG;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAevH;AAED,yHAAyH;AACzH,wBAAgB,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAQ7F;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,SAAS,EAAE,CAAA;CAAE,CAcxH"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Bucket a dataset by a spec. One typed-array-friendly pass over the rows;
|
|
6
|
+
* no query engine — count/sum by one or two keys over a million
|
|
7
|
+
* dictionary-encoded rows is tens of milliseconds, and keeping the member
|
|
8
|
+
* ids per bucket is what a chart library cannot do for us.
|
|
9
|
+
*
|
|
10
|
+
* `slice` restricts the rows to those whose ids intersect it — that is how
|
|
11
|
+
* one chart's selection re-aggregates every other chart on a dashboard.
|
|
12
|
+
*/
|
|
13
|
+
import { assignColors, OTHER_BUCKET_COLOR, OTHER_BUCKET_KEY } from './palette.js';
|
|
14
|
+
const OTHER_LABEL = 'Other';
|
|
15
|
+
const MISSING_KEY = '__missing__';
|
|
16
|
+
function categoryKeyer() {
|
|
17
|
+
return (value) => {
|
|
18
|
+
if (value === null || value === undefined || value === '')
|
|
19
|
+
return null;
|
|
20
|
+
const label = String(value);
|
|
21
|
+
return { key: label, label, order: 0 };
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** ISO week key (`2026-W37`) for a date value; weeks start on Monday. */
|
|
25
|
+
export function isoWeekKey(ms) {
|
|
26
|
+
const d = new Date(ms);
|
|
27
|
+
// Shift to the Thursday of this ISO week (UTC), whose year is the ISO year.
|
|
28
|
+
const day = d.getUTCDay() || 7;
|
|
29
|
+
const thursday = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 4 - day));
|
|
30
|
+
const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
|
|
31
|
+
const week = Math.ceil(((thursday.getTime() - yearStart) / 86_400_000 + 1) / 7);
|
|
32
|
+
return `${thursday.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
|
|
33
|
+
}
|
|
34
|
+
function timelineKeyer() {
|
|
35
|
+
return (value) => {
|
|
36
|
+
if (value === null || value === undefined || value === '')
|
|
37
|
+
return null;
|
|
38
|
+
const ms = typeof value === 'number' ? value : Date.parse(String(value));
|
|
39
|
+
if (!Number.isFinite(ms))
|
|
40
|
+
return null;
|
|
41
|
+
const key = isoWeekKey(ms);
|
|
42
|
+
// Order by the Monday of the week so labels sort chronologically.
|
|
43
|
+
const d = new Date(ms);
|
|
44
|
+
const monday = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - ((d.getUTCDay() || 7) - 1));
|
|
45
|
+
return { key, label: key, order: monday };
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Sturges' rule, the spreadsheet default: ⌈log2 n⌉ + 1 bins, at least 1. */
|
|
49
|
+
export function sturgesBins(n) {
|
|
50
|
+
return Math.max(1, Math.ceil(Math.log2(Math.max(1, n))) + 1);
|
|
51
|
+
}
|
|
52
|
+
function histogramKeyer(rows, column, bins) {
|
|
53
|
+
let min = Infinity;
|
|
54
|
+
let max = -Infinity;
|
|
55
|
+
let n = 0;
|
|
56
|
+
for (const row of rows) {
|
|
57
|
+
const v = row.values[column];
|
|
58
|
+
if (typeof v !== 'number' || !Number.isFinite(v))
|
|
59
|
+
continue;
|
|
60
|
+
n += 1;
|
|
61
|
+
if (v < min)
|
|
62
|
+
min = v;
|
|
63
|
+
if (v > max)
|
|
64
|
+
max = v;
|
|
65
|
+
}
|
|
66
|
+
// A saved spec can carry `bins: 0`; a non-positive count would produce
|
|
67
|
+
// negative indices and `-Infinity` labels, so clamp to at least one bin.
|
|
68
|
+
const count = Math.max(1, Math.floor(bins ?? sturgesBins(n)));
|
|
69
|
+
const width = n === 0 || max === min ? 1 : (max - min) / count;
|
|
70
|
+
const format = (x) => (Number.isInteger(x) ? String(x) : x.toFixed(2));
|
|
71
|
+
return (value) => {
|
|
72
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
73
|
+
return null;
|
|
74
|
+
// The max value lands in the last bin, not one past it.
|
|
75
|
+
const index = Math.min(count - 1, Math.floor((value - min) / width));
|
|
76
|
+
const lo = min + index * width;
|
|
77
|
+
const hi = index === count - 1 ? max : lo + width;
|
|
78
|
+
return { key: String(index), label: `${format(lo)}–${format(hi)}`, order: index };
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function keyerFor(spec, dataset, column) {
|
|
82
|
+
if (spec.type === 'histogram')
|
|
83
|
+
return histogramKeyer(dataset.rows, column, spec.bins);
|
|
84
|
+
if (spec.type === 'timeline')
|
|
85
|
+
return timelineKeyer();
|
|
86
|
+
return categoryKeyer();
|
|
87
|
+
}
|
|
88
|
+
function rowInSlice(row, slice) {
|
|
89
|
+
if (!slice)
|
|
90
|
+
return true;
|
|
91
|
+
const ids = row.ids;
|
|
92
|
+
for (let i = 0; i < ids.length; i++)
|
|
93
|
+
if (slice.has(ids[i]))
|
|
94
|
+
return true;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
function measureOf(row, spec, measureColumn) {
|
|
98
|
+
if (spec.measure.agg === 'count')
|
|
99
|
+
return 1;
|
|
100
|
+
const v = row.values[measureColumn];
|
|
101
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : 0;
|
|
102
|
+
}
|
|
103
|
+
function orderBuckets(accs, spec) {
|
|
104
|
+
const byLabel = spec.sort === 'label' || spec.type === 'histogram' || spec.type === 'timeline';
|
|
105
|
+
return [...accs].sort((a, b) => byLabel
|
|
106
|
+
? a.order - b.order || a.label.localeCompare(b.label)
|
|
107
|
+
: b.value - a.value || a.label.localeCompare(b.label));
|
|
108
|
+
}
|
|
109
|
+
/** Fold everything past `topN` into one `Other` bucket. Never for binned dimensions. */
|
|
110
|
+
function applyTopN(accs, spec) {
|
|
111
|
+
if (!spec.topN || spec.topN <= 0 || accs.length <= spec.topN)
|
|
112
|
+
return accs;
|
|
113
|
+
if (spec.type === 'histogram' || spec.type === 'timeline')
|
|
114
|
+
return accs;
|
|
115
|
+
const kept = accs.slice(0, spec.topN);
|
|
116
|
+
const other = { key: OTHER_BUCKET_KEY, label: OTHER_LABEL, value: 0, count: 0, ids: new Set(), order: Number.MAX_SAFE_INTEGER, isOther: true };
|
|
117
|
+
for (const acc of accs.slice(spec.topN)) {
|
|
118
|
+
other.value += acc.value;
|
|
119
|
+
other.count += acc.count;
|
|
120
|
+
for (const id of acc.ids)
|
|
121
|
+
other.ids.add(id);
|
|
122
|
+
}
|
|
123
|
+
kept.push(other);
|
|
124
|
+
return kept;
|
|
125
|
+
}
|
|
126
|
+
function toBucket(acc, color) {
|
|
127
|
+
return { key: acc.key, label: acc.label, value: acc.value, count: acc.count, ids: Uint32Array.from(acc.ids), color };
|
|
128
|
+
}
|
|
129
|
+
export function aggregate(spec, dataset, options = {}) {
|
|
130
|
+
const columnIndex = (id) => (id ? dataset.columns.findIndex((c) => c.id === id) : -1);
|
|
131
|
+
const dimension = columnIndex(spec.dimension);
|
|
132
|
+
if (dimension < 0)
|
|
133
|
+
throw new Error(`chart "${spec.id}": dimension column "${spec.dimension}" is not in the dataset`);
|
|
134
|
+
const measureColumn = spec.measure.agg === 'sum' ? columnIndex(spec.measure.column) : -1;
|
|
135
|
+
if (spec.measure.agg === 'sum' && measureColumn < 0) {
|
|
136
|
+
throw new Error(`chart "${spec.id}": measure column "${spec.measure.column ?? ''}" is not in the dataset`);
|
|
137
|
+
}
|
|
138
|
+
const stackColumn = spec.type === 'stackedBar' ? columnIndex(spec.stackBy) : -1;
|
|
139
|
+
const keyer = keyerFor(spec, dataset, dimension);
|
|
140
|
+
// categories: dimension key → accumulator (all series folded together, for ordering + ids)
|
|
141
|
+
const categories = new Map();
|
|
142
|
+
// series: stack key → (dimension key → accumulator)
|
|
143
|
+
const series = new Map();
|
|
144
|
+
let total = 0;
|
|
145
|
+
let unbucketed = 0;
|
|
146
|
+
const bump = (acc, row, measure) => {
|
|
147
|
+
acc.value += measure;
|
|
148
|
+
acc.count += 1;
|
|
149
|
+
for (let i = 0; i < row.ids.length; i++)
|
|
150
|
+
acc.ids.add(row.ids[i]);
|
|
151
|
+
};
|
|
152
|
+
for (const row of dataset.rows) {
|
|
153
|
+
if (!rowInSlice(row, options.slice))
|
|
154
|
+
continue;
|
|
155
|
+
const keyed = keyer(row.values[dimension]);
|
|
156
|
+
if (!keyed) {
|
|
157
|
+
unbucketed += 1;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const measure = measureOf(row, spec, measureColumn);
|
|
161
|
+
total += measure;
|
|
162
|
+
let cat = categories.get(keyed.key);
|
|
163
|
+
if (!cat) {
|
|
164
|
+
cat = { ...keyed, value: 0, count: 0, ids: new Set() };
|
|
165
|
+
categories.set(keyed.key, cat);
|
|
166
|
+
}
|
|
167
|
+
bump(cat, row, measure);
|
|
168
|
+
if (stackColumn >= 0) {
|
|
169
|
+
const raw = row.values[stackColumn];
|
|
170
|
+
const stackKey = raw === null || raw === undefined || raw === '' ? MISSING_KEY : String(raw);
|
|
171
|
+
let s = series.get(stackKey);
|
|
172
|
+
if (!s) {
|
|
173
|
+
s = { label: stackKey === MISSING_KEY ? '(none)' : stackKey, cells: new Map() };
|
|
174
|
+
series.set(stackKey, s);
|
|
175
|
+
}
|
|
176
|
+
let cell = s.cells.get(keyed.key);
|
|
177
|
+
if (!cell) {
|
|
178
|
+
cell = { ...keyed, value: 0, count: 0, ids: new Set() };
|
|
179
|
+
s.cells.set(keyed.key, cell);
|
|
180
|
+
}
|
|
181
|
+
bump(cell, row, measure);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const ordered = applyTopN(orderBuckets([...categories.values()], spec), spec);
|
|
185
|
+
const keptKeys = new Set(ordered.filter((o) => !o.isOther).map((o) => o.key));
|
|
186
|
+
const folded = new Set([...categories.keys()].filter((k) => !keptKeys.has(k)));
|
|
187
|
+
// Colours: a stacked bar keys colour by SERIES (the legend), a plain chart by
|
|
188
|
+
// category; the Other bucket always gets the neutral grey.
|
|
189
|
+
const colorLabels = stackColumn >= 0 ? [...series.values()].map((s) => s.label) : ordered.filter((o) => !o.isOther).map((o) => o.label);
|
|
190
|
+
const palette = assignColors(colorLabels, options.palette);
|
|
191
|
+
const colorFor = (acc) => (acc.isOther ? OTHER_BUCKET_COLOR : palette.colors.get(acc.label) ?? OTHER_BUCKET_COLOR);
|
|
192
|
+
const categoryBuckets = ordered.map((acc) => toBucket(acc, colorFor(acc)));
|
|
193
|
+
// An element can sit in several categories (a clash element under two
|
|
194
|
+
// rules, a task product in two tasks), so the reverse index keeps them all.
|
|
195
|
+
const categoryOf = new Map();
|
|
196
|
+
categoryBuckets.forEach((bucket, index) => {
|
|
197
|
+
for (let i = 0; i < bucket.ids.length; i++) {
|
|
198
|
+
const id = bucket.ids[i];
|
|
199
|
+
const list = categoryOf.get(id);
|
|
200
|
+
if (list)
|
|
201
|
+
list.push(index);
|
|
202
|
+
else
|
|
203
|
+
categoryOf.set(id, [index]);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
let seriesOut;
|
|
207
|
+
if (stackColumn >= 0) {
|
|
208
|
+
seriesOut = [...series.entries()].map(([stackKey, s]) => {
|
|
209
|
+
const color = palette.colors.get(s.label) ?? OTHER_BUCKET_COLOR;
|
|
210
|
+
const buckets = ordered.map((cat) => {
|
|
211
|
+
if (cat.isOther) {
|
|
212
|
+
// The Other column of this series: its cells for every folded category.
|
|
213
|
+
const other = { key: OTHER_BUCKET_KEY, label: OTHER_LABEL, value: 0, count: 0, ids: new Set(), order: 0, isOther: true };
|
|
214
|
+
for (const [k, cell] of s.cells)
|
|
215
|
+
if (folded.has(k)) {
|
|
216
|
+
other.value += cell.value;
|
|
217
|
+
other.count += cell.count;
|
|
218
|
+
for (const id of cell.ids)
|
|
219
|
+
other.ids.add(id);
|
|
220
|
+
}
|
|
221
|
+
return toBucket(other, color);
|
|
222
|
+
}
|
|
223
|
+
const cell = s.cells.get(cat.key);
|
|
224
|
+
return cell ? toBucket(cell, color) : { key: cat.key, label: cat.label, value: 0, count: 0, ids: new Uint32Array(0), color };
|
|
225
|
+
});
|
|
226
|
+
return { key: stackKey, label: s.label, buckets };
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
seriesOut = [{ key: spec.dimension, label: spec.title, buckets: categoryBuckets }];
|
|
231
|
+
}
|
|
232
|
+
const unit = measureColumn >= 0 ? dataset.columns[measureColumn].unit : undefined;
|
|
233
|
+
return { spec, categories: categoryBuckets, series: seriesOut, total, unbucketed, categoryOf, unit, palette };
|
|
234
|
+
}
|
|
235
|
+
/** The element ids behind a set of category indices — what a chart click selects in 3D. */
|
|
236
|
+
export function idsForCategories(aggregation, indices) {
|
|
237
|
+
const out = new Set();
|
|
238
|
+
for (const index of indices) {
|
|
239
|
+
const bucket = aggregation.categories[index];
|
|
240
|
+
if (!bucket)
|
|
241
|
+
continue;
|
|
242
|
+
for (let i = 0; i < bucket.ids.length; i++)
|
|
243
|
+
out.add(bucket.ids[i]);
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The category indices a 3D selection touches, with how much of each bucket
|
|
249
|
+
* is selected — `full` buckets are what a chart marks selected, `partial`
|
|
250
|
+
* ones what it emphasises.
|
|
251
|
+
*/
|
|
252
|
+
export function categoriesForIds(aggregation, ids) {
|
|
253
|
+
const hits = new Map();
|
|
254
|
+
for (const id of ids) {
|
|
255
|
+
const indices = aggregation.categoryOf.get(id);
|
|
256
|
+
if (!indices)
|
|
257
|
+
continue;
|
|
258
|
+
for (const index of indices)
|
|
259
|
+
hits.set(index, (hits.get(index) ?? 0) + 1);
|
|
260
|
+
}
|
|
261
|
+
const full = [];
|
|
262
|
+
const partial = [];
|
|
263
|
+
for (const [index, n] of hits) {
|
|
264
|
+
(n >= aggregation.categories[index].ids.length ? full : partial).push(index);
|
|
265
|
+
}
|
|
266
|
+
full.sort((a, b) => a - b);
|
|
267
|
+
partial.sort((a, b) => a - b);
|
|
268
|
+
return { full, partial };
|
|
269
|
+
}
|
|
270
|
+
/** The element ids behind a set of chart items: a stacked segment selects only its own series' share of the category. */
|
|
271
|
+
export function idsForItems(aggregation, items) {
|
|
272
|
+
const out = new Set();
|
|
273
|
+
for (const { seriesIndex, dataIndex } of items) {
|
|
274
|
+
const bucket = aggregation.series[seriesIndex]?.buckets[dataIndex];
|
|
275
|
+
if (!bucket)
|
|
276
|
+
continue;
|
|
277
|
+
for (let i = 0; i < bucket.ids.length; i++)
|
|
278
|
+
out.add(bucket.ids[i]);
|
|
279
|
+
}
|
|
280
|
+
return out;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* The chart items a 3D selection touches, per series: `full` items have every
|
|
284
|
+
* id selected, `partial` ones some. For a single-series chart this is
|
|
285
|
+
* {@link categoriesForIds} with `seriesIndex: 0`.
|
|
286
|
+
*/
|
|
287
|
+
export function itemsForIds(aggregation, ids) {
|
|
288
|
+
const selected = ids instanceof Set ? ids : new Set(ids);
|
|
289
|
+
const full = [];
|
|
290
|
+
const partial = [];
|
|
291
|
+
aggregation.series.forEach((series, seriesIndex) => {
|
|
292
|
+
series.buckets.forEach((bucket, dataIndex) => {
|
|
293
|
+
if (bucket.ids.length === 0)
|
|
294
|
+
return;
|
|
295
|
+
let hits = 0;
|
|
296
|
+
for (let i = 0; i < bucket.ids.length; i++)
|
|
297
|
+
if (selected.has(bucket.ids[i]))
|
|
298
|
+
hits += 1;
|
|
299
|
+
if (hits === 0)
|
|
300
|
+
return;
|
|
301
|
+
(hits === bucket.ids.length ? full : partial).push({ seriesIndex, dataIndex });
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
return { full, partial };
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=aggregate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An aggregation as an ECharts option.
|
|
3
|
+
*
|
|
4
|
+
* The option touches no DOM and holds no host state, so the same builder
|
|
5
|
+
* serves the on-screen canvas chart, the off-screen SVG export and a test
|
|
6
|
+
* that inspects the shape. Every series gets `selectedMode: 'multiple'` and an
|
|
7
|
+
* `emphasis.focus` blur so a click is a persistent selection the host can
|
|
8
|
+
* read back through `selectchanged`, and everything not selected fades the
|
|
9
|
+
* way the 3D view ghosts it.
|
|
10
|
+
*
|
|
11
|
+
* Colours come from the buckets (assigned by label in `aggregate`), never
|
|
12
|
+
* from ECharts' own palette, so the legend, the 3D overlay and the printed
|
|
13
|
+
* report agree.
|
|
14
|
+
*/
|
|
15
|
+
import type { Aggregation, ChartItem } from './types.js';
|
|
16
|
+
/** The tokens a host reads off its stylesheet; ECharts has no CSS variables. */
|
|
17
|
+
export interface ChartTheme {
|
|
18
|
+
text: string;
|
|
19
|
+
mutedText: string;
|
|
20
|
+
axis: string;
|
|
21
|
+
grid: string;
|
|
22
|
+
background: string;
|
|
23
|
+
fontFamily: string;
|
|
24
|
+
}
|
|
25
|
+
export declare const DEFAULT_THEME: ChartTheme;
|
|
26
|
+
export interface BuildOptionArgs {
|
|
27
|
+
aggregation: Aggregation;
|
|
28
|
+
theme?: ChartTheme;
|
|
29
|
+
/** Items to mark selected (ECharts `select` state); a number is a category index on every series. */
|
|
30
|
+
selected?: ReadonlyArray<number | ChartItem>;
|
|
31
|
+
/** Show the title inside the chart; a host card usually draws its own. */
|
|
32
|
+
showTitle?: boolean;
|
|
33
|
+
/** Width available to the chart in px; sizes the category labels so none is dropped. */
|
|
34
|
+
width?: number;
|
|
35
|
+
}
|
|
36
|
+
/** A plain-object ECharts option; typed loosely so this module needs no ECharts import. */
|
|
37
|
+
export type EChartsOptionObject = Record<string, unknown>;
|
|
38
|
+
/** Opacity of the buckets outside a selection, so the selected ones read at a glance. */
|
|
39
|
+
export declare const UNSELECTED_OPACITY = 0.35;
|
|
40
|
+
export declare function buildEChartsOption(args: BuildOptionArgs): EChartsOptionObject;
|
|
41
|
+
//# sourceMappingURL=echarts-option.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echarts-option.d.ts","sourceRoot":"","sources":["../src/echarts-option.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,WAAW,EAAU,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjE,gFAAgF;AAChF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,UAO3B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,qGAAqG;IACrG,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,2FAA2F;AAC3F,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsB1D,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AA0BvC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,mBAAmB,CAyF7E"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export const DEFAULT_THEME = {
|
|
5
|
+
text: '#1f2933',
|
|
6
|
+
mutedText: '#6b7280',
|
|
7
|
+
axis: '#9ca3af',
|
|
8
|
+
grid: '#e5e7eb',
|
|
9
|
+
background: 'transparent',
|
|
10
|
+
fontFamily: 'system-ui, sans-serif',
|
|
11
|
+
};
|
|
12
|
+
/** Fallback width when the host has not measured yet. */
|
|
13
|
+
const DEFAULT_WIDTH = 600;
|
|
14
|
+
function formatValue(value, unit) {
|
|
15
|
+
const text = Number.isInteger(value) ? String(value) : value.toFixed(2);
|
|
16
|
+
return unit ? `${text} ${unit}` : text;
|
|
17
|
+
}
|
|
18
|
+
function measureLabel(aggregation) {
|
|
19
|
+
const { measure } = aggregation.spec;
|
|
20
|
+
return measure.agg === 'count' ? 'Count' : `Sum of ${measure.column ?? ''}`;
|
|
21
|
+
}
|
|
22
|
+
/** Selected flags for one series: category indices apply to every series, items only to their own. */
|
|
23
|
+
function selectedFlags(count, seriesIndex, selected) {
|
|
24
|
+
const flags = new Array(count).fill(false);
|
|
25
|
+
for (const sel of selected ?? []) {
|
|
26
|
+
const i = typeof sel === 'number' ? sel : sel.seriesIndex === seriesIndex ? sel.dataIndex : -1;
|
|
27
|
+
if (i >= 0 && i < count)
|
|
28
|
+
flags[i] = true;
|
|
29
|
+
}
|
|
30
|
+
return flags;
|
|
31
|
+
}
|
|
32
|
+
/** Opacity of the buckets outside a selection, so the selected ones read at a glance. */
|
|
33
|
+
export const UNSELECTED_OPACITY = 0.35;
|
|
34
|
+
function itemData(buckets, flags) {
|
|
35
|
+
const dimOthers = flags.some(Boolean);
|
|
36
|
+
return buckets.map((b, i) => ({
|
|
37
|
+
name: b.label,
|
|
38
|
+
value: b.value,
|
|
39
|
+
itemStyle: dimOthers && !flags[i] ? { color: b.color, opacity: UNSELECTED_OPACITY } : { color: b.color },
|
|
40
|
+
selected: flags[i],
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
function barSeries(aggregation, selected, stacked) {
|
|
44
|
+
return aggregation.series.map((s, seriesIndex) => ({
|
|
45
|
+
type: 'bar',
|
|
46
|
+
name: s.label,
|
|
47
|
+
stack: stacked ? 'total' : undefined,
|
|
48
|
+
data: itemData(s.buckets, selectedFlags(s.buckets.length, seriesIndex, selected)),
|
|
49
|
+
selectedMode: 'multiple',
|
|
50
|
+
select: { itemStyle: { borderColor: '#000', borderWidth: 2 } },
|
|
51
|
+
emphasis: { focus: 'self' },
|
|
52
|
+
itemStyle: stacked ? { color: s.buckets[0]?.color } : undefined,
|
|
53
|
+
large: true,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
export function buildEChartsOption(args) {
|
|
57
|
+
const { aggregation, selected } = args;
|
|
58
|
+
const theme = args.theme ?? DEFAULT_THEME;
|
|
59
|
+
const { spec, categories } = aggregation;
|
|
60
|
+
const flags = selectedFlags(categories.length, 0, selected);
|
|
61
|
+
const unit = spec.measure.agg === 'sum' ? aggregation.unit : undefined;
|
|
62
|
+
const base = {
|
|
63
|
+
backgroundColor: theme.background,
|
|
64
|
+
textStyle: { color: theme.text, fontFamily: theme.fontFamily },
|
|
65
|
+
// Only components that are actually used may appear as keys: ECharts
|
|
66
|
+
// reports an `undefined` `title` as a missing TitleComponent.
|
|
67
|
+
...(args.showTitle ? { title: { text: spec.title, left: 'center', textStyle: { color: theme.text, fontSize: 13 } } } : {}),
|
|
68
|
+
tooltip: { trigger: 'item', valueFormatter: (v) => formatValue(v, unit) },
|
|
69
|
+
animation: false,
|
|
70
|
+
};
|
|
71
|
+
if (spec.type === 'pie') {
|
|
72
|
+
return {
|
|
73
|
+
...base,
|
|
74
|
+
legend: { type: 'scroll', orient: 'vertical', right: 0, top: 'middle', textStyle: { color: theme.mutedText } },
|
|
75
|
+
series: [{
|
|
76
|
+
type: 'pie',
|
|
77
|
+
name: measureLabel(aggregation),
|
|
78
|
+
radius: ['35%', '70%'],
|
|
79
|
+
center: ['40%', '50%'],
|
|
80
|
+
// An empty dataset shows the host's message, not a grey placeholder ring.
|
|
81
|
+
showEmptyCircle: false,
|
|
82
|
+
data: itemData(categories, flags),
|
|
83
|
+
selectedMode: 'multiple',
|
|
84
|
+
selectedOffset: 6,
|
|
85
|
+
emphasis: { focus: 'self' },
|
|
86
|
+
label: { color: theme.mutedText, formatter: '{b}' },
|
|
87
|
+
}],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (spec.type === 'treemap') {
|
|
91
|
+
return {
|
|
92
|
+
...base,
|
|
93
|
+
series: [{
|
|
94
|
+
type: 'treemap',
|
|
95
|
+
name: measureLabel(aggregation),
|
|
96
|
+
roam: false,
|
|
97
|
+
nodeClick: false,
|
|
98
|
+
breadcrumb: { show: false },
|
|
99
|
+
data: itemData(categories, flags),
|
|
100
|
+
selectedMode: 'multiple',
|
|
101
|
+
emphasis: { focus: 'self' },
|
|
102
|
+
label: { color: '#fff' },
|
|
103
|
+
}],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// bar / stackedBar / histogram / timeline: category x, measure y
|
|
107
|
+
const stacked = spec.type === 'stackedBar';
|
|
108
|
+
const labels = categories.map((c) => c.label);
|
|
109
|
+
// Long IFC class names ("IfcBuildingElementProxy") would collide upright
|
|
110
|
+
// and `hideOverlap` would then drop a neighbour outright. Each label gets
|
|
111
|
+
// its share of the width and is truncated with an ellipsis instead — the
|
|
112
|
+
// full name is in the tooltip and the legend. Past eight buckets the
|
|
113
|
+
// shares are too narrow to read, so the labels tilt.
|
|
114
|
+
const share = Math.floor((args.width ?? DEFAULT_WIDTH) / Math.max(1, categories.length)) - 6;
|
|
115
|
+
const rotate = categories.length > 8 ? 30 : 0;
|
|
116
|
+
// Tilted labels overlap far less, so they may run past their share.
|
|
117
|
+
const labelWidth = rotate ? Math.max(60, share * 2) : Math.max(36, share);
|
|
118
|
+
// A count needs no axis title; a sum says what it sums, and gets room for it.
|
|
119
|
+
const yName = spec.measure.agg === 'sum' ? measureLabel(aggregation) : '';
|
|
120
|
+
return {
|
|
121
|
+
...base,
|
|
122
|
+
// ECharts 6 keeps axis labels inside the grid's outer bounds by default
|
|
123
|
+
// (`containLabel` is the removed v5 way of saying the same).
|
|
124
|
+
grid: { left: 8, right: 8, top: stacked ? 32 : yName ? 28 : 12, bottom: 8 },
|
|
125
|
+
...(stacked ? { legend: { top: 0, textStyle: { color: theme.mutedText } } } : {}),
|
|
126
|
+
xAxis: {
|
|
127
|
+
type: 'category',
|
|
128
|
+
data: labels,
|
|
129
|
+
axisLine: { lineStyle: { color: theme.axis } },
|
|
130
|
+
axisLabel: { color: theme.mutedText, interval: 0, rotate, width: labelWidth, overflow: 'truncate', hideOverlap: true },
|
|
131
|
+
},
|
|
132
|
+
yAxis: {
|
|
133
|
+
type: 'value',
|
|
134
|
+
name: yName,
|
|
135
|
+
nameTextStyle: { color: theme.mutedText },
|
|
136
|
+
axisLabel: { color: theme.mutedText },
|
|
137
|
+
splitLine: { lineStyle: { color: theme.grid } },
|
|
138
|
+
},
|
|
139
|
+
series: barSeries(aggregation, selected, stacked),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=echarts-option.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echarts-option.js","sourceRoot":"","sources":["../src/echarts-option.ts"],"names":[],"mappings":"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"}
|