@cehlers88/chart 1.1.1 → 1.2.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 CHANGED
@@ -60,13 +60,104 @@ Attributes:
60
60
 
61
61
  | Attribute | Description | Default |
62
62
  |-------------|----------------------------------------------------------------------|---------|
63
- | `width` | Canvas width in pixels | `300` |
63
+ | `width` | Canvas width in pixels; `100%`/`auto` makes the diagram responsive (it takes the width of its container and is redrawn sharply whenever that changes) | `300` |
64
64
  | `height` | Canvas height in pixels | `150` |
65
65
  | `value` | JSON string with the data groups (see data format below) | `[]` |
66
66
  | `autostart` | Starts the chart automatically once mounted (`"true"`/`"false"`) | `true` |
67
67
 
68
68
  Additional plugins can be registered on the element before it starts via `getPlugin()`/`addPlugin()`.
69
69
 
70
+ ## Changing data at runtime
71
+
72
+ The data of a chart is not frozen after the page was loaded – it can be read,
73
+ replaced and manipulated at any time, either through the `<canvas-diagram>`
74
+ element or through the `ChartEngine`. A running chart picks the changes up with
75
+ the next frame, no restart needed.
76
+
77
+ ```html
78
+ <canvas-diagram id="sales" width="600" height="300"
79
+ value='{"Revenue":[1,5,3,8,2]}'></canvas-diagram>
80
+
81
+ <script type="module">
82
+ import { DataGroupFactory, diagramRegistry } from "@cehlers88/chart";
83
+
84
+ const diagram = document.getElementById("sales");
85
+ // ... or, without a dom reference:
86
+ // const diagram = diagramRegistry.getDiagram("sales");
87
+
88
+ diagram.addValue(6, "Revenue"); // append a value
89
+ diagram.setValue("Revenue", 0, 4); // replace a single value
90
+ diagram.removeValue("Revenue", 1); // remove a single value
91
+ diagram.addDataGroup( // add a whole group
92
+ DataGroupFactory.createDataGroup([2, 3, 1], "Costs", "#e84949")
93
+ );
94
+ diagram.removeDataGroup("Costs"); // remove a whole group
95
+ diagram.setData({ Revenue: [1, 2, 3] }); // replace everything
96
+ diagram.clearData(); // remove everything
97
+
98
+ console.log(diagram.getDataGroups()); // read the current data
99
+ </script>
100
+ ```
101
+
102
+ Setting the `value` attribute again works as well and replaces the complete data:
103
+
104
+ ```javascript
105
+ document.getElementById("sales").setAttribute("value", '{"Revenue":[3,4,5]}');
106
+ ```
107
+
108
+ Methods of `<canvas-diagram>`:
109
+
110
+ | Method | Description |
111
+ |-----------------------------------------|--------------------------------------------------------------------------|
112
+ | `setData(definition)` | Replaces all data. Accepts a JSON string, an array or an object |
113
+ | `setDataGroups(dataGroups)` | Replaces all data with ready-made `TDataGroup`s |
114
+ | `getDataGroups()` | Returns the current data groups |
115
+ | `getDataGroup(labelOrIndex)` | Returns a single data group |
116
+ | `addDataGroup(dataGroup)` | Adds a data group |
117
+ | `removeDataGroup(labelOrIndex)` | Removes a data group |
118
+ | `addValue(value, groupName?)` | Appends a value; creates the group if it does not exist yet |
119
+ | `setValue(labelOrIndex, index, value)` | Replaces a single value; missing values in between are filled up empty |
120
+ | `removeValue(labelOrIndex, index)` | Removes a single value |
121
+ | `clearData()` | Removes all data groups |
122
+ | `addPlugin(plugin)` / `getPlugin(name)` | Registers / returns a plugin – also while the chart is already running |
123
+ | `start()` / `stop()` | Starts / stops the render loop |
124
+ | `getEngine()` | Returns the underlying `ChartEngine` |
125
+
126
+ The same data methods exist on `ChartEngine`, so the programmatic usage works
127
+ identically:
128
+
129
+ ```typescript
130
+ const engine = new ChartEngine(canvas, { plugins: [new plugins.BarsPlugin()] });
131
+
132
+ engine.setData({ Revenue: [1, 5, 3] });
133
+ engine.start();
134
+
135
+ setInterval(() => engine.addValue(Math.random() * 10, "Revenue"), 1000);
136
+ ```
137
+
138
+ Data methods may be called before the element is mounted as well; those calls
139
+ are applied as soon as the element is connected (and take precedence over the
140
+ `value` attribute).
141
+
142
+ ### Live data
143
+
144
+ For values that arrive after the page was loaded (ajax, Mercure, websockets, …) give the
145
+ group a `maxLength` and append the new values with their timestamp. The oldest values are
146
+ pushed out, so the chart keeps its time window, and the new value is labelled like the
147
+ initial ones:
148
+
149
+ ```html
150
+ <canvas-diagram id="co2" width="100%" height="110"
151
+ value='{"CO2":{"data":[450,470],"timestamps":[1790000000,1790000600],"unit":"ppm","maxLength":2}}'></canvas-diagram>
152
+
153
+ <script type="module">
154
+ import { diagramRegistry } from "@cehlers88/chart";
155
+
156
+ // without a group name the value goes to the only group of the chart
157
+ diagramRegistry.getDiagram("co2").addValue({ value: 480, timestamp: 1790001200 });
158
+ </script>
159
+ ```
160
+
70
161
  ## Data format
71
162
 
72
163
  `DataGroupFactory` accepts several notations for the values within a group:
@@ -91,13 +182,58 @@ As a JSON string (e.g. for the custom element's `value` attribute), groups are g
91
182
  }
92
183
  ```
93
184
 
185
+ The object notation takes a few optional keys more:
186
+
187
+ | Key | Description |
188
+ |--------------|-----------------------------------------------------------------------------------------------|
189
+ | `unit` | Unit of the values, shown in the tooltip and on the value axis (`"°C"`, `"ppm"`) |
190
+ | `labels` | One label per value (e.g. the time of a measurement), shown in the tooltip and on the x axis |
191
+ | `timestamps` | One unix timestamp per value (seconds or milliseconds), turned into time labels; `0`/`null` means "no label". Values below 1e11 are read as seconds (up to the year 5138), larger ones as milliseconds (from 1973 on). Single values take theirs as `{ "value": 1, "timestamp": 1790000000 }` |
192
+ | `maxLength` | Maximum number of values; values appended later push the oldest ones out |
193
+
194
+ `null` values are gaps: the line is interrupted there instead of dropping to 0, and they
195
+ do not count for the value range.
196
+
197
+ ```json
198
+ { "CO2": { "data": [null, 450, 470], "timestamps": [0, 1790000000, 1790000600], "unit": "ppm" } }
199
+ ```
200
+
201
+ ## Look & theming
202
+
203
+ `DiagramLinePlugin` draws a smooth (monotone, never overshooting) line with a gradient
204
+ fill, a value axis with "nice" steps on the right and - if the values carry labels - a
205
+ label axis at the bottom. Hovering (or tapping) shows a crosshair and a tooltip with the
206
+ values next to the pointer. Options: `smooth`, `fill`, `lineWidth`, `showGrid`,
207
+ `showYLabels`, `showXLabels`, `showTooltip`, `showBulletPoints`, `showZeroLine`,
208
+ `maxYTicks`, `decimals`.
209
+
210
+ Colours are read from CSS custom properties of the canvas, so the host page adapts the
211
+ charts to its theme:
212
+
213
+ ```css
214
+ canvas-diagram {
215
+ --chart-text-color: #8a93a6;
216
+ --chart-grid-color: rgba(255, 255, 255, .07);
217
+ --chart-tooltip-background: rgba(12, 12, 12, .94);
218
+ --chart-tooltip-border: rgba(255, 255, 255, .12);
219
+ --chart-tooltip-text-color: #e4e4e4;
220
+ --chart-font: 11px system-ui, sans-serif;
221
+ --chart-background: transparent; /* background of the canvas */
222
+ --chart-border-radius: 0;
223
+ }
224
+ ```
225
+
226
+ A plugin property of the same name (`textColor`, `gridColor`, `tooltipBackground`,
227
+ `tooltipBorder`, `tooltipTextColor`, `font`) wins over the CSS property. Numbers and
228
+ times are formatted in the language of the page (`<html lang>`).
229
+
94
230
  ## Available plugins
95
231
 
96
232
  | Plugin | Purpose |
97
233
  |--------------------------|---------------------------------------------------------------------|
98
234
  | `BarsPlugin` | Renders data groups as bars |
99
- | `DiagramLinePlugin` | Renders data groups as lines, including helper lines |
100
- | `LegendsPlugin` | Displays a legend for the data groups |
235
+ | `DiagramLinePlugin` | Renders data groups as lines with value axis, crosshair and tooltip |
236
+ | `LegendsPlugin` | Displays a legend for the data groups (only for two or more groups unless `showSingleGroup`; steps aside while a tooltip covers it) |
101
237
  | `TooltipPlugin` | Shows tooltips on hover over data points |
102
238
  | `CameraMovePlugin` | Enables scrolling/panning the view via mouse/wheel |
103
239
  | `PaginationPlugin` | Splits large data sets into pages |
@@ -115,6 +251,12 @@ npm run watch # build in watch mode
115
251
  npm test # run tests with Jest
116
252
  ```
117
253
 
254
+ ## Release / Deployment
255
+
256
+ Pushes/merges to `main` trigger the `.github/workflows/publish.yml` GitHub Actions workflow, which installs dependencies, runs the tests and the build, and publishes the package to npm if `package.json`'s `version` differs from the version currently published on npm. To cut a release, bump `version` in `package.json` before merging to `main`.
257
+
258
+ This requires an `NPM_TOKEN` repository secret (an npm automation token with publish rights for `@cehlers88/chart`).
259
+
118
260
  ## License
119
261
 
120
262
  ISC © Christoph Ehlers
