@peter.prib/renderengine 0.15.1 → 0.15.3
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/dist/renderengine-workspace.umd.js +6485 -3992
- package/dist/renderengine.umd.js +6251 -3877
- package/documentation/REFERENCE.md +384 -28
- package/package.json +1 -1
- package/src/archimateArchiFormat.js +114 -10
- package/src/archimateArchive.js +27 -4
- package/src/archimateExchangeFormat.js +12 -4
- package/src/archimateSpecializations.js +11 -1
- package/src/chartCatalog.js +6 -4
- package/src/charting/ArchimateDiagramEditor.js +7 -109
- package/src/charting/DiagramTypeRegistry.js +20 -1
- package/src/charting/DiagramViewPropertiesDialog.js +54 -10
- package/src/charting/Edge.js +22 -0
- package/src/charting/Legend.js +1 -2
- package/src/charting/Statistics.js +14 -0
- package/src/charting/archimate/ArchimateCanvasEditor.js +21 -5
- package/src/charting/archimate/ViewGroupTemplate.js +5 -2
- package/src/charting/charts/BarChart.js +59 -8
- package/src/charting/charts/HexbinChart.js +15 -0
- package/src/charting/charts/LollipopChart.js +42 -7
- package/src/charting/decision/DecisionWorkbench.js +71 -4
- package/src/charting/diagramModel/DiagramJsonFileFormat.js +32 -0
- package/src/charting/diagramModel/DiagramModel.js +39 -0
- package/src/charting/diagramModel/DiagramView.js +102 -61
- package/src/charting/diagramModel/index.js +11 -10
- package/src/charting/diagrams/AddGroupToViewCommand.js +35 -0
- package/src/charting/diagrams/ArchimateModel.js +53 -13
- package/src/charting/diagrams/GraphDiagram3D.js +15 -0
- package/src/charting/diagrams/NestInstanceCommand.js +2 -1
- package/src/charting/graph/GraphSource.js +72 -0
- package/src/charting/modelTree/NavigatorModel.js +22 -8
- package/src/charting/report/TemplatedReport.js +27 -377
- package/src/charting/report/ViewsReport.js +118 -0
- package/src/charting/report/reportWriters.js +496 -0
- package/src/charting/templates/C4BoundaryTemplate.js +34 -0
- package/src/charting/templates/C4ComponentTemplate.js +30 -0
- package/src/charting/templates/C4ContainerTemplate.js +49 -0
- package/src/charting/templates/C4PersonTemplate.js +35 -0
- package/src/charting/templates/C4SystemTemplate.js +32 -0
- package/src/charting/templates/C4Template.js +95 -0
- package/src/charting/templates/index.js +6 -0
- package/src/charting/templates/templateRegistry.js +77 -0
- package/src/compute/ComputeBackend.js +132 -0
- package/src/compute/CpuBackend.js +209 -0
- package/src/compute/WebGpuBackend.js +630 -0
- package/src/compute/index.js +5 -0
- package/src/compute/selectBackend.js +85 -0
- package/src/index.js +3403 -3370
- package/src/kernelExpr.js +80 -5
- package/src/workspace/parts/ArchimateEditorPart.js +2 -2
- package/src/workspace/parts/DiagramEditorPart.js +146 -131
- package/src/workspace/parts/ViewsPart.js +106 -0
|
@@ -104,6 +104,31 @@ catalog `key` for you.
|
|
|
104
104
|
| `wordCloud` | `wordCloud(data, opts)` | `Array<{text: string, value: number}>` | spiral placement + bounding-box collision; `minFontSize`, `maxFontSize`, `padding` |
|
|
105
105
|
| `parallelCoordinates` | `parallelCoordinates(data, opts)` | `Array<{label?, category?, [dim: number]}>` | one vertical axis per numeric dimension; category-driven colors; `dimensions` |
|
|
106
106
|
| `geoMap` | `geoMap(data, opts)` | `{features: Array<{id, name, value?, color?, geometry}>, bubbles?: Array<{lat, lon, value}>}` | equirectangular projection; `center`, `scale`, `colorScale`; see note below |
|
|
107
|
+
| `polarArea` | `polarAreaChart(data, opts)` | `Array<{label, value, exploded?}>` | Nightingale rose equal-angle wedges; `scale: 'radius'|'area'`, `extrude3D`, `depth`, `innerRadiusRatio` |
|
|
108
|
+
| `pie3D` | `pieChart3D(data, opts)` | `Array<{label, value}>` | isometric 3D pie; `depth`, `tilt`, `exploded`, `colors` |
|
|
109
|
+
| `donut3D` | `donutChart3D(data, opts)` | `Array<{label, value}>` | isometric 3D donut; `innerRadiusRatio`, `depth`, `tilt` |
|
|
110
|
+
| `pareto` | `paretoChart(data, opts)` | `Array<{label, value}>` | sorted descending bars with cumulative percentage line (80/20 rule); `barColor`, `lineColor` |
|
|
111
|
+
| `lollipop` | `lollipopChart(data, opts)` | `Array<{label, value}>` | stem with circular point markers; `orientation: 'vertical'|'horizontal'`, `pointRadius` |
|
|
112
|
+
| `marimekko` | `marimekkoChart(data, opts)` | `Array<{name, values: Array<{label, value}>}>` | 2D mosaic chart where both bar width and height encode values |
|
|
113
|
+
| `icicle` | `icicleChart(data, opts)` | `Array<{label, value?, children?}>` | hierarchical partition chart laying out tree levels as rectangular blocks; `orientation` |
|
|
114
|
+
| `dumbbell` | `dumbbellChart(data, opts)` | `Array<{label, start, end}>` or multi-series `Array<{name, values}>` | connected pair of dots showing change across categories; `colorByDelta`, `showDeltas`, `orientation` |
|
|
115
|
+
| `slopegraph` | `slopegraph(data, opts)` | `Array<{label, values: number[]}>` or `Array<{label, start, end}>` | connects categories across stages with direct labels; `stageLabels`, `collisionAvoidance` |
|
|
116
|
+
| `circlePack` | `circlePackChart(data, opts)` | `Array<{label, value?, children?}>` | nested tangent circles sized by value with translucent branch containment; `padding` |
|
|
117
|
+
| `ridgeline` | `ridgelineChart(data, opts)` | `Array<{label, values: number[]}>` | vertically staggered, overlapping Gaussian-KDE density curves (Joy plot); `overlap`, `showMedian` |
|
|
118
|
+
| `beeswarm` | `beeswarmChart(data, opts)` | `Array<{label, values: number[]}>` | packed individual sample points along category slots; `mode: 'beeswarm'|'raincloud'`, `radius` |
|
|
119
|
+
| `combo` | `comboChart(data, opts)` | multi-series with type specifications | composite multi-series chart combining bars, lines, and area layers on primary/secondary axes |
|
|
120
|
+
| `hexbin` | `hexbinChart(data, opts)` | `Array<{x, y, value?}>` or `Array<[x, y]>` | 2D hexagonal density binning for large scatter clouds; `radius`, `minCount`, `colorScale` |
|
|
121
|
+
| `ecdf` | `ecdfChart(data, opts)` | `number[]` or `Array<{label, values: number[]}>` | empirical cumulative distribution step function (0..1); `showMedian`, `showQuantiles`, `step` |
|
|
122
|
+
| `splom` | `scatterMatrixChart(data, opts)` | `Array<object>` with numeric dimensions | scatter plot matrix of pairwise bivariate relationships; `dimensions`, `colorCol` |
|
|
123
|
+
| `sparklineTable` | `sparklineTableChart(data, opts)` | `Array<{label, values: number[], current?, change?}>` | data table with embedded inline trendline sparklines; `columns` |
|
|
124
|
+
| `horizon` | `horizonChart(data, opts)` | `Array<{label, values: number[]}>` | compact layered area strips folding positive and negative magnitude bands; `bands`, `posColors` |
|
|
125
|
+
| `ohlc` | `ohlcChart(data, opts)` | `Array<{label, open, high, low, close}>` | Open-High-Low-Close financial bar chart; `upColor`, `downColor` |
|
|
126
|
+
| `alluvial` | `alluvialDiagram(data, opts)` | `{dimensions: string[], rows: Array<object>}` or `Array<{steps, value}>` | multi-stage categorical flow diagram across ordered dimensions; `nodeWidth`, `curvature` |
|
|
127
|
+
| `renko` | `renkoChart(data, opts)` | `number[]` or `Array<{label, close}>` | brick-based trend-filtering chart filtering out time noise; `brickSize` |
|
|
128
|
+
| `contour` | `contourChart(data, opts)` | `number[][]` (2D scalar grid) or `Array<{x, y, value}>` | marching-squares isolines and filled isoband contours; `levels`, `filled`, `showLines` |
|
|
129
|
+
| `kagi` | `kagiChart(data, opts)` | `number[]` or `Array<{label, close}>` | trend reversal chart with alternating line thickness; `reversalAmount` |
|
|
130
|
+
| `pointAndFigure` | `pointAndFigureChart(data, opts)` | `number[]` or `Array<{label, close}>` | columns of X's (rising) and O's (falling); `boxSize`, `reversal` |
|
|
131
|
+
| `surface3D` | `surfaceChart3D(data, opts)` | `Array<{x, z, value}>` or `{xLabels, zLabels, values}` | continuous 3D surface mesh with gradient height coloring, wireframe, and orbit camera |
|
|
107
132
|
|
|
108
133
|
**Gauges.** Every gauge is a `GaugeChart` (`src/charting/charts/GaugeChart.js`) and takes the same options:
|
|
109
134
|
|
|
@@ -1340,6 +1365,278 @@ SVG each mark answers a click with `{ label, series }`.
|
|
|
1340
1365
|
engine.barChart(data, { onDatumClick: ({ label }) => openDetail(label) });
|
|
1341
1366
|
```
|
|
1342
1367
|
|
|
1368
|
+
## Advanced Statistical, Flow, Distribution & 3D Charts
|
|
1369
|
+
|
|
1370
|
+
Specialized charts designed for dense distributions, multi-stage transitions, continuous terrains, and flow modeling.
|
|
1371
|
+
|
|
1372
|
+
### Dumbbell / Gap Chart — `dumbbellChart(data, options)`
|
|
1373
|
+
|
|
1374
|
+
A connected pair of dots per category showing before/after, actual/target, or interval comparisons without the visual clutter of clustered bars.
|
|
1375
|
+
|
|
1376
|
+
- **Data shapes:**
|
|
1377
|
+
- `Array<{label: string, start: number, end: number}>`
|
|
1378
|
+
- Multi-series `Array<{name: string, values: Array<{label: string, value: number}>}>` (first two series used as start and end)
|
|
1379
|
+
- **Notable options:**
|
|
1380
|
+
- `orientation`: `'horizontal'` (default) or `'vertical'`.
|
|
1381
|
+
- `colorByDelta`: `true` to color connectors and endpoints by direction of change (green for gain, red for loss).
|
|
1382
|
+
- `startColor`, `endColor`: Custom endpoint colors when `colorByDelta` is false.
|
|
1383
|
+
- `upColor`, `downColor`, `neutralColor`: Colors used when `colorByDelta: true`.
|
|
1384
|
+
- `showDeltas`: `true` to render direct delta badges (e.g. `+12%`, `-5`) next to the endpoints.
|
|
1385
|
+
- `showValues`: `true` to render numeric value labels at dots.
|
|
1386
|
+
- `pointRadius`: Radius of endpoint circles in pixels (default `5`).
|
|
1387
|
+
- `startLabel`, `endLabel`: Custom legend labels for the start and end series.
|
|
1388
|
+
|
|
1389
|
+
```javascript
|
|
1390
|
+
engine.dumbbellChart([
|
|
1391
|
+
{ label: 'Latency', start: 240, end: 110 },
|
|
1392
|
+
{ label: 'Throughput', start: 850, end: 1420 },
|
|
1393
|
+
{ label: 'Error Rate', start: 4.2, end: 0.8 },
|
|
1394
|
+
], { colorByDelta: true, showDeltas: true, showValues: true });
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
### Slopegraph — `slopegraph(data, options)`
|
|
1398
|
+
|
|
1399
|
+
Connects categories across two or more discrete stages or time points to highlight hierarchy shifts, rate-of-change differences, and rank reversals.
|
|
1400
|
+
|
|
1401
|
+
- **Data shapes:**
|
|
1402
|
+
- `Array<{label: string, values: number[]}>` (multi-stage trajectory)
|
|
1403
|
+
- `Array<{label: string, start: number, end: number}>` (2-stage before/after)
|
|
1404
|
+
- **Notable options:**
|
|
1405
|
+
- `stageLabels`: Array of column headings for the stages (e.g. `['2024', '2025', '2026']`).
|
|
1406
|
+
- `showDirectLabels`: `true` (default) to label line endpoints directly, avoiding an external legend.
|
|
1407
|
+
- `labelSide`: `'both'` (default), `'left'`, or `'right'`.
|
|
1408
|
+
- `collisionAvoidance`: `true` (default) to run iterative vertical relaxation preventing overlapping text labels on crowded axes.
|
|
1409
|
+
- `lineWidth`: Stroke width of trajectory lines (default `2`).
|
|
1410
|
+
- `pointRadius`: Radius of dots at each stage (default `4`).
|
|
1411
|
+
- `highlightOnHover`: `true` (default) to dim competing lines on cursor hover.
|
|
1412
|
+
|
|
1413
|
+
```javascript
|
|
1414
|
+
engine.slopegraph([
|
|
1415
|
+
{ label: 'Product Alpha', values: [12, 19, 28] },
|
|
1416
|
+
{ label: 'Product Beta', values: [24, 21, 15] },
|
|
1417
|
+
{ label: 'Product Gamma', values: [8, 14, 22] },
|
|
1418
|
+
], { stageLabels: ['Q1', 'Q2', 'Q3'], showDirectLabels: true });
|
|
1419
|
+
```
|
|
1420
|
+
|
|
1421
|
+
### Ridgeline Plot (Joy Plot) — `ridgelineChart(data, options)`
|
|
1422
|
+
|
|
1423
|
+
Vertically staggered, partially overlapping Gaussian kernel density estimates (KDE) across multiple ordered or categorical groups. Ideal for comparing distributions over time or stages in compact vertical space.
|
|
1424
|
+
|
|
1425
|
+
- **Data shape:** `Array<{label: string, values: number[]}>` (raw sample observations per group).
|
|
1426
|
+
- **Notable options:**
|
|
1427
|
+
- `overlap`: Vertical overlap ratio between adjacent ridges (default `0.65`; `0` = non-overlapping rows, `1.0` = high overlap).
|
|
1428
|
+
- `fillOpacity`: Opacity of the filled ridge area under each density curve (default `0.74`).
|
|
1429
|
+
- `showMedian`: `true` (default) to draw vertical line ticks at each group's sample median.
|
|
1430
|
+
- `medianColor`: Color of the median tick indicator (default `'#ffffff'`).
|
|
1431
|
+
- `colors`: Palette array for ridges, or auto-assigned from workspace theme.
|
|
1432
|
+
|
|
1433
|
+
```javascript
|
|
1434
|
+
engine.ridgelineChart([
|
|
1435
|
+
{ label: 'Sprint 1', values: [14, 18, 22, 25, 27, 28, 30, 35, 42] },
|
|
1436
|
+
{ label: 'Sprint 2', values: [10, 12, 15, 18, 20, 22, 24, 26, 29] },
|
|
1437
|
+
{ label: 'Sprint 3', values: [8, 9, 11, 14, 16, 17, 18, 20, 22] },
|
|
1438
|
+
], { overlap: 0.7, showMedian: true });
|
|
1439
|
+
```
|
|
1440
|
+
|
|
1441
|
+
### Beeswarm & Raincloud Plot — `beeswarmChart(data, options)`
|
|
1442
|
+
|
|
1443
|
+
Plots every individual observation as a non-overlapping circle packed tightly along a category axis without jitter noise. Raincloud mode pairs the packed dot cloud with a half-KDE density violin and a compact box plot.
|
|
1444
|
+
|
|
1445
|
+
- **Data shape:** `Array<{label: string, values: number[]}>` (raw sample numbers per group).
|
|
1446
|
+
- **Notable options:**
|
|
1447
|
+
- `mode`: `'beeswarm'` (default; centered packed point swarm) or `'raincloud'` (half-violin cloud + box plot + offset swarm).
|
|
1448
|
+
- `radius`: Radius of each observation dot (default `3.5`).
|
|
1449
|
+
- `padding`: Minimum pixel gap between adjacent packed points (default `1`).
|
|
1450
|
+
- `halfViolin`: In raincloud mode, draws upper density envelope (default `true`).
|
|
1451
|
+
- `boxPlot`: In raincloud mode, draws embedded quartiles and median bar (default `true`).
|
|
1452
|
+
- `colors`: Array of categorical colors per group.
|
|
1453
|
+
|
|
1454
|
+
```javascript
|
|
1455
|
+
engine.beeswarmChart([
|
|
1456
|
+
{ label: 'Control', values: [2.1, 2.4, 2.5, 2.7, 2.9, 3.1, 3.2, 3.6, 4.0] },
|
|
1457
|
+
{ label: 'Treatment', values: [3.2, 3.5, 3.8, 4.1, 4.2, 4.5, 4.8, 5.2, 5.9] },
|
|
1458
|
+
], { mode: 'raincloud', radius: 4 });
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
### Empirical Cumulative Distribution Function — `ecdfChart(data, options)`
|
|
1462
|
+
|
|
1463
|
+
Draws exact empirical step CDFs \(P(X \le x)\) from 0 to 1, comparing distributions without bin-width artifacts. Includes automated Kolmogorov-Smirnov distance calculations.
|
|
1464
|
+
|
|
1465
|
+
- **Data shapes:**
|
|
1466
|
+
- `number[]` (single sample)
|
|
1467
|
+
- `Array<{label: string, values: number[]}>` (multi-group comparison)
|
|
1468
|
+
- **Notable options:**
|
|
1469
|
+
- `showMedian`: `true` (default) to project dashed 50th-percentile lines to axes.
|
|
1470
|
+
- `showQuantiles`: `true` to annotate 25th, 50th, and 75th percentile markers.
|
|
1471
|
+
- `step`: Step interpolation style (`'vh'` default: vertical-then-horizontal, or `'hv'`).
|
|
1472
|
+
- `compare`: When two series are supplied, calculates and highlights the maximum vertical distance \(D_{KS}\) (`EcdfChart.ksDistance(s1, s2)`).
|
|
1473
|
+
- `colors`: Palette array for series steps.
|
|
1474
|
+
|
|
1475
|
+
```javascript
|
|
1476
|
+
engine.ecdfChart([
|
|
1477
|
+
{ label: 'Algorithm A', values: [12, 15, 18, 22, 25, 29, 34, 40] },
|
|
1478
|
+
{ label: 'Algorithm B', values: [8, 11, 14, 16, 19, 21, 24, 28] },
|
|
1479
|
+
], { showMedian: true, compare: true });
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1482
|
+
### Hexagonal 2D Density Binning — `hexbinChart(data, options)`
|
|
1483
|
+
|
|
1484
|
+
Aggregates dense 2D scatter coordinate clouds into regular hexagonal tiles, preventing visual saturation and overplotting in large point datasets.
|
|
1485
|
+
|
|
1486
|
+
- **Data shapes:**
|
|
1487
|
+
- `Array<{x: number, y: number, value?: number}>`
|
|
1488
|
+
- `Array<[x: number, y: number]>`
|
|
1489
|
+
- **Notable options:**
|
|
1490
|
+
- `radius`: Outer radius of each hexagon cell in pixels (default `14`).
|
|
1491
|
+
- `minCount`: Minimum point count threshold required to render a cell (default `1`).
|
|
1492
|
+
- `colorScale`: Sequential color palette array (e.g. `['#e0f3f8', '#67a9cf', '#02818a', '#bd0026']`).
|
|
1493
|
+
- `title`, `xAxisLabel`, `yAxisLabel`: Chart and axis labels.
|
|
1494
|
+
|
|
1495
|
+
```javascript
|
|
1496
|
+
const points = Array.from({ length: 5000 }, () => ({
|
|
1497
|
+
x: Math.random() * 100,
|
|
1498
|
+
y: Math.random() * 100,
|
|
1499
|
+
}));
|
|
1500
|
+
engine.hexbinChart(points, { radius: 12, minCount: 2 });
|
|
1501
|
+
```
|
|
1502
|
+
|
|
1503
|
+
### Horizon Chart — `horizonChart(data, options)`
|
|
1504
|
+
|
|
1505
|
+
Folds continuous time-series magnitude into 2 to 5 layered colored bands within a narrow vertical band (e.g. 30–50px), preserving high precision while displaying dozens of series simultaneously.
|
|
1506
|
+
|
|
1507
|
+
- **Data shape:** `Array<{label: string, values: number[]}>`
|
|
1508
|
+
- **Notable options:**
|
|
1509
|
+
- `bands`: Number of layered folding bands (default `3`).
|
|
1510
|
+
- `posColors`: Color gradient array for positive values (default 3-stage blues).
|
|
1511
|
+
- `negColors`: Color gradient array for negative values (default 3-stage reds).
|
|
1512
|
+
- `title`: Chart title.
|
|
1513
|
+
|
|
1514
|
+
```javascript
|
|
1515
|
+
engine.horizonChart([
|
|
1516
|
+
{ label: 'CPU Core 0', values: [10, 25, 45, 80, 95, 60, 40, 30] },
|
|
1517
|
+
{ label: 'CPU Core 1', values: [-15, 20, 50, 70, 85, 45, 20, -10] },
|
|
1518
|
+
], { bands: 3 });
|
|
1519
|
+
```
|
|
1520
|
+
|
|
1521
|
+
### Circle Packing — `circlePackChart(data, options)`
|
|
1522
|
+
|
|
1523
|
+
Represents hierarchical tree structures as nested tangent circles sized by value, with translucent ancestor boundary rings and hover elevation.
|
|
1524
|
+
|
|
1525
|
+
- **Data shape:** Hierarchical tree `Array<{label: string, value?: number, children?: Array}>`
|
|
1526
|
+
- **Notable options:**
|
|
1527
|
+
- `padding`: Pixel gap between tangent sibling circles (default `2`).
|
|
1528
|
+
- `showLabels`: `true` (default) to label circles that have sufficient interior area.
|
|
1529
|
+
- `minLabelRadius`: Minimum circle radius in pixels required to render text inside (default `14`).
|
|
1530
|
+
- `colors`: Palette array mapped across top-level tree branches.
|
|
1531
|
+
|
|
1532
|
+
```javascript
|
|
1533
|
+
engine.circlePackChart([{
|
|
1534
|
+
label: 'Architecture',
|
|
1535
|
+
children: [
|
|
1536
|
+
{ label: 'Backend', children: [{ label: 'API', value: 40 }, { label: 'DB', value: 30 }] },
|
|
1537
|
+
{ label: 'Frontend', children: [{ label: 'Web', value: 25 }, { label: 'Mobile', value: 15 }] },
|
|
1538
|
+
],
|
|
1539
|
+
}], { padding: 4 });
|
|
1540
|
+
```
|
|
1541
|
+
|
|
1542
|
+
### Alluvial Diagram — `alluvialDiagram(data, options)`
|
|
1543
|
+
|
|
1544
|
+
Visualizes categorical flows across three or more sequential dimensions using smooth cubic bezier ribbons whose widths represent flow volumes.
|
|
1545
|
+
|
|
1546
|
+
- **Data shapes:**
|
|
1547
|
+
- Multi-stage pathway list: `Array<{steps: string[], value: number}>`
|
|
1548
|
+
- Tabular rows: `{dimensions: string[], rows: Array<object>}`
|
|
1549
|
+
- Edge list: `Array<{source: string, target: string, value: number}>`
|
|
1550
|
+
- **Notable options:**
|
|
1551
|
+
- `dimensions`: Array of dimension stage names (e.g. `['Role', 'Department', 'Access Level']`).
|
|
1552
|
+
- `nodeWidth`: Width of category pillar rectangles in pixels (default `18`).
|
|
1553
|
+
- `nodePadding`: Vertical separation between category nodes (default `12`).
|
|
1554
|
+
- `curvature`: Bezier curvature ratio for flow links (default `0.5`).
|
|
1555
|
+
- `linkOpacity`: Fill opacity for flow ribbons (default `0.55`).
|
|
1556
|
+
- `colors`: Palette array for node categories.
|
|
1557
|
+
|
|
1558
|
+
```javascript
|
|
1559
|
+
engine.alluvialDiagram([
|
|
1560
|
+
{ steps: ['Engineering', 'Senior', 'Admin'], value: 12 },
|
|
1561
|
+
{ steps: ['Engineering', 'Junior', 'User'], value: 28 },
|
|
1562
|
+
{ steps: ['Product', 'Lead', 'Admin'], value: 5 },
|
|
1563
|
+
{ steps: ['Product', 'Analyst', 'User'], value: 15 },
|
|
1564
|
+
], { dimensions: ['Department', 'Seniority', 'Permission'] });
|
|
1565
|
+
```
|
|
1566
|
+
|
|
1567
|
+
### Polar Area (Nightingale Rose) — `polarAreaChart(data, options)`
|
|
1568
|
+
|
|
1569
|
+
Divides a circle into equal angular sectors where the radial distance (or area) of each sector represents its magnitude. Supports optional 3D isometric extrusion and interactive wedge pull-out.
|
|
1570
|
+
|
|
1571
|
+
- **Data shape:** `Array<{label: string, value: number, exploded?: boolean}>`
|
|
1572
|
+
- **Notable options:**
|
|
1573
|
+
- `scale`: `'radius'` (linear radial distance) or `'area'` (square-root scaling so slice area is proportional to value).
|
|
1574
|
+
- `extrude3D`: `true` to render as an isometric 3D cylindrical cylinder with depth shading.
|
|
1575
|
+
- `depth`: Extrusion height in pixels when `extrude3D: true` (default `22`).
|
|
1576
|
+
- `innerRadiusRatio`: Donut hole ratio (default `0.12`).
|
|
1577
|
+
- `padAngle`: Angular spacing between sectors in radians (default `0.02`).
|
|
1578
|
+
- `hoverExplode`: `true` to pull out wedges under the cursor.
|
|
1579
|
+
|
|
1580
|
+
```javascript
|
|
1581
|
+
engine.polarAreaChart([
|
|
1582
|
+
{ label: 'North', value: 45 },
|
|
1583
|
+
{ label: 'East', value: 80 },
|
|
1584
|
+
{ label: 'South', value: 35 },
|
|
1585
|
+
{ label: 'West', value: 60 },
|
|
1586
|
+
], { scale: 'area', extrude3D: true, depth: 25 });
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
### 3D Surface Mesh — `surfaceChart3D(data, options)`
|
|
1590
|
+
|
|
1591
|
+
Renders continuous 3D mathematical surfaces, terrain elevations, or 2D matrix loss landscapes using true 4×4 perspective transformations and interactive orbit camera rotation.
|
|
1592
|
+
|
|
1593
|
+
- **Data shapes:**
|
|
1594
|
+
- Regular grid: `{xLabels: string[]|number[], zLabels: string[]|number[], values: number[][]}`
|
|
1595
|
+
- Coordinate tuples: `Array<{x: string|number, z: string|number, value: number}>`
|
|
1596
|
+
- **Notable options:**
|
|
1597
|
+
- `wireframe`: `true` (default) to overlay contrasting grid lines on surface polygons.
|
|
1598
|
+
- `wireframeColor`: Stroke color for wireframe lines (default `'rgba(255,255,255,0.45)'`).
|
|
1599
|
+
- `colorScale`: Array of gradient color stops for height-based surface shading.
|
|
1600
|
+
- `initialTheta`, `initialPhi`, `initialDistance`: Initial camera angles and zoom distance.
|
|
1601
|
+
- Orbit interaction: Drag to rotate camera azimuth and elevation, mouse wheel to zoom in/out.
|
|
1602
|
+
|
|
1603
|
+
```javascript
|
|
1604
|
+
const xLabels = [-2, -1, 0, 1, 2];
|
|
1605
|
+
const zLabels = [-2, -1, 0, 1, 2];
|
|
1606
|
+
const values = xLabels.map(x => zLabels.map(z => Math.sin(Math.sqrt(x * x + z * z))));
|
|
1607
|
+
|
|
1608
|
+
engine.surfaceChart3D({ xLabels, zLabels, values }, {
|
|
1609
|
+
title: 'Bivariate Ripple Surface',
|
|
1610
|
+
wireframe: true,
|
|
1611
|
+
});
|
|
1612
|
+
```
|
|
1613
|
+
|
|
1614
|
+
### Contour Plot — `contourChart(data, options)`
|
|
1615
|
+
|
|
1616
|
+
Generates smooth isoline curves and filled isoband color regions from 2D scalar fields using the marching-squares algorithm with automated numeric elevation labels.
|
|
1617
|
+
|
|
1618
|
+
- **Data shapes:**
|
|
1619
|
+
- 2D scalar matrix: `number[][]` (rows × columns)
|
|
1620
|
+
- Coordinate list: `Array<{x: number, y: number, value: number}>`
|
|
1621
|
+
- **Notable options:**
|
|
1622
|
+
- `levels`: Number of contour threshold intervals (default `8`), or an explicit array of numbers `[0.1, 0.25, 0.5, 0.75]`.
|
|
1623
|
+
- `filled`: `true` (default) to render shaded polygon bands between isolines.
|
|
1624
|
+
- `showLines`: `true` (default) to stroke isoline boundaries.
|
|
1625
|
+
- `showLabels`: `true` (default) to annotate contour lines with numeric elevation values.
|
|
1626
|
+
- `colorScale`: Array of colors interpolated across contour levels.
|
|
1627
|
+
- `lineColor`: Stroke color for isolines (default `'rgba(0,0,0,0.3)'`).
|
|
1628
|
+
|
|
1629
|
+
```javascript
|
|
1630
|
+
const grid = [
|
|
1631
|
+
[0.1, 0.2, 0.4, 0.2, 0.1],
|
|
1632
|
+
[0.2, 0.6, 0.9, 0.6, 0.2],
|
|
1633
|
+
[0.4, 0.9, 1.0, 0.9, 0.4],
|
|
1634
|
+
[0.2, 0.6, 0.9, 0.6, 0.2],
|
|
1635
|
+
[0.1, 0.2, 0.4, 0.2, 0.1],
|
|
1636
|
+
];
|
|
1637
|
+
engine.contourChart(grid, { levels: 6, filled: true, showLabels: true });
|
|
1638
|
+
```
|
|
1639
|
+
|
|
1343
1640
|
## Common options
|
|
1344
1641
|
|
|
1345
1642
|
Not every method takes every option below — the table above calls out what's notable per type —
|
|
@@ -1523,10 +1820,10 @@ data — `addDataPoint` is a **no-op** when it's `'none'`:
|
|
|
1523
1820
|
|
|
1524
1821
|
| `streamShape` | Chart types | Behavior |
|
|
1525
1822
|
|---|---|---|
|
|
1526
|
-
| `flat` | `bar`, `pie`, `scatter`, `bubble`, `candlestick`, `stackedBar`, `funnel`, `waterfall`, `histogram`, `qq`, `lag`, `treemap`, `sunburst`, `outline`, `bar3D`, `bubble3D` | one new record appended to the outer array |
|
|
1527
|
-
| `series` | `line`, `area`, `pipe` | every series' own `values` grows by one point |
|
|
1528
|
-
| `grouped-sample` | `boxPlot`, `density`, `violin` | exactly ONE randomly-chosen group's `values` grows (a new sample observation belongs to one group, unlike a shared time axis) |
|
|
1529
|
-
| `none` | `heatmap`, `radar` (fixed matrix/axis-set), `bar3DOrbit`/`stackedBar3DOrbit` (fixed grid), `gauge-dial`/`gauge-bar`/`bullet` (a value to replace, not a window) | `addDataPoint` no-ops — for gauges, just call `dialGauge(newValue)`/`barGauge(newValue)`/`bulletGauge(newValue)` again directly |
|
|
1823
|
+
| `flat` | `bar`, `pie`, `scatter`, `bubble`, `candlestick`, `stackedBar`, `funnel`, `waterfall`, `histogram`, `qq`, `lag`, `treemap`, `sunburst`, `outline`, `bar3D`, `bubble3D`, `dumbbell`, `slopegraph`, `circlePack`, `horizon`, `polarArea`, `hexbin`, `pareto`, `lollipop` | one new record appended to the outer array |
|
|
1824
|
+
| `series` | `line`, `area`, `pipe`, `combo` | every series' own `values` grows by one point |
|
|
1825
|
+
| `grouped-sample` | `boxPlot`, `density`, `violin`, `ecdf`, `beeswarm`, `ridgeline` | exactly ONE randomly-chosen group's `values` grows (a new sample observation belongs to one group, unlike a shared time axis) |
|
|
1826
|
+
| `none` | `heatmap`, `radar` (fixed matrix/axis-set), `bar3DOrbit`/`stackedBar3DOrbit`/`surface3D` (fixed grid), `gauge-dial`/`gauge-bar`/`bullet` (a value to replace, not a window), `alluvial`, `contour`, `splom` | `addDataPoint` no-ops — for gauges, just call `dialGauge(newValue)`/`barGauge(newValue)`/`bulletGauge(newValue)` again directly |
|
|
1530
1827
|
|
|
1531
1828
|
### 2. Graphs — `addGraphNode`
|
|
1532
1829
|
|
|
@@ -2610,6 +2907,7 @@ new RectangleTemplate('r1', 'Billing', { fontFamily: 'Georgia', fontSize: '14pt'
|
|
|
2610
2907
|
| Boxes | `RectangleTemplate`, `RoundedRectangleTemplate`, `StadiumTemplate`, `PredefinedProcessTemplate`, `ClassTemplate`, `ComponentTemplate`, `SwimlaneTemplate`, `PackageTemplate`, `BoxTemplate` (3D) |
|
|
2611
2908
|
| Round | `CircleTemplate`, `EllipseTemplate`, `FinalStateTemplate`, `CloudTemplate` |
|
|
2612
2909
|
| Polygons | `DiamondTemplate`, `TriangleTemplate`, `PentagonTemplate`, `HexagonTemplate`, `OctagonTemplate`, `StarTemplate`, `ParallelogramTemplate`, `TrapezoidTemplate`, `ManualInputTemplate` |
|
|
2910
|
+
| C4 Architecture | `C4PersonTemplate`, `C4SystemTemplate`, `C4ContainerTemplate`, `C4ComponentTemplate`, `C4BoundaryTemplate` |
|
|
2613
2911
|
| Other | `CylinderTemplate`, `DocumentTemplate`, `NoteTemplate`, `DataStoreTemplate`, `ActorTemplate`, `LifelineTemplate` |
|
|
2614
2912
|
|
|
2615
2913
|
A template draws its outline in `shapeElements(doc)`, or in `points()` when it extends
|
|
@@ -2642,6 +2940,19 @@ empty canvas, or on the shape at the other end, cancels. This is one undo step
|
|
|
2642
2940
|
|
|
2643
2941
|
**Container nesting and hierarchy.** Shapes such as `PackageTemplate`, `SwimlaneTemplate`, and `BoxTemplate` are containers (`isContainer = true`). When an element is dropped inside a container (`nestsOnDrop(parentId, childId)`), it is parented via `NestElementCommand` (setting `child.parentId`). Moving a container recursively moves all nested descendants (`moversFor(templateId)`). Containers can automatically expand their bounds to fit their contents via `fitNesting(changes, { padding })`. Ancestor loops are prevented (`isAncestor(childId, parentId)`).
|
|
2644
2942
|
|
|
2943
|
+
**C4 Model notation & architecture diagrams.** The `'c4-architecture'` category in `DIAGRAM_TYPES` (and `editor.setPaletteCategory('c4-architecture')`) provides first-class support for Simon Brown's C4 model across Context, Container, Component, and Code levels:
|
|
2944
|
+
- `C4PersonTemplate`: A human user, actor, persona, or stakeholder (`#08427b`, white text) with an integrated person silhouette badge and `[Person]` tagline.
|
|
2945
|
+
- `C4SystemTemplate`: Software system in focus (`#1168bd`, white text, `[Software System]`) or external software systems (`external: true`, `#999999`, `[Software System: External]`).
|
|
2946
|
+
- `C4ContainerTemplate`: Applications, web services, or microservices (`#438dd5`, white text, `[Container: <technology>]`), and database datastores (`containerType: 'database'`, cylinder icon).
|
|
2947
|
+
- `C4ComponentTemplate`: Modular components, controllers, and services (`#85bbf0`, dark text, `[Component: <technology>]`) with the UML component glyph.
|
|
2948
|
+
- `C4BoundaryTemplate`: Enterprise, system, or container scope boundaries (`isContainer = true`, dashed border `#707070`, bracketed header `[<boundaryType> Boundary]`) that enclose nested child elements.
|
|
2949
|
+
|
|
2950
|
+
```javascript
|
|
2951
|
+
const person = new C4PersonTemplate('p1', 'Customer', { description: 'Personal banking customer' });
|
|
2952
|
+
const system = new C4SystemTemplate('s1', 'Internet Banking System', { description: 'Allows customers to view accounts and make payments' });
|
|
2953
|
+
const boundary = new C4BoundaryTemplate('b1', 'Big Bank plc', { boundaryType: 'Enterprise' });
|
|
2954
|
+
```
|
|
2955
|
+
|
|
2645
2956
|
**Line style levels.** A line's style resolves through `EdgeStyleCascade`: the line itself,
|
|
2646
2957
|
then each level in `editor.edgeStyleLevels` (most specific first, `[{ key, label, style }]`),
|
|
2647
2958
|
then the schema default. A value a level doesn't set is inherited. `EDGE_STYLE_PROPERTIES` is the
|
|
@@ -3209,7 +3520,7 @@ drawn with this library's charts. It reads decisionengine's JSON, not decisionen
|
|
|
3209
3520
|
document
|
|
3210
3521
|
|
|
3211
3522
|
```js
|
|
3212
|
-
{ kind: 'sadis-workbench', report, plan?, before? } // report.toJSON(), plan.toJSON(), an earlier report.toJSON()
|
|
3523
|
+
{ kind: 'sadis-workbench', report, plan?, before?, graph? } // report.toJSON(), plan.toJSON(), an earlier report.toJSON(), the scored graph
|
|
3213
3524
|
```
|
|
3214
3525
|
|
|
3215
3526
|
which decisionengine's SADIS Explorer downloads ("Download for the Decision Workbench").
|
|
@@ -3228,6 +3539,7 @@ for (const view of workbench.views()) {
|
|
|
3228
3539
|
|---|---|---|
|
|
3229
3540
|
| Executive | a report | `kpi-tile` (what to build next; half the value delivered by), `stackedBar` (score part by part), `line` (value delivered by period) |
|
|
3230
3541
|
| Architecture | a report | `scatter` (visible rating against basin position: foundations sit high and left), `lollipop` (share each frees) |
|
|
3542
|
+
| Explore | the scored graph | `graph` diagram of the first candidate's neighbourhood: its ways up to each objective it reaches (shortest, along contributions) and what waits on it (depends on it, or is blocked by it); notes spell each way out. Walked with `NavigatorModel.forGraph` |
|
|
3231
3543
|
| Delivery | a plan | `gantt` (the plan on a calendar), `stackedBar` (capacity used per period, per team when planned by team) |
|
|
3232
3544
|
| Portfolio | a report with perspectives | `heatmap` (rank by perspective), `dumbbell` (best and worst rank, most contested first) |
|
|
3233
3545
|
| Replay | an earlier report | `slopegraph` (rank then → now); notes say what entered, left (and why) and moved |
|
|
@@ -3385,7 +3697,7 @@ nav.back(); // returns to 'billing-app'
|
|
|
3385
3697
|
const paths = nav.findPaths('billing-app', 'ledger-db', 5);
|
|
3386
3698
|
|
|
3387
3699
|
// Trace transitive downstream or upstream impact:
|
|
3388
|
-
const impact = nav.
|
|
3700
|
+
const impact = nav.traceImpact('billing-app', { maxDepth: 4, direction: 'outgoing' });
|
|
3389
3701
|
|
|
3390
3702
|
// 2. Build or render the Navigator UI panel:
|
|
3391
3703
|
const panel = new NavigatorPanel({
|
|
@@ -3400,7 +3712,26 @@ const panel = new NavigatorPanel({
|
|
|
3400
3712
|
- **Cycle detection and path tracking:** Tracks visited nodes along active branches to prevent infinite recursion in cyclic relationship graphs, annotating cycles in tree outputs.
|
|
3401
3713
|
- **Directional filters:** Traversal can follow outgoing relationships, incoming relationships, or bidirectional connections (`setDirection('outgoing' | 'incoming' | 'both')`).
|
|
3402
3714
|
- **History stack:** Maintains full forward and backward navigation stacks (`focus(id)`, `back()`, `forward()`, `canGoBack`, `canGoForward`).
|
|
3403
|
-
- **Impact and path finding:** Built-in BFS/DFS algorithms find connecting pathways (`findPaths(fromId, toId, maxDepth)`) and downstream dependency cascades (`
|
|
3715
|
+
- **Impact and path finding:** Built-in BFS/DFS algorithms find connecting pathways (`findPaths(fromId, toId, maxDepth)`) and downstream dependency cascades (`traceImpact(elementId, { maxDepth, direction })`).
|
|
3716
|
+
|
|
3717
|
+
|
|
3718
|
+
**Any graph, not only ArchiMate.** `NavigatorModel` reads its graph only through four questions —
|
|
3719
|
+
`getElement(id)`, `relationshipsFor(id)` (`{ incoming, outgoing }`, each `{ id, source, target, kind }`),
|
|
3720
|
+
`viewsContaining(id)` and `layerOf(element)` — the `GraphSource` interface
|
|
3721
|
+
(`src/charting/graph/GraphSource.js`). `ArchimateModel` answers them already (its layers from
|
|
3722
|
+
`treeLayerOf`); `DocumentGraph` answers them for a graph document, `{ nodes: [{ id, labels, props }],
|
|
3723
|
+
edges: [{ from, to, type, props }] }` — sqlengine's graphs and decisionengine's portfolios — a node's type its
|
|
3724
|
+
first label, its layer its type:
|
|
3725
|
+
|
|
3726
|
+
```javascript
|
|
3727
|
+
import { NavigatorModel, DocumentGraph } from '@peter.prib/renderengine';
|
|
3728
|
+
const nav = NavigatorModel.forGraph(graphDocument, { rootId: 'cap-semantic-registry' });
|
|
3729
|
+
nav.findPaths('cap-semantic-registry', 'obj-trusted-data', { direction: 'outgoing', allowedKinds: ['ENABLES', 'SUPPORTS'] });
|
|
3730
|
+
nav.traceImpact('cap-semantic-registry', { direction: 'incoming', allowedKinds: ['DEPENDS_ON'] });
|
|
3731
|
+
```
|
|
3732
|
+
|
|
3733
|
+
Why an interface rather than a second walker: traversal is the same for every graph; only these reads
|
|
3734
|
+
differ, so each kind of graph answers them and the one walker (paths, impact, history, the tree) serves all.
|
|
3404
3735
|
|
|
3405
3736
|
## Templated Reports (`TemplatedReport`)
|
|
3406
3737
|
|
|
@@ -3492,30 +3823,55 @@ dataModel.addArchimateLink(link);
|
|
|
3492
3823
|
|
|
3493
3824
|
## Multi-View Chart Dashboards (`ViewsPart` / `DecisionWorkbenchPart`)
|
|
3494
3825
|
|
|
3495
|
-
`ViewsPart` (`src/workspace/parts/ViewsPart.js
|
|
3826
|
+
`ViewsPart` (`src/workspace/parts/ViewsPart.js`, type `views`) shows a set of chart **views** inside
|
|
3827
|
+
one workspace part: a tab per view, each a grid of charts with its notes underneath, and a toolbar that
|
|
3828
|
+
opens a file. A view is plain data:
|
|
3496
3829
|
|
|
3497
|
-
```
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
part: 'views',
|
|
3502
|
-
views: [
|
|
3503
|
-
{
|
|
3504
|
-
id: 'executive-summary',
|
|
3505
|
-
title: 'Executive Summary',
|
|
3506
|
-
charts: [
|
|
3507
|
-
{ title: 'System Health', chartType: 'gauge dial', data: [{ score: 94 }], options: { min: 0, max: 100 } },
|
|
3508
|
-
{ title: 'Revenue Trend', chartType: 'area', data: [...] }
|
|
3509
|
-
],
|
|
3510
|
-
notes: ['All latency thresholds met', 'Quarterly SLA target achieved']
|
|
3511
|
-
}
|
|
3512
|
-
]
|
|
3513
|
-
};
|
|
3830
|
+
```js
|
|
3831
|
+
{ id: 'summary', title: 'Summary',
|
|
3832
|
+
charts: [{ title, chartType, data, options? }], // chartType: a CHART_CATALOG key ('kpi-tile', 'bar', 'gantt', …)
|
|
3833
|
+
notes: ['plain lines the charts cannot show'] }
|
|
3514
3834
|
```
|
|
3515
3835
|
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3836
|
+
Like any part it is registered, added with `addParts`, and placed in a layout by its `partId`. It uses
|
|
3837
|
+
`ChartPart`, so it is registered with it rather than being among `BUILTIN_PARTS`:
|
|
3838
|
+
|
|
3839
|
+
```js
|
|
3840
|
+
const { registerBuiltinParts, ChartPart, ViewsPart } = RenderEngineWorkspace;
|
|
3841
|
+
registerBuiltinParts(ws);
|
|
3842
|
+
ws.registerParts([ChartPart, ViewsPart]);
|
|
3843
|
+
ws.addParts([{
|
|
3844
|
+
id: 'summary', type: 'views', title: 'Summary',
|
|
3845
|
+
views: [{
|
|
3846
|
+
id: 'health', title: 'Health',
|
|
3847
|
+
charts: [
|
|
3848
|
+
{ title: 'Availability (%)', chartType: 'kpi-tile', data: { value: 99.95 } },
|
|
3849
|
+
{ title: 'Errors by service', chartType: 'bar', data: [{ label: 'api', value: 12 }, { label: 'web', value: 3 }] },
|
|
3850
|
+
],
|
|
3851
|
+
notes: ['All latency thresholds met'],
|
|
3852
|
+
}],
|
|
3853
|
+
}]);
|
|
3854
|
+
ws.registerPerspective('Summary', { type: 'part', partId: 'summary' });
|
|
3855
|
+
```
|
|
3856
|
+
|
|
3857
|
+
- **One part, any layout.** It sits in a tab, a split, a dashboard cell or a WorkArea document beside
|
|
3858
|
+
what else the host shows; it does not register perspectives of its own.
|
|
3859
|
+
- **Composed from existing parts.** Each chart is a `ChartPart`, the notes a `ListPart`. Gauge-like
|
|
3860
|
+
charts (catalog `category: 'gauge'`, e.g. `kpi-tile`, `gauge-bar`, `bullet`) share the top row as
|
|
3861
|
+
tiles; other charts take half a row, or the whole row when a view has one (`ViewsPart.layout(views)`).
|
|
3862
|
+
- **Spec:** `views`, `open` (default true: the toolbar's file opener), `empty` (the text shown with no
|
|
3863
|
+
views). `part.read(doc)` shows a `{ views: [...] }` document from code. The views shown are kept in
|
|
3864
|
+
`spec.views`, so a serialized workspace comes back showing them.
|
|
3865
|
+
- **Other kinds of document** are subclasses overriding `viewsFrom(doc)` (and `accept`, `controls()`,
|
|
3866
|
+
`controlValues()` for options their reader takes). Why a subclass and not a reader in the spec, and
|
|
3867
|
+
why one part rather than perspectives: `documentation/WORKSPACE_ARCHITECTURE.md` (Parts).
|
|
3868
|
+
|
|
3869
|
+
`DecisionWorkbenchPart` (`src/workspace/parts/DecisionWorkbenchPart.js`, type `decision-workbench`) is
|
|
3870
|
+
the first such subclass. It reads a SADIS workbench document from decisionengine
|
|
3871
|
+
(`{ kind: 'sadis-workbench', report, plan?, before? }`) through `DecisionWorkbench` and shows its
|
|
3872
|
+
**executive**, **architecture**, **delivery**, **portfolio** and **replay** views (see *Decision
|
|
3873
|
+
Workbench* above), with toolbar fields for the calendar the delivery plan is drawn on. Spec: `ViewsPart`'s
|
|
3874
|
+
plus `document`, `start`, `periodDays`. `examples/decision-workbench.html` hosts one.
|
|
3519
3875
|
|
|
3520
3876
|
## Where to go next
|
|
3521
3877
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.prib/renderengine",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "ArchiMate modeller, data modeller, diagram editor, OLAP cube & pivot chart studio, and 50+ type chart library for the browser, with no runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|