@@ -14,8 +14,12 @@ export default class ChartEngine implements IChartEngine {
14
14
  private _entityRegistry;
15
15
  private _ctx;
16
16
  private _dataGroups;
17
+ private _dataGroupsSignature;
18
+ private _processedDataGroups;
17
19
  private _plugins;
18
20
  private _pluginProperties;
21
+ private _created;
22
+ private _runStackEntry;
19
23
  constructor(canvasElement: HTMLCanvasElement, properties?: {
20
24
  plugins?: IChartPlugin[];
21
25
  });
@@ -26,9 +30,59 @@ export default class ChartEngine implements IChartEngine {
26
30
  setPluginProperty(propertyName: string, value: any): ChartEngine;
27
31
  create(): ChartEngine;
28
32
  addDataGroup(dataGroup: TDataGroup): IChartEngine;
33
+ /**
34
+ * Returns the data groups currently held by the engine.
35
+ * The returned groups are the live objects; changes made to them are
36
+ * picked up with the next update cycle.
37
+ */
38
+ getDataGroups(): TDataGroup[];
39
+ /**
40
+ * Returns a single data group, addressed either by its label or by its index.
41
+ */
42
+ getDataGroup(group: string | number): TDataGroup | undefined;
43
+ /**
44
+ * Replaces all data groups at once.
45
+ */
46
+ setDataGroups(dataGroups: TDataGroup[]): IChartEngine;
47
+ /**
48
+ * Replaces the complete data of the chart. Accepts everything
49
+ * `DataGroupFactory.parseDataGroupsDefinition` understands: a JSON string,
50
+ * a plain array of values or an object keyed by group name.
51
+ */
52
+ setData(dataDefinition: string | any[] | object): IChartEngine;
53
+ /**
54
+ * Removes a data group, addressed either by its label or by its index.
55
+ */
56
+ removeDataGroup(group: string | number): IChartEngine;
57
+ /**
58
+ * Removes all data groups.
59
+ */
60
+ clearData(): IChartEngine;
29
61
  addValue(value: any, groupName?: string): IChartEngine;
62
+ /**
63
+ * Replaces a single value within a data group.
64
+ */
65
+ setValue(group: string | number, dataIndex: number, value: any): IChartEngine;
66
+ /**
67
+ * Removes a single value from a data group.
68
+ */
69
+ removeValue(group: string | number, dataIndex: number): IChartEngine;
30
70
  draw(): ChartEngine;
31
71
  update(): ChartEngine;
72
+ /**
73
+ * Returns the data groups handed to the plugins. They are a detached copy
74
+ * of the data owned by the engine and are renewed whenever that data
75
+ * changed. Without that separation the plugins would hold references to
76
+ * the very objects manipulated from outside, so neither they nor the
77
+ * engine could tell a manipulation from the state of the last frame.
78
+ */
79
+ private getPipelineDataGroups;
32
80
  start(): void;
81
+ /**
82
+ * Stops the render loop of this engine. The data stays untouched, so the
83
+ * chart can be started again later on.
84
+ */
85
+ stop(): ChartEngine;
86
+ isRunning(): boolean;
33
87
  private getEngineCallbacks;
34
88
  }
@@ -1,10 +1,23 @@
1
1
  import { TDataGroup } from "../type/TDataGroup";
2
+ import { TData } from "../type/TData";
2
3
  export default class DataGroupFactory {
3
4
  static buildCounter: number;
4
5
  private static _colors;
5
6
  private static _lastColorIndex;
7
+ /**
8
+ * Normalizes a single value definition into a TData object.
9
+ * Accepts plain numbers, ranges ([start, end]), null (empty value) and
10
+ * objects like {value, valueStart, label}.
11
+ */
12
+ static createDataValue(valueDef: any): TData;
6
13
  static createDataGroup(values: any[], groupLabel?: string, color?: string): TDataGroup;
7
- static parseDataGroupsDefinition(value: string): TDataGroup[];
14
+ /**
15
+ * Parses a data group definition. Beside the JSON notation used by the
16
+ * `value` attribute of `<canvas-diagram>` an already parsed object/array
17
+ * may be passed, so data can be handed over programmatically at runtime.
18
+ */
19
+ static parseDataGroupsDefinition(value: string | any[] | object): TDataGroup[];
20
+ static getNextColor(): string;
8
21
  static setColor(color: string, index: number): void;
9
22
  static setColors(colors: string[]): void;
10
23
  }
@@ -8,9 +8,17 @@ import CanvasDiagram from "../customElement/CanvasDiagram";
8
8
  import { ICanvasDiagram } from "../interface/ICanvasDiagram";
9
9
  declare class DiagramRegistry {
10
10
  private static _identPrefix;
11
+ private static _identCounter;
11
12
  private createUniqueIdentifier;
12
13
  getDiagram(identifier: string): ICanvasDiagram;
14
+ hasDiagram(identifier: string): boolean;
15
+ getDiagrams(): ICanvasDiagram[];
13
16
  register(diagram: CanvasDiagram, identifier?: string): DiagramRegistry;
17
+ /**
18
+ * Removes a diagram from the registry, either by its identifier or by the
19
+ * element itself, so removed diagrams are not kept alive by the registry.
20
+ */
21
+ unregister(diagram: CanvasDiagram | string): DiagramRegistry;
14
22
  }
15
23
  export default DiagramRegistry;
16
24
  export declare const diagramRegistry: DiagramRegistry;
@@ -7,13 +7,43 @@
7
7
  import '../style/CanvasDiagram.css';
8
8
  import { IChartPlugin } from "../interface/IChartPlugin";
9
9
  import { ICanvasDiagram } from "../interface/ICanvasDiagram";
10
+ import { TDataGroup } from "../type/TDataGroup";
11
+ import { IChartEngine } from "../interface/IChartEngine";
10
12
  declare class CanvasDiagram extends HTMLElement implements ICanvasDiagram {
11
13
  private _cleanDom;
12
14
  private _engine;
15
+ private _ignoreValueAttribute;
16
+ private _pendingActions;
17
+ static get observedAttributes(): string[];
13
18
  connectedCallback(): void;
19
+ disconnectedCallback(): void;
20
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
14
21
  addPlugin(plugin: IChartPlugin): ICanvasDiagram;
15
22
  getPlugin(pluginName: string): IChartPlugin | undefined;
23
+ getEngine(): IChartEngine | undefined;
24
+ addDataGroup(dataGroup: TDataGroup): ICanvasDiagram;
25
+ addValue(value: any, groupName?: string): ICanvasDiagram;
26
+ clearData(): ICanvasDiagram;
27
+ getDataGroup(group: string | number): TDataGroup | undefined;
28
+ getDataGroups(): TDataGroup[];
29
+ removeDataGroup(group: string | number): ICanvasDiagram;
30
+ removeValue(group: string | number, dataIndex: number): ICanvasDiagram;
31
+ /**
32
+ * Replaces the complete data of the diagram, at any time - also long after
33
+ * the page was loaded.
34
+ */
35
+ setData(dataDefinition: string | any[] | object): ICanvasDiagram;
36
+ setDataGroups(dataGroups: TDataGroup[]): ICanvasDiagram;
37
+ setValue(group: string | number, dataIndex: number, value: any): ICanvasDiagram;
16
38
  start(): ICanvasDiagram;
39
+ stop(): ICanvasDiagram;
40
+ /**
41
+ * Runs the given action against the engine. If the element is not mounted
42
+ * yet, the action is queued and executed as soon as the engine exists,
43
+ * so data can be set before as well as after the element was connected.
44
+ */
45
+ private withEngine;
46
+ private flushPendingActions;
17
47
  private createCanvas;
18
48
  private evalArguments;
19
49
  }
package/dist/index.d.ts CHANGED
@@ -9,7 +9,6 @@ import BarsPluginClass from "./plugin/BarsPlugin";
9
9
  import ChartEngineClass from './ChartEngine';
10
10
  import DataGroupFactoryClass from "./Factory/DataGroupFactory";
11
11
  import DiagramLine from "./plugin/DiagramLine";
12
- import DiagramRegistry from "./Registry/DiagramRegistry";
13
12
  import CameraMove from "./plugin/CameraMove";
14
13
  import EnrichGroupInfosPlugin from "./plugin/EnrichGroupInfosPlugin";
15
14
  import TimelinePlugin from "./plugin/TimelinePlugin";
@@ -18,7 +17,7 @@ import PaginationPlugin from "./plugin/PaginationPlugin";
18
17
  export declare const CanvasDiagram: typeof CanvasDiagramClass;
19
18
  export declare const ChartEngine: typeof ChartEngineClass;
20
19
  export declare const DataGroupFactory: typeof DataGroupFactoryClass;
21
- export declare const diagramRegistry: DiagramRegistry;
20
+ export declare const diagramRegistry: import("./Registry/DiagramRegistry").default;
22
21
  export declare const plugins: {
23
22
  BarsPlugin: typeof BarsPluginClass;
24
23
  CameraMovePlugin: typeof CameraMove;
@@ -32,7 +31,7 @@ declare const _default: {
32
31
  CanvasDiagram: typeof CanvasDiagramClass;
33
32
  ChartEngine: typeof ChartEngineClass;
34
33
  DataGroupFactory: typeof DataGroupFactoryClass;
35
- diagramRegistry: DiagramRegistry;
34
+ diagramRegistry: import("./Registry/DiagramRegistry").default;
36
35
  plugins: {
37
36
  BarsPlugin: typeof BarsPluginClass;
38
37
  CameraMovePlugin: typeof CameraMove;
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ eval("{!function(t,e){ true?module.exports=e():0}(this,()=>(()=>{\"use strict\";
36
36
  (module, __webpack_exports__, __webpack_require__) {
37
37
 
38
38
  "use strict";
39
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `canvas-diagram {\n background: #dddddd;\n box-sizing: border-box;\n display: inline-block;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/style/CanvasDiagram.css?./node_modules/css-loader/dist/cjs.js\n}");
39
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `canvas-diagram {\n box-sizing: border-box;\n display: inline-block;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/style/CanvasDiagram.css?./node_modules/css-loader/dist/cjs.js\n}");
40
40
 
41
41
  /***/ },
42
42
 
@@ -146,7 +146,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
146
146
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
147
147
 
148
148
  "use strict";
149
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ ChartEngine)\n/* harmony export */ });\n/* harmony import */ var _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./plugin/EnrichGroupInfosPlugin */ \"./src/plugin/EnrichGroupInfosPlugin.ts\");\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./plugin/LegendsPlugin */ \"./src/plugin/LegendsPlugin.ts\");\n/* harmony import */ var _Registry_EntityRegistry__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Registry/EntityRegistry */ \"./src/Registry/EntityRegistry.ts\");\n/* harmony import */ var _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./plugin/PaginationPlugin */ \"./src/plugin/PaginationPlugin.ts\");\n/* harmony import */ var _Camera__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Camera */ \"./src/Camera.ts\");\n/**\n * Library ChartEngine\n * Created 26.11.22\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\n\nconst _runStack = [];\nlet _isRunning = false;\nconst _exec = () => {\n if (_isRunning)\n return;\n _isRunning = true;\n window.requestAnimationFrame(() => {\n _runStack.map(f => f());\n _isRunning = false;\n if (_runStack.length > 0)\n _exec();\n });\n};\nclass ChartEngine {\n _camera = new _Camera__WEBPACK_IMPORTED_MODULE_5__[\"default\"]();\n _canvasElement;\n _entityRegistry = new _Registry_EntityRegistry__WEBPACK_IMPORTED_MODULE_3__[\"default\"]();\n _ctx;\n _dataGroups = [];\n _plugins = [];\n _pluginProperties = {};\n constructor(canvasElement, properties = {\n plugins: []\n }) {\n this._canvasElement = canvasElement;\n this._ctx = canvasElement.getContext('2d');\n this._canvasElement.height = this._canvasElement.offsetHeight;\n this._canvasElement.width = this._canvasElement.offsetWidth;\n [\n new _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"](),\n new _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_4__[\"default\"](),\n new _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_2__[\"default\"](),\n ...properties.plugins,\n ].map(plugin => {\n this.addPlugin(plugin);\n });\n this._canvasElement.addEventListener('pointermove', (e) => {\n this._plugins.map(p => p.handleHover(e.offsetX + this._camera.getX(), e.offsetY + this._camera.getY()));\n });\n this._canvasElement.addEventListener('wheel', (e) => {\n this._plugins.map(p => p.handleScroll(e.deltaX, e.deltaY));\n });\n this._canvasElement.addEventListener('pointerout', (e) => {\n this._plugins.map(p => p.handleLeave());\n });\n }\n addPlugin(plugin) {\n for (let key in this._pluginProperties) {\n plugin.setProperty(key, this._pluginProperties[key]);\n }\n plugin\n .setCamera(this._camera)\n .setEntityRegistry(this._entityRegistry);\n this._plugins.push(plugin);\n return this;\n }\n getDrawAreaRect() {\n return {\n x: 0,\n y: 0,\n w: this._canvasElement.width,\n h: this._canvasElement.height\n };\n }\n getPlugin(pluginName) {\n return this._plugins.find((plugin) => plugin.getName() === pluginName);\n }\n getPlugins() {\n return this._plugins.sort((p1, p2) => p1.getPriority() - p2.getPriority());\n }\n setPluginProperty(propertyName, value) {\n this._pluginProperties[propertyName] = value;\n this._plugins.map(p => p.setProperty(propertyName, value));\n return this;\n }\n create() {\n this._plugins.map(p => p.create(this._canvasElement, this._dataGroups));\n return this;\n }\n addDataGroup(dataGroup) {\n this._dataGroups.push(dataGroup);\n return this;\n }\n addValue(value, groupName = '') {\n const dataGroup = this._dataGroups.find((group) => group.label === groupName);\n if (dataGroup) {\n dataGroup.data.push(value);\n }\n else {\n this._dataGroups.push(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].createDataGroup([value], groupName));\n }\n return this;\n }\n draw() {\n this._ctx.clearRect(0, 0, this._canvasElement.width, this._canvasElement.height);\n this.getPlugins().map(p => p.draw());\n return this;\n }\n update() {\n this.getPlugins().map(p => {\n this._dataGroups = p.update(this._dataGroups).dataGroups;\n });\n return this;\n }\n start() {\n this.create();\n _runStack.push(() => {\n this.update();\n this.draw();\n });\n _exec();\n }\n getEngineCallbacks() {\n return {\n updateData: (indexGroup, indexData, newData) => {\n console.log('updateData context:', this);\n this._dataGroups[indexData].data[indexData] = newData;\n return this;\n }\n };\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/ChartEngine.ts?\n}");
149
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ ChartEngine)\n/* harmony export */ });\n/* harmony import */ var _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./plugin/EnrichGroupInfosPlugin */ \"./src/plugin/EnrichGroupInfosPlugin.ts\");\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./plugin/LegendsPlugin */ \"./src/plugin/LegendsPlugin.ts\");\n/* harmony import */ var _Registry_EntityRegistry__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Registry/EntityRegistry */ \"./src/Registry/EntityRegistry.ts\");\n/* harmony import */ var _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./plugin/PaginationPlugin */ \"./src/plugin/PaginationPlugin.ts\");\n/* harmony import */ var _Camera__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Camera */ \"./src/Camera.ts\");\n/**\n * Library ChartEngine\n * Created 26.11.22\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\n\nconst _runStack = [];\nlet _isRunning = false;\nconst _exec = () => {\n if (_isRunning)\n return;\n _isRunning = true;\n window.requestAnimationFrame(() => {\n _runStack.map(f => f());\n _isRunning = false;\n if (_runStack.length > 0)\n _exec();\n });\n};\nclass ChartEngine {\n _camera = new _Camera__WEBPACK_IMPORTED_MODULE_5__[\"default\"]();\n _canvasElement;\n _entityRegistry = new _Registry_EntityRegistry__WEBPACK_IMPORTED_MODULE_3__[\"default\"]();\n _ctx;\n _dataGroups = [];\n _dataGroupsSignature = '';\n _processedDataGroups = [];\n _plugins = [];\n _pluginProperties = {};\n _created = false;\n _runStackEntry;\n constructor(canvasElement, properties = {\n plugins: []\n }) {\n this._canvasElement = canvasElement;\n this._ctx = canvasElement.getContext('2d');\n this._canvasElement.height = this._canvasElement.offsetHeight;\n this._canvasElement.width = this._canvasElement.offsetWidth;\n [\n new _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"](),\n new _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_4__[\"default\"](),\n new _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_2__[\"default\"](),\n ...(properties.plugins || []),\n ].map(plugin => {\n this.addPlugin(plugin);\n });\n this._canvasElement.addEventListener('pointermove', (e) => {\n this._plugins.map(p => p.handleHover(e.offsetX + this._camera.getX(), e.offsetY + this._camera.getY()));\n });\n this._canvasElement.addEventListener('wheel', (e) => {\n this._plugins.map(p => p.handleScroll(e.deltaX, e.deltaY));\n });\n this._canvasElement.addEventListener('pointerout', (e) => {\n this._plugins.map(p => p.handleLeave());\n });\n }\n addPlugin(plugin) {\n for (let key in this._pluginProperties) {\n plugin.setProperty(key, this._pluginProperties[key]);\n }\n plugin\n .setCamera(this._camera)\n .setEntityRegistry(this._entityRegistry);\n this._plugins.push(plugin);\n if (this._created) {\n // The chart is already running, so the plugin has to catch up.\n plugin.create(this._canvasElement, this.getPipelineDataGroups());\n }\n return this;\n }\n getDrawAreaRect() {\n return {\n x: 0,\n y: 0,\n w: this._canvasElement.width,\n h: this._canvasElement.height\n };\n }\n getPlugin(pluginName) {\n return this._plugins.find((plugin) => plugin.getName() === pluginName);\n }\n getPlugins() {\n return this._plugins.sort((p1, p2) => p1.getPriority() - p2.getPriority());\n }\n setPluginProperty(propertyName, value) {\n this._pluginProperties[propertyName] = value;\n this._plugins.map(p => p.setProperty(propertyName, value));\n return this;\n }\n create() {\n this._plugins.map(p => p.create(this._canvasElement, this.getPipelineDataGroups()));\n this._created = true;\n return this;\n }\n addDataGroup(dataGroup) {\n this._dataGroups.push(dataGroup);\n return this;\n }\n /**\n * Returns the data groups currently held by the engine.\n * The returned groups are the live objects; changes made to them are\n * picked up with the next update cycle.\n */\n getDataGroups() {\n return this._dataGroups;\n }\n /**\n * Returns a single data group, addressed either by its label or by its index.\n */\n getDataGroup(group) {\n if (typeof group === 'number') {\n return this._dataGroups[group];\n }\n return this._dataGroups.find((dataGroup) => dataGroup.label === group);\n }\n /**\n * Replaces all data groups at once.\n */\n setDataGroups(dataGroups) {\n this._dataGroups = dataGroups || [];\n return this;\n }\n /**\n * Replaces the complete data of the chart. Accepts everything\n * `DataGroupFactory.parseDataGroupsDefinition` understands: a JSON string,\n * a plain array of values or an object keyed by group name.\n */\n setData(dataDefinition) {\n return this.setDataGroups(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].parseDataGroupsDefinition(dataDefinition));\n }\n /**\n * Removes a data group, addressed either by its label or by its index.\n */\n removeDataGroup(group) {\n const index = typeof group === 'number' ? group : this._dataGroups.findIndex((dataGroup) => dataGroup.label === group);\n if (index > -1 && index < this._dataGroups.length) {\n this._dataGroups.splice(index, 1);\n }\n return this;\n }\n /**\n * Removes all data groups.\n */\n clearData() {\n this._dataGroups = [];\n return this;\n }\n addValue(value, groupName = '') {\n const dataGroup = this._dataGroups.find((group) => group.label === groupName);\n if (dataGroup) {\n dataGroup.data.push(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].createDataValue(value));\n }\n else {\n this._dataGroups.push(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].createDataGroup([value], groupName));\n }\n return this;\n }\n /**\n * Replaces a single value within a data group.\n */\n setValue(group, dataIndex, value) {\n const dataGroup = this.getDataGroup(group);\n if (!dataGroup) {\n throw new Error('ChartEngine.setValue: data group \"' + group + '\" not found.');\n }\n if (!Number.isSafeInteger(dataIndex) || dataIndex < 0) {\n throw new Error('ChartEngine.setValue: data index must be a non-negative integer.');\n }\n while (dataGroup.data.length <= dataIndex) {\n dataGroup.data.push(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].createDataValue(null));\n }\n dataGroup.data[dataIndex] = _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_1__[\"default\"].createDataValue(value);\n return this;\n }\n /**\n * Removes a single value from a data group.\n */\n removeValue(group, dataIndex) {\n const dataGroup = this.getDataGroup(group);\n if (dataGroup && dataIndex > -1 && dataIndex < dataGroup.data.length) {\n dataGroup.data.splice(dataIndex, 1);\n }\n return this;\n }\n draw() {\n this._ctx.clearRect(0, 0, this._canvasElement.width, this._canvasElement.height);\n this.getPlugins().map(p => p.draw());\n return this;\n }\n update() {\n let dataGroups = this.getPipelineDataGroups();\n this.getPlugins().map(p => {\n dataGroups = p.update(dataGroups).dataGroups;\n });\n return this;\n }\n /**\n * Returns the data groups handed to the plugins. They are a detached copy\n * of the data owned by the engine and are renewed whenever that data\n * changed. Without that separation the plugins would hold references to\n * the very objects manipulated from outside, so neither they nor the\n * engine could tell a manipulation from the state of the last frame.\n */\n getPipelineDataGroups() {\n const signature = JSON.stringify(this._dataGroups);\n if (signature !== this._dataGroupsSignature) {\n this._dataGroupsSignature = signature;\n this._processedDataGroups = JSON.parse(signature);\n }\n return this._processedDataGroups;\n }\n start() {\n if (this._runStackEntry) {\n // already running\n return;\n }\n if (!this._created) {\n this.create();\n }\n this._runStackEntry = () => {\n this.update();\n this.draw();\n };\n _runStack.push(this._runStackEntry);\n _exec();\n }\n /**\n * Stops the render loop of this engine. The data stays untouched, so the\n * chart can be started again later on.\n */\n stop() {\n if (this._runStackEntry) {\n const index = _runStack.indexOf(this._runStackEntry);\n if (index > -1) {\n _runStack.splice(index, 1);\n }\n this._runStackEntry = undefined;\n }\n return this;\n }\n isRunning() {\n return this._runStackEntry !== undefined;\n }\n getEngineCallbacks() {\n return {\n updateData: (indexGroup, indexData, newData) => {\n this._dataGroups[indexGroup].data[indexData] = newData;\n return this;\n }\n };\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/ChartEngine.ts?\n}");
150
150
 
151
151
  /***/ },
152
152
 
@@ -168,7 +168,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
168
168
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
169
169
 
170
170
  "use strict";
171
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ DataGroupFactory)\n/* harmony export */ });\nclass DataGroupFactory {\n static buildCounter = 0;\n static _colors = [\n '#e84949',\n '#30cb30',\n '#f0a30a',\n '#1d91e3',\n '#ec459e',\n '#9f4ef4',\n '#f4f44e',\n '#4ef4f4',\n '#4ef49f',\n '#f49f4e',\n '#4e9bf4',\n ];\n static _lastColorIndex = -1;\n static createDataGroup(values, groupLabel = '', color = '') {\n DataGroupFactory.buildCounter++;\n if (color === '') {\n DataGroupFactory._lastColorIndex++;\n if (DataGroupFactory._lastColorIndex >= DataGroupFactory._colors.length) {\n DataGroupFactory._lastColorIndex = 0;\n }\n color = DataGroupFactory._colors[DataGroupFactory._lastColorIndex];\n }\n const dataGroup = {\n color,\n label: groupLabel === '' ? 'Group#' + DataGroupFactory.buildCounter : groupLabel,\n description: \"\",\n data: values.map((valueDef) => {\n let value = valueDef;\n let label = undefined;\n let valueStart = valueDef;\n let valueEnd = valueDef;\n if (valueDef !== null) {\n if (typeof valueDef === 'object') {\n if (Array.isArray(valueDef.value)) {\n if (valueDef.value.length === 2) {\n valueStart = valueDef.value[0];\n value = valueDef.value[1];\n valueEnd = valueDef.value[1];\n }\n else {\n console.warn('valueDef.value must be an array with 2 elements', valueDef);\n }\n }\n else {\n value = valueDef.value;\n valueEnd = valueDef.value;\n valueStart = valueDef.valueStart;\n }\n label = valueDef.label;\n }\n else {\n if (Array.isArray(valueDef) && valueDef.length === 2) {\n valueStart = valueDef[0];\n value = valueDef[1];\n valueEnd = valueDef[1];\n label = valueDef[0] + ' - ' + valueDef[1];\n }\n }\n }\n return {\n empty: (value === null),\n hasLabel: (valueDef && valueDef.label !== undefined),\n label,\n value,\n valueEnd,\n valueStart\n };\n }),\n infos: {}\n };\n return dataGroup;\n }\n static parseDataGroupsDefinition(value) {\n const valueObj = JSON.parse(value);\n const result = [];\n if (Array.isArray(valueObj)) {\n if (typeof valueObj[0] === 'number' || Array.isArray(valueObj[0])) {\n result.push(DataGroupFactory.createDataGroup(valueObj));\n }\n }\n else {\n if (typeof valueObj === 'object') {\n Object.keys(valueObj).map((key) => {\n if (Array.isArray(valueObj[key])) {\n result.push(DataGroupFactory.createDataGroup(valueObj[key], key));\n }\n else {\n result.push(DataGroupFactory.createDataGroup(valueObj[key].data, key, valueObj[key].color));\n }\n });\n }\n }\n return result;\n }\n static setColor(color, index) {\n DataGroupFactory._colors[index] = color;\n }\n static setColors(colors) {\n DataGroupFactory._colors = colors;\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/Factory/DataGroupFactory.ts?\n}");
171
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ DataGroupFactory)\n/* harmony export */ });\nclass DataGroupFactory {\n static buildCounter = 0;\n static _colors = [\n '#e84949',\n '#30cb30',\n '#f0a30a',\n '#1d91e3',\n '#ec459e',\n '#9f4ef4',\n '#f4f44e',\n '#4ef4f4',\n '#4ef49f',\n '#f49f4e',\n '#4e9bf4',\n ];\n static _lastColorIndex = -1;\n /**\n * Normalizes a single value definition into a TData object.\n * Accepts plain numbers, ranges ([start, end]), null (empty value) and\n * objects like {value, valueStart, label}.\n */\n static createDataValue(valueDef) {\n let value = valueDef;\n let label = undefined;\n let valueStart = valueDef;\n let valueEnd = valueDef;\n if (valueDef !== null && valueDef !== undefined) {\n if (typeof valueDef === 'object' && !Array.isArray(valueDef)) {\n if (Array.isArray(valueDef.value)) {\n if (valueDef.value.length === 2) {\n valueStart = valueDef.value[0];\n value = valueDef.value[1];\n valueEnd = valueDef.value[1];\n }\n else {\n console.warn('valueDef.value must be an array with 2 elements', valueDef);\n }\n }\n else {\n value = valueDef.value;\n valueEnd = valueDef.value;\n valueStart = valueDef.valueStart === undefined ? 0 : valueDef.valueStart;\n }\n label = valueDef.label;\n }\n else {\n if (Array.isArray(valueDef) && valueDef.length === 2) {\n valueStart = valueDef[0];\n value = valueDef[1];\n valueEnd = valueDef[1];\n label = valueDef[0] + ' - ' + valueDef[1];\n }\n }\n }\n return {\n empty: (value === null || value === undefined),\n hasLabel: (valueDef !== null && valueDef !== undefined && valueDef.label !== undefined),\n label,\n value,\n valueEnd,\n valueStart\n };\n }\n static createDataGroup(values, groupLabel = '', color = '') {\n DataGroupFactory.buildCounter++;\n if (color === '') {\n color = DataGroupFactory.getNextColor();\n }\n return {\n color,\n label: groupLabel === '' ? 'Group#' + DataGroupFactory.buildCounter : groupLabel,\n description: \"\",\n data: (values || []).map((valueDef) => DataGroupFactory.createDataValue(valueDef)),\n infos: {}\n };\n }\n /**\n * Parses a data group definition. Beside the JSON notation used by the\n * `value` attribute of `<canvas-diagram>` an already parsed object/array\n * may be passed, so data can be handed over programmatically at runtime.\n */\n static parseDataGroupsDefinition(value) {\n const valueObj = typeof value === 'string' ? JSON.parse(value) : value;\n const result = [];\n if (valueObj === null || valueObj === undefined) {\n return result;\n }\n if (Array.isArray(valueObj)) {\n if (valueObj.length > 0) {\n result.push(DataGroupFactory.createDataGroup(valueObj));\n }\n }\n else {\n if (typeof valueObj === 'object') {\n Object.keys(valueObj).map((key) => {\n if (Array.isArray(valueObj[key])) {\n result.push(DataGroupFactory.createDataGroup(valueObj[key], key));\n }\n else {\n result.push(DataGroupFactory.createDataGroup(valueObj[key].data, key, valueObj[key].color));\n }\n });\n }\n }\n return result;\n }\n static getNextColor() {\n DataGroupFactory._lastColorIndex++;\n if (DataGroupFactory._lastColorIndex >= DataGroupFactory._colors.length) {\n DataGroupFactory._lastColorIndex = 0;\n }\n return DataGroupFactory._colors[DataGroupFactory._lastColorIndex];\n }\n static setColor(color, index) {\n DataGroupFactory._colors[index] = color;\n }\n static setColors(colors) {\n DataGroupFactory._colors = colors;\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/Factory/DataGroupFactory.ts?\n}");
172
172
 
173
173
  /***/ },
174
174
 
@@ -179,7 +179,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
179
179
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
180
180
 
181
181
  "use strict";
182
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ diagramRegistry: () => (/* binding */ diagramRegistry)\n/* harmony export */ });\nconst _diagrams = {};\nclass DiagramRegistry {\n static _identPrefix = 'dia_';\n createUniqueIdentifier() {\n return 'unq' + Date.now().toString();\n }\n getDiagram(identifier) {\n const diagram = _diagrams[DiagramRegistry._identPrefix + identifier];\n if (diagram === undefined) {\n throw new Error('DiagramRegistry.getDiagram: diagram with identifier ' + identifier + ' not found.');\n }\n return diagram;\n }\n register(diagram, identifier = '') {\n if (identifier === '') {\n identifier = diagram.hasAttribute('id') ? diagram.getAttribute('id') : '';\n }\n if (identifier === '') {\n identifier = this.createUniqueIdentifier();\n }\n _diagrams[DiagramRegistry._identPrefix + identifier] = diagram;\n return this;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DiagramRegistry);\nconst diagramRegistry = new DiagramRegistry();\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/Registry/DiagramRegistry.ts?\n}");
182
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ diagramRegistry: () => (/* binding */ diagramRegistry)\n/* harmony export */ });\nconst _diagrams = {};\nclass DiagramRegistry {\n static _identPrefix = 'dia_';\n static _identCounter = 0;\n createUniqueIdentifier() {\n DiagramRegistry._identCounter++;\n return 'unq' + Date.now().toString() + '_' + DiagramRegistry._identCounter;\n }\n getDiagram(identifier) {\n const diagram = _diagrams[DiagramRegistry._identPrefix + identifier];\n if (diagram === undefined) {\n throw new Error('DiagramRegistry.getDiagram: diagram with identifier ' + identifier + ' not found.');\n }\n return diagram;\n }\n hasDiagram(identifier) {\n return _diagrams[DiagramRegistry._identPrefix + identifier] !== undefined;\n }\n getDiagrams() {\n return Object.keys(_diagrams).map(ident => _diagrams[ident]);\n }\n register(diagram, identifier = '') {\n if (identifier === '') {\n identifier = diagram.hasAttribute('id') ? diagram.getAttribute('id') : '';\n }\n if (identifier === '') {\n identifier = this.createUniqueIdentifier();\n }\n _diagrams[DiagramRegistry._identPrefix + identifier] = diagram;\n return this;\n }\n /**\n * Removes a diagram from the registry, either by its identifier or by the\n * element itself, so removed diagrams are not kept alive by the registry.\n */\n unregister(diagram) {\n if (typeof diagram === 'string') {\n delete _diagrams[DiagramRegistry._identPrefix + diagram];\n return this;\n }\n Object.keys(_diagrams).map(ident => {\n if (_diagrams[ident] === diagram) {\n delete _diagrams[ident];\n }\n });\n return this;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DiagramRegistry);\nconst diagramRegistry = new DiagramRegistry();\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/Registry/DiagramRegistry.ts?\n}");
183
183
 
184
184
  /***/ },
185
185
 
@@ -201,7 +201,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
201
201
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
202
202
 
203
203
  "use strict";
204
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _style_CanvasDiagram_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../style/CanvasDiagram.css */ \"./src/style/CanvasDiagram.css\");\n/* harmony import */ var _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Registry/DiagramRegistry */ \"./src/Registry/DiagramRegistry.ts\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @cehlers88/ceutils */ \"./node_modules/@cehlers88/ceutils/dist/index.js\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _ChartEngine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../ChartEngine */ \"./src/ChartEngine.ts\");\n/**\n * Element CanvasDiagram\n * Created 03.10.24\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\nclass CanvasDiagram extends HTMLElement {\n _cleanDom = true;\n _engine;\n connectedCallback() {\n _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_1__.diagramRegistry.register(this);\n const canvas = this.createCanvas();\n this.appendChild(canvas);\n this._engine = new _ChartEngine__WEBPACK_IMPORTED_MODULE_4__[\"default\"](canvas);\n this.evalArguments();\n }\n addPlugin(plugin) {\n this._engine.addPlugin(plugin);\n return this;\n }\n getPlugin(pluginName) {\n return this._engine.getPlugin(pluginName);\n }\n start() {\n this._engine.start();\n return this;\n }\n createCanvas() {\n const canvas = _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__.domLib.createElement('canvas');\n this.setAttribute('style', 'width:0px; height:0px;');\n [\n { name: 'height', defaultValue: 150 },\n { name: 'width', defaultValue: 300 },\n ].map((attrDef) => {\n let value = (this.hasAttribute(attrDef.name) ? this.getAttribute(attrDef.name) : attrDef.defaultValue.toString());\n value = value.replace('px', '');\n canvas.setAttribute(attrDef.name, value);\n this.style[attrDef.name] = value + 'px';\n });\n console.log('createCanvas', this.getAttribute('style'), ' ->', canvas);\n return canvas;\n }\n evalArguments() {\n [\n {\n name: 'value', defaultValue: '[]', callback: (value) => {\n _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"].parseDataGroupsDefinition(value).map(dataGroupDef => {\n console.log(dataGroupDef, 'per argument');\n this._engine.addDataGroup(_Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"].createDataGroup(dataGroupDef.data, dataGroupDef.label, dataGroupDef.color));\n });\n }\n },\n {\n name: 'autostart', defaultValue: 'true', callback: (value) => {\n if (value === 'true') {\n this.start();\n }\n }\n }\n ].map(attrDef => {\n const callbackArgument = this.hasAttribute(attrDef.name) ? this.getAttribute(attrDef.name) : attrDef.defaultValue;\n attrDef.callback(callbackArgument);\n if (this._cleanDom) {\n this.removeAttribute(attrDef.name);\n }\n });\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (CanvasDiagram);\ncustomElements.define('canvas-diagram', CanvasDiagram);\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/customElement/CanvasDiagram.ts?\n}");
204
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _style_CanvasDiagram_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../style/CanvasDiagram.css */ \"./src/style/CanvasDiagram.css\");\n/* harmony import */ var _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Registry/DiagramRegistry */ \"./src/Registry/DiagramRegistry.ts\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @cehlers88/ceutils */ \"./node_modules/@cehlers88/ceutils/dist/index.js\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _ChartEngine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../ChartEngine */ \"./src/ChartEngine.ts\");\n/**\n * Element CanvasDiagram\n * Created 03.10.24\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\nclass CanvasDiagram extends HTMLElement {\n _cleanDom = true;\n _engine;\n _ignoreValueAttribute = false;\n _pendingActions = [];\n static get observedAttributes() {\n return ['value'];\n }\n connectedCallback() {\n if (this._engine) {\n // The element was moved within the dom, no need to build it again.\n return;\n }\n _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_1__.diagramRegistry.register(this);\n const canvas = this.createCanvas();\n this.appendChild(canvas);\n this._engine = new _ChartEngine__WEBPACK_IMPORTED_MODULE_4__[\"default\"](canvas);\n this.evalArguments();\n this.flushPendingActions();\n }\n disconnectedCallback() {\n if (this._engine) {\n this._engine.stop();\n }\n _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_1__.diagramRegistry.unregister(this);\n }\n attributeChangedCallback(name, oldValue, newValue) {\n if (name !== 'value' || this._ignoreValueAttribute || newValue === null) {\n return;\n }\n if (!this._engine) {\n // Attribute is evaluated within connectedCallback anyway.\n return;\n }\n this.setData(newValue);\n }\n addPlugin(plugin) {\n return this.withEngine(engine => engine.addPlugin(plugin));\n }\n getPlugin(pluginName) {\n return this._engine ? this._engine.getPlugin(pluginName) : undefined;\n }\n getEngine() {\n return this._engine;\n }\n addDataGroup(dataGroup) {\n return this.withEngine(engine => engine.addDataGroup(dataGroup));\n }\n addValue(value, groupName = '') {\n return this.withEngine(engine => engine.addValue(value, groupName));\n }\n clearData() {\n return this.withEngine(engine => engine.clearData());\n }\n getDataGroup(group) {\n return this._engine ? this._engine.getDataGroup(group) : undefined;\n }\n getDataGroups() {\n return this._engine ? this._engine.getDataGroups() : [];\n }\n removeDataGroup(group) {\n return this.withEngine(engine => engine.removeDataGroup(group));\n }\n removeValue(group, dataIndex) {\n return this.withEngine(engine => engine.removeValue(group, dataIndex));\n }\n /**\n * Replaces the complete data of the diagram, at any time - also long after\n * the page was loaded.\n */\n setData(dataDefinition) {\n return this.withEngine(engine => engine.setData(dataDefinition));\n }\n setDataGroups(dataGroups) {\n return this.withEngine(engine => engine.setDataGroups(dataGroups));\n }\n setValue(group, dataIndex, value) {\n return this.withEngine(engine => engine.setValue(group, dataIndex, value));\n }\n start() {\n return this.withEngine(engine => engine.start());\n }\n stop() {\n return this.withEngine(engine => engine.stop());\n }\n /**\n * Runs the given action against the engine. If the element is not mounted\n * yet, the action is queued and executed as soon as the engine exists,\n * so data can be set before as well as after the element was connected.\n */\n withEngine(action) {\n if (this._engine) {\n action(this._engine);\n }\n else {\n this._pendingActions.push(action);\n }\n return this;\n }\n flushPendingActions() {\n const actions = this._pendingActions;\n this._pendingActions = [];\n actions.map(action => action(this._engine));\n }\n createCanvas() {\n const canvas = _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_2__.domLib.createElement('canvas');\n this.setAttribute('style', 'width:0px; height:0px;');\n [\n { name: 'height', defaultValue: 150 },\n { name: 'width', defaultValue: 300 },\n ].map((attrDef) => {\n let value = (this.hasAttribute(attrDef.name) ? this.getAttribute(attrDef.name) : attrDef.defaultValue.toString());\n value = value.replace('px', '');\n console.log('set', attrDef, value);\n canvas.setAttribute(attrDef.name, value);\n console.log(canvas);\n this.style[attrDef.name] = value + 'px';\n });\n return canvas;\n }\n evalArguments() {\n [\n {\n name: 'value', defaultValue: '[]', callback: (value) => {\n _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"].parseDataGroupsDefinition(value).map(dataGroupDef => {\n this._engine.addDataGroup(dataGroupDef);\n });\n }\n },\n {\n name: 'autostart', defaultValue: 'true', callback: (value) => {\n if (value === 'true') {\n this.start();\n }\n }\n }\n ].map(attrDef => {\n const callbackArgument = this.hasAttribute(attrDef.name) ? this.getAttribute(attrDef.name) : attrDef.defaultValue;\n attrDef.callback(callbackArgument);\n if (this._cleanDom) {\n // Removing the attribute must not be mistaken for a data change.\n this._ignoreValueAttribute = true;\n this.removeAttribute(attrDef.name);\n this._ignoreValueAttribute = false;\n }\n });\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (CanvasDiagram);\ncustomElements.define('canvas-diagram', CanvasDiagram);\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/customElement/CanvasDiagram.ts?\n}");
205
205
 
206
206
  /***/ },
207
207
 
@@ -212,7 +212,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
212
212
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
213
213
 
214
214
  "use strict";
215
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CanvasDiagram: () => (/* binding */ CanvasDiagram),\n/* harmony export */ ChartEngine: () => (/* binding */ ChartEngine),\n/* harmony export */ DataGroupFactory: () => (/* binding */ DataGroupFactory),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ diagramRegistry: () => (/* binding */ diagramRegistry),\n/* harmony export */ plugins: () => (/* binding */ plugins)\n/* harmony export */ });\n/* harmony import */ var _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./customElement/CanvasDiagram */ \"./src/customElement/CanvasDiagram.ts\");\n/* harmony import */ var _plugin_BarsPlugin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./plugin/BarsPlugin */ \"./src/plugin/BarsPlugin.ts\");\n/* harmony import */ var _ChartEngine__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ChartEngine */ \"./src/ChartEngine.ts\");\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _plugin_DiagramLine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./plugin/DiagramLine */ \"./src/plugin/DiagramLine.ts\");\n/* harmony import */ var _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Registry/DiagramRegistry */ \"./src/Registry/DiagramRegistry.ts\");\n/* harmony import */ var _plugin_CameraMove__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./plugin/CameraMove */ \"./src/plugin/CameraMove.ts\");\n/* harmony import */ var _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./plugin/EnrichGroupInfosPlugin */ \"./src/plugin/EnrichGroupInfosPlugin.ts\");\n/* harmony import */ var _plugin_TimelinePlugin__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./plugin/TimelinePlugin */ \"./src/plugin/TimelinePlugin.ts\");\n/* harmony import */ var _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./plugin/LegendsPlugin */ \"./src/plugin/LegendsPlugin.ts\");\n/* harmony import */ var _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./plugin/PaginationPlugin */ \"./src/plugin/PaginationPlugin.ts\");\n/**\n * index.ts\n * Created 05.05.24\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\n\n\n\n\n\n\nconst CanvasDiagram = _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\nconst ChartEngine = _ChartEngine__WEBPACK_IMPORTED_MODULE_2__[\"default\"];\nconst DataGroupFactory = _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"];\nconst diagramRegistry = new _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_5__[\"default\"]();\nconst plugins = {\n BarsPlugin: _plugin_BarsPlugin__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n CameraMovePlugin: _plugin_CameraMove__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n EnrichGroupInfosPlugin: _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_7__[\"default\"],\n DiagramLinePlugin: _plugin_DiagramLine__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n LegendsPlugin: _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n PaginationPlugin: _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_10__[\"default\"],\n TimelinePlugin: _plugin_TimelinePlugin__WEBPACK_IMPORTED_MODULE_8__[\"default\"]\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n CanvasDiagram: _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n ChartEngine: _ChartEngine__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n DataGroupFactory: _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n diagramRegistry,\n plugins\n});\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/index.ts?\n}");
215
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CanvasDiagram: () => (/* binding */ CanvasDiagram),\n/* harmony export */ ChartEngine: () => (/* binding */ ChartEngine),\n/* harmony export */ DataGroupFactory: () => (/* binding */ DataGroupFactory),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ diagramRegistry: () => (/* binding */ diagramRegistry),\n/* harmony export */ plugins: () => (/* binding */ plugins)\n/* harmony export */ });\n/* harmony import */ var _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./customElement/CanvasDiagram */ \"./src/customElement/CanvasDiagram.ts\");\n/* harmony import */ var _plugin_BarsPlugin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./plugin/BarsPlugin */ \"./src/plugin/BarsPlugin.ts\");\n/* harmony import */ var _ChartEngine__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ChartEngine */ \"./src/ChartEngine.ts\");\n/* harmony import */ var _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Factory/DataGroupFactory */ \"./src/Factory/DataGroupFactory.ts\");\n/* harmony import */ var _plugin_DiagramLine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./plugin/DiagramLine */ \"./src/plugin/DiagramLine.ts\");\n/* harmony import */ var _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Registry/DiagramRegistry */ \"./src/Registry/DiagramRegistry.ts\");\n/* harmony import */ var _plugin_CameraMove__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./plugin/CameraMove */ \"./src/plugin/CameraMove.ts\");\n/* harmony import */ var _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./plugin/EnrichGroupInfosPlugin */ \"./src/plugin/EnrichGroupInfosPlugin.ts\");\n/* harmony import */ var _plugin_TimelinePlugin__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./plugin/TimelinePlugin */ \"./src/plugin/TimelinePlugin.ts\");\n/* harmony import */ var _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./plugin/LegendsPlugin */ \"./src/plugin/LegendsPlugin.ts\");\n/* harmony import */ var _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./plugin/PaginationPlugin */ \"./src/plugin/PaginationPlugin.ts\");\n/**\n * index.ts\n * Created 05.05.24\n *\n * @author Christoph Ehlers\n */\n\n\n\n\n\n\n\n\n\n\n\nconst CanvasDiagram = _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\nconst ChartEngine = _ChartEngine__WEBPACK_IMPORTED_MODULE_2__[\"default\"];\nconst DataGroupFactory = _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"];\nconst diagramRegistry = _Registry_DiagramRegistry__WEBPACK_IMPORTED_MODULE_5__.diagramRegistry;\nconst plugins = {\n BarsPlugin: _plugin_BarsPlugin__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n CameraMovePlugin: _plugin_CameraMove__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n EnrichGroupInfosPlugin: _plugin_EnrichGroupInfosPlugin__WEBPACK_IMPORTED_MODULE_7__[\"default\"],\n DiagramLinePlugin: _plugin_DiagramLine__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n LegendsPlugin: _plugin_LegendsPlugin__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n PaginationPlugin: _plugin_PaginationPlugin__WEBPACK_IMPORTED_MODULE_10__[\"default\"],\n TimelinePlugin: _plugin_TimelinePlugin__WEBPACK_IMPORTED_MODULE_8__[\"default\"]\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n CanvasDiagram: _customElement_CanvasDiagram__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n ChartEngine: _ChartEngine__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n DataGroupFactory: _Factory_DataGroupFactory__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n diagramRegistry,\n plugins\n});\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/index.ts?\n}");
216
216
 
217
217
  /***/ },
218
218
 
@@ -223,7 +223,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
223
223
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
224
224
 
225
225
  "use strict";
226
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ AbstractDiagramPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractPlugin */ \"./src/plugin/AbstractPlugin.ts\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @cehlers88/ceutils */ \"./node_modules/@cehlers88/ceutils/dist/index.js\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__);\n\n\nclass AbstractDiagramPlugin extends _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(props = {}) {\n super({\n viewSize: -1,\n ...props\n });\n this._priority = 50;\n }\n update(dataGroups) {\n if (this.getProperty('enabled', true) === false)\n return { dataGroups };\n if (JSON.stringify(this._dataGroups) !== JSON.stringify(dataGroups)) {\n this.updateBufferSize(dataGroups);\n }\n return super.update(dataGroups);\n }\n updateBufferSize(dataGroups) {\n const groupWithMostData = dataGroups.reduce((prev, current) => {\n return prev.data.length > current.data.length ? prev : current;\n });\n const viewSize = this.getProperty('viewSize', -1);\n const dataPerView = viewSize === -1 ? groupWithMostData.data.length : viewSize;\n const singleGroupWidth = this.getDrawAreaRect().w / dataPerView;\n const bufferWidth = groupWithMostData.data.length * singleGroupWidth;\n this.setBuffer(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__.domLib.createElement('canvas', {\n height: this.getDrawAreaRect().h.toString(),\n width: bufferWidth.toString()\n }));\n this._camera.setMaxX(bufferWidth - this.getDrawAreaRect().w);\n return this.getDrawAreaRect().w / dataPerView;\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/AbstractDiagramPlugin.ts?\n}");
226
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ AbstractDiagramPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractPlugin */ \"./src/plugin/AbstractPlugin.ts\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @cehlers88/ceutils */ \"./node_modules/@cehlers88/ceutils/dist/index.js\");\n/* harmony import */ var _cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__);\n\n\nclass AbstractDiagramPlugin extends _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(props = {}) {\n super({\n viewSize: -1,\n ...props\n });\n this._priority = 50;\n }\n onDataGroupsChanged(dataGroups) {\n this.updateBufferSize(dataGroups);\n }\n updateBufferSize(dataGroups) {\n const viewSize = this.getProperty('viewSize', -1);\n const maxDataLength = dataGroups.length === 0 ? 0 : Math.max(...dataGroups.map((dataGroup) => dataGroup.data.length));\n const dataPerView = viewSize === -1 ? maxDataLength : viewSize;\n if (maxDataLength < 1 || dataPerView < 1) {\n // Without data there is nothing to scale the buffer by.\n this.setBuffer(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__.domLib.createElement('canvas', {\n height: this.getDrawAreaRect().h.toString(),\n width: this.getDrawAreaRect().w.toString()\n }));\n this._camera.setMaxX(0);\n return this.getDrawAreaRect().w;\n }\n const singleGroupWidth = this.getDrawAreaRect().w / dataPerView;\n const bufferWidth = maxDataLength * singleGroupWidth;\n this.setBuffer(_cehlers88_ceutils__WEBPACK_IMPORTED_MODULE_1__.domLib.createElement('canvas', {\n height: this.getDrawAreaRect().h.toString(),\n width: bufferWidth.toString()\n }));\n this._camera.setMaxX(bufferWidth - this.getDrawAreaRect().w);\n return singleGroupWidth;\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/AbstractDiagramPlugin.ts?\n}");
227
227
 
228
228
  /***/ },
229
229
 
@@ -234,7 +234,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
234
234
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
235
235
 
236
236
  "use strict";
237
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ AbstractPlugin)\n/* harmony export */ });\nclass AbstractPlugin {\n _camera;\n _dataGroups = [];\n _entityRegistry;\n _fixed = false;\n _priority = 50;\n bufferCtx;\n ctx;\n redrawBuffer = true;\n _buffer;\n _stateChangedListener;\n _drawAreaRect;\n _properties = {};\n constructor(props = {}) {\n if (props.enabled === undefined) {\n props.enabled = true;\n }\n Object.keys(props).map(key => {\n this.setProperty(key, props[key]);\n });\n }\n get needsRedraw() {\n return this.redrawBuffer;\n }\n setStateChangedListener(listener) {\n this._stateChangedListener = listener;\n return this;\n }\n setState(newState) {\n return this;\n }\n update(dataGroups) {\n if (this.getProperty('enabled', true) === false)\n return { dataGroups };\n this._dataGroups = this.updateDataGroups(dataGroups).dataGroups;\n return { dataGroups: this._dataGroups };\n }\n updateDataGroups(dataGroups) {\n return { dataGroups };\n }\n addEntity(entity) {\n this._entityRegistry.addEntity(this.getName(), entity);\n return this;\n }\n create(canvasElement, dataGroups) {\n this.createBuffer(canvasElement);\n this.setDrawAreaRect({\n x: this.getProperty('x', 0),\n y: this.getProperty('y', 0),\n w: canvasElement.width,\n h: canvasElement.height\n });\n this.ctx = canvasElement.getContext('2d');\n console.log('so', this.getDrawAreaRect());\n return {\n dataGroups,\n plugin: this\n };\n }\n drawBuffer() {\n this.redrawBuffer = false;\n }\n draw(forceRedraw = false) {\n const padding = this.getProperty('padding', 0);\n if (this.needsRedraw || forceRedraw) {\n this.bufferCtx.clearRect(0, 0, this._buffer.width, this._buffer.height);\n this.drawBuffer();\n //console.log('redraw buffer', this.bufferCtx.canvas.width, this.bufferCtx.canvas.height);\n }\n this.ctx.drawImage(this._buffer, this._fixed ? 0 : this._camera.x, this._fixed ? 0 : this._camera.y, this._drawAreaRect.w, this._drawAreaRect.h, this._drawAreaRect.x + padding, this._drawAreaRect.y + padding, this._drawAreaRect.w - (2 * padding), this._drawAreaRect.h - (2 * padding));\n return this;\n }\n getDrawAreaRect() {\n return this._drawAreaRect;\n }\n getPriority() {\n return this._priority;\n }\n getProperty(propertyName, defaultResult) {\n return this._properties[propertyName] ?? defaultResult;\n }\n handleClick(x, y) {\n return this;\n }\n handleHover(x, y) {\n return this;\n }\n handleLeave() {\n this.handleHover(-1, -1);\n return this;\n }\n handleScroll(x, y) {\n return this;\n }\n setBuffer(buffer) {\n this._buffer = buffer;\n this.bufferCtx = buffer.getContext('2d');\n return this;\n }\n setCamera(camera) {\n this._camera = camera;\n return this;\n }\n setDrawAreaRect(rect) {\n this._drawAreaRect = rect;\n return this;\n }\n setEntityRegistry(entityRegistry) {\n this._entityRegistry = entityRegistry;\n return this;\n }\n setProperty(propertyName, value) {\n this._properties[propertyName] = value;\n return this;\n }\n init() {\n return this;\n }\n createBuffer(canvasElement, width = null, height = null) {\n console.log('create buffer', width, height, canvasElement, this);\n this._buffer = document.createElement('canvas');\n this._buffer.width = width ?? canvasElement.width;\n this._buffer.height = height ?? canvasElement.height;\n this.bufferCtx = this._buffer.getContext('2d');\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/AbstractPlugin.ts?\n}");
237
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ AbstractPlugin)\n/* harmony export */ });\nclass AbstractPlugin {\n _camera;\n _dataGroups = [];\n _entityRegistry;\n _fixed = false;\n _priority = 50;\n bufferCtx;\n ctx;\n redrawBuffer = true;\n _dataGroupsChanged = true;\n _buffer;\n _dataGroupsSignature = '';\n _stateChangedListener;\n _drawAreaRect;\n _properties = {};\n constructor(props = {}) {\n if (props.enabled === undefined) {\n props.enabled = true;\n }\n Object.keys(props).map(key => {\n this.setProperty(key, props[key]);\n });\n }\n get needsRedraw() {\n return this.redrawBuffer;\n }\n setStateChangedListener(listener) {\n this._stateChangedListener = listener;\n return this;\n }\n setState(newState) {\n return this;\n }\n update(dataGroups) {\n if (this.getProperty('enabled', true) === false)\n return { dataGroups };\n this.detectDataGroupsChange(dataGroups);\n if (this._dataGroupsChanged) {\n // Data was manipulated in the meantime, so the buffer is outdated.\n this.redrawBuffer = true;\n this.onDataGroupsChanged(dataGroups);\n }\n this._dataGroups = this.updateDataGroups(dataGroups).dataGroups;\n return { dataGroups: this._dataGroups };\n }\n updateDataGroups(dataGroups) {\n return { dataGroups };\n }\n addEntity(entity) {\n this._entityRegistry.addEntity(this.getName(), entity);\n return this;\n }\n create(canvasElement, dataGroups) {\n this.createBuffer(canvasElement);\n this.setDrawAreaRect({\n x: this.getProperty('x', 0),\n y: this.getProperty('y', 0),\n w: canvasElement.width,\n h: canvasElement.height\n });\n this.ctx = canvasElement.getContext('2d');\n return {\n dataGroups,\n plugin: this\n };\n }\n drawBuffer() {\n this.redrawBuffer = false;\n }\n draw(forceRedraw = false) {\n const padding = this.getProperty('padding', 0);\n if (this.needsRedraw || forceRedraw) {\n this.bufferCtx.clearRect(0, 0, this._buffer.width, this._buffer.height);\n this.drawBuffer();\n //console.log('redraw buffer', this.bufferCtx.canvas.width, this.bufferCtx.canvas.height);\n }\n try {\n this.ctx.drawImage(this._buffer, this._fixed ? 0 : this._camera.x, this._fixed ? 0 : this._camera.y, this._drawAreaRect.w, this._drawAreaRect.h, this._drawAreaRect.x + padding, this._drawAreaRect.y + padding, this._drawAreaRect.w - (2 * padding), this._drawAreaRect.h - (2 * padding));\n }\n catch (e) {\n console.warn(e);\n }\n return this;\n }\n getDrawAreaRect() {\n return this._drawAreaRect;\n }\n getPriority() {\n return this._priority;\n }\n getProperty(propertyName, defaultResult) {\n return this._properties[propertyName] ?? defaultResult;\n }\n handleClick(x, y) {\n return this;\n }\n handleHover(x, y) {\n return this;\n }\n handleLeave() {\n this.handleHover(-1, -1);\n return this;\n }\n handleScroll(x, y) {\n return this;\n }\n setBuffer(buffer) {\n this._buffer = buffer;\n this.bufferCtx = buffer.getContext('2d');\n return this;\n }\n setCamera(camera) {\n this._camera = camera;\n return this;\n }\n setDrawAreaRect(rect) {\n this._drawAreaRect = rect;\n return this;\n }\n setEntityRegistry(entityRegistry) {\n this._entityRegistry = entityRegistry;\n return this;\n }\n setProperty(propertyName, value) {\n this._properties[propertyName] = value;\n return this;\n }\n init() {\n return this;\n }\n /**\n * Hook for plugins that have to prepare themselves (e.g. resize their\n * buffer) before the changed data is processed.\n */\n onDataGroupsChanged(dataGroups) {\n }\n createBuffer(canvasElement, width = null, height = null) {\n this._buffer = document.createElement('canvas');\n this._buffer.width = width ?? canvasElement.width;\n this._buffer.height = height ?? canvasElement.height;\n this.bufferCtx = this._buffer.getContext('2d');\n }\n /**\n * Compares the given data groups by content against the ones seen by the\n * last update and remembers the result in `_dataGroupsChanged`. Comparing\n * by content (instead of holding on to the data groups themselves) is what\n * makes manipulations of already known data groups visible.\n */\n detectDataGroupsChange(dataGroups) {\n const signature = JSON.stringify(dataGroups);\n this._dataGroupsChanged = signature !== this._dataGroupsSignature;\n this._dataGroupsSignature = signature;\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/AbstractPlugin.ts?\n}");
238
238
 
239
239
  /***/ },
240
240
 
@@ -245,7 +245,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
245
245
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
246
246
 
247
247
  "use strict";
248
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ERangeType: () => (/* binding */ ERangeType),\n/* harmony export */ \"default\": () => (/* binding */ BarsPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractDiagramPlugin */ \"./src/plugin/AbstractDiagramPlugin.ts\");\n/**\n * Library BarsPlugin\n * Created 05.05.24\n *\n * @author Christoph Ehlers\n */\n\nvar ERangeType;\n(function (ERangeType) {\n ERangeType[\"ZERO_BASED\"] = \"zero_based\";\n ERangeType[\"MIN_MAX\"] = \"min_max\";\n})(ERangeType || (ERangeType = {}));\nclass BarsPlugin extends _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n barGroups = [];\n hoverPosition = { x: 0, y: 0 };\n rangeType = ERangeType.MIN_MAX;\n constructor(props = {}) {\n super({\n animationSpeed: 1,\n enableAnimation: true,\n padding: 0,\n ...props,\n });\n }\n drawBuffer() {\n this.barGroups.map((group) => {\n group.map((bar) => {\n this.bufferCtx.fillStyle = bar.color;\n const hover = this.hoverPosition.x >= bar.x && this.hoverPosition.x <= bar.x + bar.width;\n this.bufferCtx.fillRect(bar.x - (hover ? 1 : 0), bar.y, bar.width + (hover ? 2 : 0), bar.height);\n });\n });\n super.drawBuffer();\n }\n handleHover(x, y) {\n this.hoverPosition = { x, y };\n this.barGroups.map((group) => {\n group.map((bar) => {\n let changed = false;\n if (x >= bar.x && x <= bar.x + bar.width) {\n if (!bar.hovered) {\n changed = true;\n }\n bar.hovered = true;\n }\n else {\n if (bar.hovered) {\n changed = true;\n }\n bar.hovered = false;\n }\n if (changed) {\n this.redrawBuffer = true;\n }\n });\n });\n return this;\n }\n updateDataGroups(dataGroups) {\n if (JSON.stringify(this._dataGroups) !== JSON.stringify(dataGroups)) {\n this.redrawBuffer = true;\n this._dataGroups = dataGroups;\n let maxValue = Math.max(...dataGroups.map((group) => group.infos.max));\n const minValue = Math.min(...dataGroups.map((group) => group.infos.min));\n const range = maxValue - minValue;\n //const minValueZeroDiff = minValue < 0 ? Math.abs(minValue) : 0;\n const viewHeight = this.getDrawAreaRect().h;\n const maxDataLength = Math.max(...dataGroups.map((group) => group.data.length));\n const barWidth = (this.bufferCtx.canvas.width / (maxDataLength * dataGroups.length));\n //const zeroY = this.getDrawAreaRect().y + this.getDrawAreaRect().h - (minValueZeroDiff * viewHeight / maxValue);\n this.barGroups = [];\n this._dataGroups.map((group, groupIndex) => {\n group.data.map((data, index) => {\n while (this.barGroups.length <= index) {\n this.barGroups.push([]);\n }\n const drawArea = this.getDrawAreaRect();\n const percentageValue = Math.round((data.value - minValue) / range * 100);\n const height = (viewHeight / 100) * Math.round(percentageValue);\n const y = viewHeight - (viewHeight / 100) * Math.round(percentageValue);\n const bar = {\n height, // this.getProperty('enableAnimation',false) ? 1 : data.value * viewHeight / maxValue,\n destinationH: 10,\n destinationY: y, //drawArea.y + drawArea.h - (data.valueEnd * viewHeight / maxValue),\n x: (groupIndex * barWidth) + (index * barWidth * dataGroups.length) + drawArea.x + 1,\n y: y, //this.getProperty('enableAnimation',false) ? drawArea.h - barHeight : drawArea.y + drawArea.h - (data.valueEnd * viewHeight / maxValue),\n width: barWidth - 2,\n color: group.color\n };\n this.barGroups[index].push(bar);\n });\n });\n }\n this.updateAnimations();\n return { dataGroups: this._dataGroups };\n }\n updateAnimations() {\n this.barGroups.map((group) => {\n group.map((bar) => {\n if (bar.y > bar.destinationY) {\n this.redrawBuffer = true;\n bar.y -= Math.min(1 * this.getProperty('animationSpeed', 1), bar.y - bar.destinationY);\n }\n if (bar.height < bar.destinationH) {\n this.redrawBuffer = true;\n bar.height += Math.min(1 * this.getProperty('animationSpeed', 1), bar.destinationH - bar.height);\n }\n });\n });\n return this;\n }\n getName() {\n return \"BarsPlugin\";\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/BarsPlugin.ts?\n}");
248
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ERangeType: () => (/* binding */ ERangeType),\n/* harmony export */ \"default\": () => (/* binding */ BarsPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractDiagramPlugin */ \"./src/plugin/AbstractDiagramPlugin.ts\");\n/**\n * Library BarsPlugin\n * Created 05.05.24\n *\n * @author Christoph Ehlers\n */\n\nvar ERangeType;\n(function (ERangeType) {\n ERangeType[\"ZERO_BASED\"] = \"zero_based\";\n ERangeType[\"MIN_MAX\"] = \"min_max\";\n})(ERangeType || (ERangeType = {}));\nclass BarsPlugin extends _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n barGroups = [];\n hoverPosition = { x: 0, y: 0 };\n rangeType = ERangeType.MIN_MAX;\n constructor(props = {}) {\n super({\n animationSpeed: 1,\n enableAnimation: true,\n padding: 0,\n ...props,\n });\n }\n drawBuffer() {\n this.barGroups.map((group) => {\n group.map((bar) => {\n this.bufferCtx.fillStyle = bar.color;\n const hover = this.hoverPosition.x >= bar.x && this.hoverPosition.x <= bar.x + bar.width;\n this.bufferCtx.fillRect(bar.x - (hover ? 1 : 0), bar.y, bar.width + (hover ? 2 : 0), bar.height);\n });\n });\n super.drawBuffer();\n }\n handleHover(x, y) {\n this.hoverPosition = { x, y };\n this.barGroups.map((group) => {\n group.map((bar) => {\n let changed = false;\n if (x >= bar.x && x <= bar.x + bar.width) {\n if (!bar.hovered) {\n changed = true;\n }\n bar.hovered = true;\n }\n else {\n if (bar.hovered) {\n changed = true;\n }\n bar.hovered = false;\n }\n if (changed) {\n this.redrawBuffer = true;\n }\n });\n });\n return this;\n }\n updateDataGroups(dataGroups) {\n if (this._dataGroupsChanged) {\n this.redrawBuffer = true;\n this._dataGroups = dataGroups;\n this.barGroups = [];\n const maxDataLength = dataGroups.length === 0 ? 0 : Math.max(...dataGroups.map((group) => group.data.length));\n if (maxDataLength === 0) {\n // Nothing (left) to draw - e.g. after the data was cleared at runtime.\n this.updateAnimations();\n return { dataGroups: this._dataGroups };\n }\n let maxValue = Math.max(...dataGroups.map((group) => group.infos.max));\n const minValue = Math.min(...dataGroups.map((group) => group.infos.min));\n const range = (maxValue - minValue) === 0 ? 1 : maxValue - minValue;\n //const minValueZeroDiff = minValue < 0 ? Math.abs(minValue) : 0;\n const viewHeight = this.getDrawAreaRect().h;\n const barWidth = (this.bufferCtx.canvas.width / (maxDataLength * dataGroups.length));\n //const zeroY = this.getDrawAreaRect().y + this.getDrawAreaRect().h - (minValueZeroDiff * viewHeight / maxValue);\n this._dataGroups.map((group, groupIndex) => {\n group.data.map((data, index) => {\n while (this.barGroups.length <= index) {\n this.barGroups.push([]);\n }\n const drawArea = this.getDrawAreaRect();\n const percentageValue = Math.round((data.value - minValue) / range * 100);\n const height = (viewHeight / 100) * Math.round(percentageValue);\n const y = viewHeight - (viewHeight / 100) * Math.round(percentageValue);\n const bar = {\n height, // this.getProperty('enableAnimation',false) ? 1 : data.value * viewHeight / maxValue,\n destinationH: 10,\n destinationY: y, //drawArea.y + drawArea.h - (data.valueEnd * viewHeight / maxValue),\n x: (groupIndex * barWidth) + (index * barWidth * dataGroups.length) + drawArea.x + 1,\n y: y, //this.getProperty('enableAnimation',false) ? drawArea.h - barHeight : drawArea.y + drawArea.h - (data.valueEnd * viewHeight / maxValue),\n width: barWidth - 2,\n color: group.color\n };\n this.barGroups[index].push(bar);\n });\n });\n }\n this.updateAnimations();\n return { dataGroups: this._dataGroups };\n }\n updateAnimations() {\n this.barGroups.map((group) => {\n group.map((bar) => {\n if (bar.y > bar.destinationY) {\n this.redrawBuffer = true;\n bar.y -= Math.min(1 * this.getProperty('animationSpeed', 1), bar.y - bar.destinationY);\n }\n if (bar.height < bar.destinationH) {\n this.redrawBuffer = true;\n bar.height += Math.min(1 * this.getProperty('animationSpeed', 1), bar.destinationH - bar.height);\n }\n });\n });\n return this;\n }\n getName() {\n return \"BarsPlugin\";\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/BarsPlugin.ts?\n}");
249
249
 
250
250
  /***/ },
251
251
 
@@ -267,7 +267,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
267
267
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
268
268
 
269
269
  "use strict";
270
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ERangeType: () => (/* binding */ ERangeType),\n/* harmony export */ \"default\": () => (/* binding */ DiagramLine)\n/* harmony export */ });\n/* harmony import */ var _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractDiagramPlugin */ \"./src/plugin/AbstractDiagramPlugin.ts\");\n/* harmony import */ var _Event_TooltipEvent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Event/TooltipEvent */ \"./src/Event/TooltipEvent.ts\");\n/**\n * Library DiagramLine\n * Created 26.11.22\n *\n * @author Christoph Ehlers\n */\n\n\nvar ERangeType;\n(function (ERangeType) {\n ERangeType[\"ZERO_BASED\"] = \"zero_based\";\n ERangeType[\"MIN_MAX\"] = \"min_max\";\n})(ERangeType || (ERangeType = {}));\nclass DiagramLine extends _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n bulletPointRadius = 2;\n bulletPointRadiusHover = 5;\n dataPoints = [];\n helpLines = [];\n hoverPosition = { x: 0, y: 0 };\n rangeType = ERangeType.MIN_MAX;\n syncGroupsPosition = false;\n zeroLineValue = 0;\n zeroLineValuePercentage = 0;\n constructor(props = {}) {\n super({\n fill: true,\n showBulletPoints: false,\n showHelpLines: false,\n showZeroLine: false,\n padding: 0,\n ...props\n });\n }\n drawHelpLines() {\n if (!this.getProperty('showHelpLines', false))\n return this;\n this.helpLines.map((helpLine) => {\n this.bufferCtx.strokeStyle = helpLine.color;\n this.bufferCtx.fillStyle = helpLine.color;\n this.bufferCtx.beginPath();\n this.bufferCtx.moveTo(super.getDrawAreaRect().x, helpLine.y);\n this.bufferCtx.lineTo(super.getDrawAreaRect().x + this.bufferCtx.canvas.width, helpLine.y);\n this.bufferCtx.stroke();\n this.bufferCtx.fillText(helpLine.label, super.getDrawAreaRect().x, helpLine.y);\n });\n return this;\n }\n drawBuffer() {\n const singlePercentageHeight = this.getDrawAreaRect().h / 100; // 1% height\n this.drawHelpLines();\n if (this._showZeroLine()) {\n this.bufferCtx.strokeStyle = '#000000';\n this.bufferCtx.beginPath();\n this.bufferCtx.moveTo(this.getDrawAreaRect().x, this.getDrawAreaRect().y + this.getDrawAreaRect().h - singlePercentageHeight * this.zeroLineValuePercentage);\n this.bufferCtx.lineTo(this.getDrawAreaRect().x + this.bufferCtx.canvas.width, this.getDrawAreaRect().y + this.getDrawAreaRect().h - singlePercentageHeight * this.zeroLineValuePercentage);\n this.bufferCtx.stroke();\n }\n //console.log('viewHeight', this.getDrawAreaRect().h, this);\n this.dataPoints.map(group => {\n this.bufferCtx.beginPath();\n let lastX = 0;\n group.map((dataPoint, index) => {\n this.bufferCtx.strokeStyle = dataPoint.color;\n this.bufferCtx.fillStyle = dataPoint.color + '88';\n this.bufferCtx.lineWidth = dataPoint.isHighlighted ? 2 : 1;\n if (index === 0) {\n if (this.getProperty('fill', false)) {\n this.bufferCtx.moveTo(dataPoint.x, this.getDrawAreaRect().y + this.getDrawAreaRect().h);\n this.bufferCtx.lineTo(dataPoint.x, dataPoint.y);\n return;\n }\n this.bufferCtx.moveTo(dataPoint.x, dataPoint.y);\n }\n else {\n this.bufferCtx.lineTo(dataPoint.x, dataPoint.y);\n }\n lastX = dataPoint.x;\n });\n if (this.getProperty('fill', false)) {\n this.bufferCtx.lineTo(lastX, this.getDrawAreaRect().y + this.getDrawAreaRect().h);\n this.bufferCtx.fill();\n }\n this.bufferCtx.stroke();\n });\n if (this.getProperty('showBulletPoints', false)) {\n this.dataPoints.map(group => {\n group.map((dataPoint) => {\n const mouseDistance = Math.sqrt(Math.pow(this.hoverPosition.x - dataPoint.x, 2) + Math.pow(this.hoverPosition.y - dataPoint.y, 2));\n if (mouseDistance < this.bulletPointRadiusHover) {\n _Event_TooltipEvent__WEBPACK_IMPORTED_MODULE_1__[\"default\"].dispatch('test', {});\n }\n this.bufferCtx.fillStyle = dataPoint.color;\n this.bufferCtx.beginPath();\n this.bufferCtx.arc(dataPoint.x, dataPoint.y, (mouseDistance < this.bulletPointRadiusHover ? this.bulletPointRadiusHover : this.bulletPointRadius), 0, 2 * Math.PI);\n this.bufferCtx.fill();\n });\n });\n }\n return this;\n }\n handleHover(x, y) {\n this.hoverPosition = { x, y };\n return this;\n }\n updateDataGroups(dataGroups) {\n if (JSON.stringify(this._dataGroups) === JSON.stringify(dataGroups))\n return { dataGroups };\n this._dataGroups = dataGroups;\n const maxValue = Math.max(...dataGroups.map((group) => group.infos.max));\n const minValue = Math.min(...this._dataGroups.map((group) => group.infos.min), (this._showZeroLine() ? 0 : maxValue));\n this.zeroLineValue = Math.min(0, ...dataGroups.map((group) => group.infos.min)) * -1;\n this.zeroLineValuePercentage = this.zeroLineValue / (maxValue + this.zeroLineValue) * 100;\n const groupWithMostData = this._dataGroups.reduce((prev, current) => prev.data.length > current.data.length ? prev : current);\n const pointGap = this.calcPointGap(groupWithMostData);\n const largestDecimalStep = Math.max(...this._dataGroups.map((group) => group.infos.largestDecimalStep));\n const globalRange = maxValue - minValue;\n this.helpLines = [];\n for (let i = 1; i <= 10; i++) {\n let height = (this.getDrawAreaRect().h / 100) * Math.round(((i * largestDecimalStep) - minValue) / globalRange * 100);\n if (largestDecimalStep * i < minValue || largestDecimalStep * i > maxValue) {\n continue;\n }\n this.helpLines.push({\n color: '#ee4444',\n y: Math.round(this.getDrawAreaRect().h - height),\n label: (i * largestDecimalStep).toString()\n });\n }\n this.dataPoints = this._dataGroups.map((dataGroup) => {\n return dataGroup.data.map((dataPoint, index) => {\n let height = this.getDrawAreaRect().h - (this.getDrawAreaRect().h / 100) * Math.round((dataPoint.value - minValue) / globalRange * 100);\n console.log(height, 'height', dataPoint.value, {\n height,\n globalRange,\n minValue,\n maxValue,\n largestDecimalStep,\n i: largestDecimalStep * index,\n viewHeight: this.getDrawAreaRect().h,\n pointGap,\n dataPoint,\n dataGroup,\n index\n });\n if (dataPoint.empty)\n return undefined;\n return {\n ...dataPoint,\n x: this.getDrawAreaRect().x + pointGap * index,\n y: height,\n color: dataGroup.color,\n };\n }).filter((dataPoint) => dataPoint !== undefined);\n });\n return { dataGroups };\n }\n getDrawAreaRect() {\n const { x, y, h, w } = super.getDrawAreaRect();\n const manipulator = 0; //(this.getProperty('showBulletPoints', false) ? this.bulletPointRadiusHover : 0);\n return {\n x: x + manipulator,\n y: y + manipulator,\n h: h - (manipulator * 2),\n w: w - (manipulator * 2)\n };\n }\n getName() {\n return \"DiagramLine\";\n }\n _showZeroLine() {\n return this.getProperty('showZeroLine', false);\n }\n calcPointGap(dataGroup) {\n return (this.getDrawAreaRect().w - (this.bulletPointRadius * 2)) / (dataGroup.data.length - 1);\n /*return this.getDrawAreaRect().w /\n (this.getProperty('viewSize', -1) === -1 ?\n (this.syncGroupsPosition ? Math.max(...this._dataGroups.map((group) => group.data.length - 1)) : dataGroup.data.length - 1) :\n this.getProperty('viewSize', -1) - 1)\n ;*/\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/DiagramLine.ts?\n}");
270
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ERangeType: () => (/* binding */ ERangeType),\n/* harmony export */ \"default\": () => (/* binding */ DiagramLine)\n/* harmony export */ });\n/* harmony import */ var _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractDiagramPlugin */ \"./src/plugin/AbstractDiagramPlugin.ts\");\n/* harmony import */ var _Event_TooltipEvent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Event/TooltipEvent */ \"./src/Event/TooltipEvent.ts\");\n/**\n * Library DiagramLine\n * Created 26.11.22\n *\n * @author Christoph Ehlers\n */\n\n\nvar ERangeType;\n(function (ERangeType) {\n ERangeType[\"ZERO_BASED\"] = \"zero_based\";\n ERangeType[\"MIN_MAX\"] = \"min_max\";\n})(ERangeType || (ERangeType = {}));\nclass DiagramLine extends _AbstractDiagramPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n bulletPointRadius = 2;\n bulletPointRadiusHover = 5;\n dataPoints = [];\n helpLines = [];\n hoverPosition = { x: 0, y: 0 };\n rangeType = ERangeType.MIN_MAX;\n syncGroupsPosition = false;\n zeroLineValue = 0;\n zeroLineValuePercentage = 0;\n constructor(props = {}) {\n super({\n fill: true,\n showBulletPoints: false,\n showHelpLines: false,\n showZeroLine: false,\n padding: 0,\n ...props\n });\n }\n drawHelpLines() {\n if (!this.getProperty('showHelpLines', false))\n return this;\n this.helpLines.map((helpLine) => {\n this.bufferCtx.strokeStyle = helpLine.color;\n this.bufferCtx.fillStyle = helpLine.color;\n this.bufferCtx.beginPath();\n this.bufferCtx.moveTo(super.getDrawAreaRect().x, helpLine.y);\n this.bufferCtx.lineTo(super.getDrawAreaRect().x + this.bufferCtx.canvas.width, helpLine.y);\n this.bufferCtx.stroke();\n this.bufferCtx.fillText(helpLine.label, super.getDrawAreaRect().x, helpLine.y);\n });\n return this;\n }\n drawBuffer() {\n const singlePercentageHeight = this.getDrawAreaRect().h / 100; // 1% height\n this.drawHelpLines();\n if (this._showZeroLine()) {\n this.bufferCtx.strokeStyle = '#000000';\n this.bufferCtx.beginPath();\n this.bufferCtx.moveTo(this.getDrawAreaRect().x, this.getDrawAreaRect().y + this.getDrawAreaRect().h - singlePercentageHeight * this.zeroLineValuePercentage);\n this.bufferCtx.lineTo(this.getDrawAreaRect().x + this.bufferCtx.canvas.width, this.getDrawAreaRect().y + this.getDrawAreaRect().h - singlePercentageHeight * this.zeroLineValuePercentage);\n this.bufferCtx.stroke();\n }\n //console.log('viewHeight', this.getDrawAreaRect().h, this);\n this.dataPoints.map(group => {\n this.bufferCtx.beginPath();\n let lastX = 0;\n group.map((dataPoint, index) => {\n this.bufferCtx.strokeStyle = dataPoint.color;\n this.bufferCtx.fillStyle = dataPoint.color + '88';\n this.bufferCtx.lineWidth = dataPoint.isHighlighted ? 2 : 1;\n if (index === 0) {\n if (this.getProperty('fill', false)) {\n this.bufferCtx.moveTo(dataPoint.x, this.getDrawAreaRect().y + this.getDrawAreaRect().h);\n this.bufferCtx.lineTo(dataPoint.x, dataPoint.y);\n return;\n }\n this.bufferCtx.moveTo(dataPoint.x, dataPoint.y);\n }\n else {\n this.bufferCtx.lineTo(dataPoint.x, dataPoint.y);\n }\n lastX = dataPoint.x;\n });\n if (this.getProperty('fill', false)) {\n this.bufferCtx.lineTo(lastX, this.getDrawAreaRect().y + this.getDrawAreaRect().h);\n this.bufferCtx.fill();\n }\n this.bufferCtx.stroke();\n });\n if (this.getProperty('showBulletPoints', false)) {\n this.dataPoints.map(group => {\n group.map((dataPoint) => {\n const mouseDistance = Math.sqrt(Math.pow(this.hoverPosition.x - dataPoint.x, 2) + Math.pow(this.hoverPosition.y - dataPoint.y, 2));\n if (mouseDistance < this.bulletPointRadiusHover) {\n _Event_TooltipEvent__WEBPACK_IMPORTED_MODULE_1__[\"default\"].dispatch('test', {});\n }\n this.bufferCtx.fillStyle = dataPoint.color;\n this.bufferCtx.beginPath();\n this.bufferCtx.arc(dataPoint.x, dataPoint.y, (mouseDistance < this.bulletPointRadiusHover ? this.bulletPointRadiusHover : this.bulletPointRadius), 0, 2 * Math.PI);\n this.bufferCtx.fill();\n });\n });\n }\n return this;\n }\n handleHover(x, y) {\n this.hoverPosition = { x, y };\n return this;\n }\n updateDataGroups(dataGroups) {\n if (!this._dataGroupsChanged)\n return { dataGroups };\n this._dataGroups = dataGroups;\n if (dataGroups.length === 0 || dataGroups.every((dataGroup) => dataGroup.data.length === 0)) {\n // Nothing (left) to draw - e.g. after the data was cleared at runtime.\n this.dataPoints = [];\n this.helpLines = [];\n return { dataGroups };\n }\n const maxValue = Math.max(...dataGroups.map((group) => group.infos.max));\n const minValue = Math.min(...this._dataGroups.map((group) => group.infos.min), (this._showZeroLine() ? 0 : maxValue));\n this.zeroLineValue = Math.min(0, ...dataGroups.map((group) => group.infos.min)) * -1;\n this.zeroLineValuePercentage = this.zeroLineValue / (maxValue + this.zeroLineValue) * 100;\n const groupWithMostData = this._dataGroups.reduce((prev, current) => prev.data.length > current.data.length ? prev : current);\n const pointGap = this.calcPointGap(groupWithMostData);\n const largestDecimalStep = Math.max(...this._dataGroups.map((group) => group.infos.largestDecimalStep));\n const globalRange = (maxValue - minValue) === 0 ? 1 : maxValue - minValue;\n this.helpLines = [];\n for (let i = 1; i <= 10; i++) {\n let height = (this.getDrawAreaRect().h / 100) * Math.round(((i * largestDecimalStep) - minValue) / globalRange * 100);\n if (largestDecimalStep * i < minValue || largestDecimalStep * i > maxValue) {\n continue;\n }\n this.helpLines.push({\n color: '#ee4444',\n y: Math.round(this.getDrawAreaRect().h - height),\n label: (i * largestDecimalStep).toString()\n });\n }\n this.dataPoints = this._dataGroups.map((dataGroup) => {\n return dataGroup.data.map((dataPoint, index) => {\n let height = this.getDrawAreaRect().h - (this.getDrawAreaRect().h / 100) * Math.round((dataPoint.value - minValue) / globalRange * 100);\n if (dataPoint.empty)\n return undefined;\n return {\n ...dataPoint,\n x: this.getDrawAreaRect().x + pointGap * index,\n y: height,\n color: dataGroup.color,\n };\n }).filter((dataPoint) => dataPoint !== undefined);\n });\n return { dataGroups };\n }\n getDrawAreaRect() {\n const { x, y, h, w } = super.getDrawAreaRect();\n const manipulator = 0; //(this.getProperty('showBulletPoints', false) ? this.bulletPointRadiusHover : 0);\n return {\n x: x + manipulator,\n y: y + manipulator,\n h: h - (manipulator * 2),\n w: w - (manipulator * 2)\n };\n }\n getName() {\n return \"DiagramLine\";\n }\n _showZeroLine() {\n return this.getProperty('showZeroLine', false);\n }\n calcPointGap(dataGroup) {\n if (dataGroup.data.length < 2) {\n return this.getDrawAreaRect().w - (this.bulletPointRadius * 2);\n }\n return (this.getDrawAreaRect().w - (this.bulletPointRadius * 2)) / (dataGroup.data.length - 1);\n /*return this.getDrawAreaRect().w /\n (this.getProperty('viewSize', -1) === -1 ?\n (this.syncGroupsPosition ? Math.max(...this._dataGroups.map((group) => group.data.length - 1)) : dataGroup.data.length - 1) :\n this.getProperty('viewSize', -1) - 1)\n ;*/\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/DiagramLine.ts?\n}");
271
271
 
272
272
  /***/ },
273
273
 
@@ -278,7 +278,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
278
278
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
279
279
 
280
280
  "use strict";
281
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ EnrichGroupInfosPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractPlugin */ \"./src/plugin/AbstractPlugin.ts\");\n/**\n * Library EnrichGroupInfosPlugin\n * Created 05.05,24\n *\n * @author Christoph Ehlers\n */\n\nclass EnrichGroupInfosPlugin extends _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor() {\n super();\n this._priority = 1;\n }\n updateDataGroups(dataGroups) {\n if (JSON.stringify(this._dataGroups) === JSON.stringify(dataGroups))\n return { dataGroups };\n console.log('EnrichGroupInfosPlugin:', dataGroups);\n this._dataGroups = dataGroups.map((dataGroup) => {\n const values = dataGroup.data.map((data) => data.value);\n const valueStarts = dataGroup.data.map((data) => data.valueStart ?? data.value);\n const min = Math.min(...valueStarts);\n const max = Math.max(...values);\n const range = max - min;\n return {\n ...dataGroup,\n infos: {\n ...dataGroup.infos,\n largestDecimalStep: Math.max(this.getLargestDecimalStep(Math.max(...values)), 0),\n max,\n min,\n range,\n valuePercentage: values.map((value) => (value - min) / (max - min) * 100)\n }\n };\n });\n console.log('EnrichGroupInfosPlugin:', this._dataGroups);\n return {\n dataGroups: this._dataGroups\n };\n }\n getLargestDecimalStep(x) {\n return Math.pow(10, Math.floor(Math.log10(x)));\n }\n getName() {\n return \"EnrichGroupInfosPlugin\";\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/EnrichGroupInfosPlugin.ts?\n}");
281
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ EnrichGroupInfosPlugin)\n/* harmony export */ });\n/* harmony import */ var _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractPlugin */ \"./src/plugin/AbstractPlugin.ts\");\n/**\n * Library EnrichGroupInfosPlugin\n * Created 05.05,24\n *\n * @author Christoph Ehlers\n */\n\nclass EnrichGroupInfosPlugin extends _AbstractPlugin__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor() {\n super();\n this._priority = 1;\n }\n updateDataGroups(dataGroups) {\n if (!this._dataGroupsChanged)\n return { dataGroups: this._dataGroups };\n this._dataGroups = dataGroups.map((dataGroup) => {\n const values = dataGroup.data.map((data) => data.value);\n const valueStarts = dataGroup.data.map((data) => data.valueStart ?? data.value);\n // A group may be empty (e.g. right after clearing or before the\n // first value was added), so the infos have to stay finite.\n const min = values.length === 0 ? 0 : Math.min(...valueStarts);\n const max = values.length === 0 ? 0 : Math.max(...values);\n const range = max - min;\n return {\n ...dataGroup,\n infos: {\n ...dataGroup.infos,\n largestDecimalStep: Math.max(this.getLargestDecimalStep(max), 0),\n max,\n min,\n range,\n valuePercentage: values.map((value) => range === 0 ? 0 : (value - min) / range * 100)\n }\n };\n });\n return {\n dataGroups: this._dataGroups\n };\n }\n getLargestDecimalStep(x) {\n if (x <= 0) {\n return 0;\n }\n return Math.pow(10, Math.floor(Math.log10(x)));\n }\n getName() {\n return \"EnrichGroupInfosPlugin\";\n }\n}\n\n\n//# sourceURL=webpack://@cehlers88/chart/./src/plugin/EnrichGroupInfosPlugin.ts?\n}");
282
282
 
283
283
  /***/ },
284
284
 
@@ -1,6 +1,20 @@
1
1
  import { IChartPlugin } from "./IChartPlugin";
2
+ import { TDataGroup } from "../type/TDataGroup";
3
+ import { IChartEngine } from "./IChartEngine";
2
4
  export interface ICanvasDiagram {
3
5
  addPlugin(plugin: any): ICanvasDiagram;
6
+ addDataGroup(dataGroup: TDataGroup): ICanvasDiagram;
7
+ addValue(value: any, groupName?: string): ICanvasDiagram;
8
+ clearData(): ICanvasDiagram;
9
+ getDataGroup(group: string | number): TDataGroup | undefined;
10
+ getDataGroups(): TDataGroup[];
11
+ getEngine(): IChartEngine | undefined;
4
12
  getPlugin(pluginName: string): IChartPlugin | undefined;
13
+ removeDataGroup(group: string | number): ICanvasDiagram;
14
+ removeValue(group: string | number, dataIndex: number): ICanvasDiagram;
15
+ setData(dataDefinition: string | any[] | object): ICanvasDiagram;
16
+ setDataGroups(dataGroups: TDataGroup[]): ICanvasDiagram;
17
+ setValue(group: string | number, dataIndex: number, value: any): ICanvasDiagram;
5
18
  start(): ICanvasDiagram;
19
+ stop(): ICanvasDiagram;
6
20
  }
@@ -4,7 +4,15 @@ export interface IChartEngine {
4
4
  addValue(value: any, groupName?: string): IChartEngine;
5
5
  addDataGroup(dataGroup: TDataGroup): IChartEngine;
6
6
  addPlugin(plugin: IChartPlugin): IChartEngine;
7
+ clearData(): IChartEngine;
8
+ getDataGroup(group: string | number): TDataGroup | undefined;
9
+ getDataGroups(): TDataGroup[];
7
10
  getPlugin(pluginName: string): IChartPlugin;
11
+ removeDataGroup(group: string | number): IChartEngine;
12
+ removeValue(group: string | number, dataIndex: number): IChartEngine;
13
+ setData(dataDefinition: string | any[] | object): IChartEngine;
14
+ setDataGroups(dataGroups: TDataGroup[]): IChartEngine;
15
+ setValue(group: string | number, dataIndex: number, value: any): IChartEngine;
8
16
  draw(): IChartEngine;
9
17
  update(): IChartEngine;
10
18
  }
@@ -6,8 +6,6 @@ export default abstract class AbstractDiagramPlugin extends AbstractPlugin {
6
6
  viewSize?: number;
7
7
  [key: string]: any;
8
8
  });
9
- update(dataGroups: TDataGroup[]): {
10
- dataGroups: TDataGroup[];
11
- };
12
- protected updateBufferSize(dataGroups: any): number;
9
+ protected onDataGroupsChanged(dataGroups: TDataGroup[]): void;
10
+ protected updateBufferSize(dataGroups: TDataGroup[]): number;
13
11
  }
@@ -19,7 +19,9 @@ export default abstract class AbstractPlugin implements IChartPlugin {
19
19
  protected bufferCtx: CanvasRenderingContext2D;
20
20
  protected ctx: CanvasRenderingContext2D;
21
21
  protected redrawBuffer: boolean;
22
+ protected _dataGroupsChanged: boolean;
22
23
  private _buffer;
24
+ private _dataGroupsSignature;
23
25
  private _stateChangedListener;
24
26
  private _drawAreaRect;
25
27
  private _properties;
@@ -57,5 +59,17 @@ export default abstract class AbstractPlugin implements IChartPlugin {
57
59
  setEntityRegistry(entityRegistry: EntityRegistry): AbstractPlugin;
58
60
  setProperty(propertyName: string, value: any): AbstractPlugin;
59
61
  init(): AbstractPlugin;
62
+ /**
63
+ * Hook for plugins that have to prepare themselves (e.g. resize their
64
+ * buffer) before the changed data is processed.
65
+ */
66
+ protected onDataGroupsChanged(dataGroups: TDataGroup[]): void;
60
67
  protected createBuffer(canvasElement: HTMLCanvasElement, width?: number | null, height?: number | null): void;
68
+ /**
69
+ * Compares the given data groups by content against the ones seen by the
70
+ * last update and remembers the result in `_dataGroupsChanged`. Comparing
71
+ * by content (instead of holding on to the data groups themselves) is what
72
+ * makes manipulations of already known data groups visible.
73
+ */
74
+ private detectDataGroupsChange;
61
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cehlers88/chart",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A library to create charts using JavaScript and Canvas-Element.",
5
5
  "main": "dist/index.js",
6
6
  "publishConfig": {
@@ -34,6 +34,7 @@
34
34
  "@types/jest": "^29.5.13",
35
35
  "css-loader": "^7.1.2",
36
36
  "jest": "^29.7.0",
37
+ "jest-environment-jsdom": "^29.7.0",
37
38
  "style-loader": "^4.0.0",
38
39
  "ts-jest": "^29.2.5",
39
40
  "ts-loader": "^9.5.1",