@pacem/pacem-charts 1.0.0-abel

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.
@@ -0,0 +1,1623 @@
1
+ (function (pacemFoundation, pacemCore) {
2
+ 'use strict';
3
+
4
+ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
5
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
7
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
9
+ };
10
+ //namespace Pacem.Components.Charts {
11
+ const MANAGED_EVENTS = ['keydown', 'keyup', 'click', 'dblclick', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave', 'mousedown', 'mouseup', 'mousemove', 'contextmenu'];
12
+ //function logN(N, x) {
13
+ // return Math.log10(x) / Math.log10(N);
14
+ //}
15
+ const MSECS_PER_DAY = 1000 * 60 * 60 * 24;
16
+ const MAX_X_LABELS = 10;
17
+ const MAX_Y_LABELS = 10;
18
+ const SERIES_DATAITEM = 'pacem:chart-series:dataitem';
19
+ const SERIES_SERIES = 'pacem:chart-series:series';
20
+ function getEvenlySpaced(items, type, min, max, formatOrLang, labels = MAX_X_LABELS) {
21
+ const length = (type === 'number' || type === 'date') ? (max - min) : Math.max(1, items.length - 1);
22
+ const gaps = labels - 1;
23
+ var retval = [];
24
+ var step = 1;
25
+ for (var l = gaps; l > 1; l--) {
26
+ if ((length % l) === 0) {
27
+ step = length / l;
28
+ break;
29
+ }
30
+ }
31
+ if (step === 1 /* coprime number? */ && length > labels) {
32
+ step = length;
33
+ }
34
+ const fnDate = typeof formatOrLang === 'function' ? formatOrLang : (step >= MSECS_PER_DAY ? ((d) => d.toLocaleDateString(formatOrLang)) : ((d) => d.toLocaleTimeString(formatOrLang)));
35
+ const fnDateFirst = typeof formatOrLang === 'function' ? formatOrLang : (step < MSECS_PER_DAY ? ((d) => d.toLocaleString(formatOrLang)) : fnDate);
36
+ const fnNum = typeof formatOrLang === 'function' ? formatOrLang : (n) => n.toLocaleString(formatOrLang);
37
+ for (var j = 0; j <= length; j += step) {
38
+ let label;
39
+ switch (type) {
40
+ case 'string':
41
+ if (j >= items.length) {
42
+ continue;
43
+ }
44
+ label = items[j].label;
45
+ break;
46
+ case 'number':
47
+ label = fnNum(min + j);
48
+ break;
49
+ case 'date':
50
+ let date = pacemCore.Utils.parseDate(min + j);
51
+ let fn = (j == 0) ? fnDateFirst : fnDate;
52
+ label = fn(date);
53
+ break;
54
+ default:
55
+ throw 'Not supported.';
56
+ }
57
+ retval.push(label);
58
+ }
59
+ return retval;
60
+ }
61
+ function getRoundedBoundaries(min, max, desiredSteps) {
62
+ desiredSteps ??= Math.min(bestGuessedDensity(min, max), MAX_Y_LABELS);
63
+ const roughStep = (max - min) / desiredSteps;
64
+ const magnitude = Math.pow(10, Math.floor(Math.log10(roughStep)));
65
+ const step = [1, 2, 5, 10].map(n => n * magnitude).filter(s => s >= roughStep).reduce((min, s) => Math.min(min, s), Number.POSITIVE_INFINITY);
66
+ return {
67
+ min: Math.floor(min / step) * step,
68
+ max: Math.ceil(max / step) * step,
69
+ round: step
70
+ };
71
+ }
72
+ // Deprecated
73
+ //function getRoundedBoundariesOld(a0: number, a1: number, steps?: number) {
74
+ // if (!(steps > 0)) {
75
+ // steps = bestGuessedDensity(a0, a1);
76
+ // }
77
+ // const magn = logN(steps, a1 - a0),
78
+ // exp = magn % 1 == 0 ? magn - 1 : magn,
79
+ // rounder = Math.pow(steps, Math.floor(exp));
80
+ // return {
81
+ // min: Math.floor(a0 / rounder) * rounder,
82
+ // max: Math.ceil(a1 / rounder) * rounder,
83
+ // round: rounder
84
+ // };
85
+ //}
86
+ function bestGuessedDensity(min, max) {
87
+ const delta = max - min;
88
+ if (!(delta > 0)) {
89
+ return 2;
90
+ }
91
+ const oom = Math.floor(Math.log10(delta));
92
+ const exp = Math.pow(10, -oom);
93
+ // bring everything to a single digit format
94
+ if (oom != 0) {
95
+ return bestGuessedDensity(min * exp, max * exp);
96
+ }
97
+ const capFn = (n) => {
98
+ const norm = Math.floor(Math.abs(n) * 10), limit = norm + 10 - (norm % 10);
99
+ return limit.roundoff();
100
+ };
101
+ const b = capFn(delta);
102
+ let a = 10;
103
+ if (min !== 0) {
104
+ a = capFn(Math.abs(max));
105
+ }
106
+ const ret = gcd(a, b);
107
+ return ret === 1 ? b : Math.max(ret, 10 - ret);
108
+ }
109
+ function gcd(a, b) {
110
+ if (a <= 0) {
111
+ return b;
112
+ }
113
+ return gcd(b % a, a);
114
+ }
115
+ class ChartEvent extends pacemCore.CustomUIEvent {
116
+ constructor(type, eventInit, originalEvent) {
117
+ super(type, eventInit, originalEvent);
118
+ }
119
+ }
120
+ let PacemChartSeriesElement = class PacemChartSeriesElement extends pacemCore.Components.PacemItemElement {
121
+ get values() {
122
+ return this.datasource;
123
+ }
124
+ };
125
+ __decorate$3([
126
+ pacemCore.Watch({ emit: true, converter: pacemCore.PropertyConverters.Json })
127
+ ], PacemChartSeriesElement.prototype, "datasource", void 0);
128
+ __decorate$3([
129
+ pacemCore.Watch({ emit: true, converter: pacemCore.PropertyConverters.String })
130
+ ], PacemChartSeriesElement.prototype, "label", void 0);
131
+ __decorate$3([
132
+ pacemCore.Watch({ emit: true, converter: pacemCore.PropertyConverters.String })
133
+ ], PacemChartSeriesElement.prototype, "color", void 0);
134
+ __decorate$3([
135
+ pacemCore.Watch({ emit: true, converter: pacemCore.PropertyConverters.Boolean })
136
+ ], PacemChartSeriesElement.prototype, "datapoints", void 0);
137
+ __decorate$3([
138
+ pacemCore.Watch( /* to be set programmatically (internally) */)
139
+ ], PacemChartSeriesElement.prototype, "_uiElements", void 0);
140
+ PacemChartSeriesElement = __decorate$3([
141
+ pacemCore.CustomElement({ tagName: pacemCore.P + '-chart-series' })
142
+ ], PacemChartSeriesElement);
143
+ const SVG_NS$2 = "http://www.w3.org/2000/svg";
144
+ class PacemSeriesChartElement extends pacemCore.Components.PacemItemsContainerElement {
145
+ constructor() {
146
+ super();
147
+ this._itemPropertyChangedCallback = (evt) => {
148
+ const propName = evt.detail.propertyName;
149
+ if (propName === 'datasource'
150
+ || propName === 'label'
151
+ || propName === 'datapoints'
152
+ || propName === 'cssClass'
153
+ || propName === 'color') {
154
+ this.draw();
155
+ }
156
+ };
157
+ this._series = [];
158
+ this._resizeHandler = (evt) => {
159
+ this._size = evt.detail;
160
+ this.draw();
161
+ };
162
+ // #endregion
163
+ this._broadcastHandler = (e) => {
164
+ /* Don't mess with the events:
165
+ * keep the original (trusted) events with their well-known names
166
+ * and provide a method to retrieve the 'ChartDataItem' based on the the eventTarget. */
167
+ const element = e.currentTarget;
168
+ const dataItem = pacemCore.CustomElementUtils.getAttachedPropertyValue(element, SERIES_DATAITEM);
169
+ if (pacemCore.Utils.isNull(dataItem)) {
170
+ return;
171
+ }
172
+ const chart = this, anchorPoint = chart.getAnchorPoint(element);
173
+ const evt = new ChartEvent('item' + e.type, { detail: { dataItem, anchorPoint } }, e);
174
+ const series = pacemCore.CustomElementUtils.getAttachedPropertyValue(element, SERIES_SERIES);
175
+ if (series instanceof PacemChartSeriesElement) {
176
+ series.dispatchEvent(evt);
177
+ }
178
+ chart.dispatchEvent(evt);
179
+ };
180
+ this._key = pacemCore.Utils.uniqueCode();
181
+ }
182
+ validate(item) {
183
+ return item instanceof PacemChartSeriesElement;
184
+ }
185
+ register(item) {
186
+ if (super.register(item)) {
187
+ item.addEventListener(pacemCore.PropertyChangeEventName, this._itemPropertyChangedCallback, false);
188
+ return true;
189
+ }
190
+ return false;
191
+ }
192
+ unregister(item) {
193
+ if (super.unregister(item)) {
194
+ item.removeEventListener(pacemCore.PropertyChangeEventName, this._itemPropertyChangedCallback, false);
195
+ return true;
196
+ }
197
+ return false;
198
+ }
199
+ propertyChangedCallback(name, old, val, first) {
200
+ super.propertyChangedCallback(name, old, val, first);
201
+ if (name === 'target') {
202
+ if (this._div != old) {
203
+ this._div && this._div.remove();
204
+ }
205
+ // reset
206
+ this._div = null;
207
+ this._body = null; // <- get checked on next draw
208
+ const eold = old;
209
+ if (eold) {
210
+ eold.classList.remove(pacemCore.PCSS + '-chart-area');
211
+ eold.innerHTML = '';
212
+ }
213
+ this._ensureResizer();
214
+ this.draw();
215
+ }
216
+ else if (!first) {
217
+ switch (name) {
218
+ case 'items':
219
+ this._databindAndDrawDebounced();
220
+ break;
221
+ case 'datasource':
222
+ this._databind();
223
+ // fall down to draw() call.
224
+ case 'yAxisDensity':
225
+ case 'xAxisDensity':
226
+ case 'xAxisType':
227
+ case 'yAxisMax':
228
+ case 'xAxisPosition':
229
+ case 'yAxisFormat':
230
+ this.draw();
231
+ break;
232
+ }
233
+ }
234
+ }
235
+ _databindAndDrawDebounced() {
236
+ cancelAnimationFrame(this._handle);
237
+ this._handle = requestAnimationFrame(() => {
238
+ this._databind();
239
+ this.draw();
240
+ });
241
+ }
242
+ _databind() {
243
+ this._datasource = pacemCore.Utils.isNullOrEmpty(this.datasource) ? this.items : this.datasource;
244
+ }
245
+ disconnectedCallback() {
246
+ this._div && this._div.remove();
247
+ const resizer = this._resizer;
248
+ if (!pacemCore.Utils.isNull(resizer)) {
249
+ resizer.removeEventListener(pacemCore.Components.ResizeEventName, this._resizeHandler, false);
250
+ resizer.remove();
251
+ this._resizer = null;
252
+ }
253
+ super.disconnectedCallback();
254
+ }
255
+ viewActivatedCallback() {
256
+ super.viewActivatedCallback();
257
+ this._ensureResizer();
258
+ this._databind();
259
+ this.draw();
260
+ }
261
+ _ensureResizer(target = this.target || this._div) {
262
+ if (pacemCore.Utils.isNull(this._resizer)) {
263
+ const shell = pacemCore.CustomElementUtils.findAncestorShell(this);
264
+ const resizer = this._resizer = shell.appendChild(new pacemCore.Components.PacemResizeElement());
265
+ resizer.addEventListener(pacemCore.Components.ResizeEventName, this._resizeHandler, false);
266
+ }
267
+ this._resizer.target = target;
268
+ }
269
+ // #region OO-scoped props
270
+ get chartSize() {
271
+ return this._size;
272
+ }
273
+ get chartSeries() {
274
+ return this._series;
275
+ }
276
+ get chartBody() {
277
+ return this._body;
278
+ }
279
+ get chartGrid() {
280
+ return this._grid;
281
+ }
282
+ get chartMask() {
283
+ return this._mask;
284
+ }
285
+ get chartKey() {
286
+ return this._key;
287
+ }
288
+ get chartContainer() {
289
+ return this._div;
290
+ }
291
+ assignUiBehaviors(ui, series, data, color) {
292
+ const alreadyRegistered = !pacemCore.Utils.isNull(pacemCore.CustomElementUtils.getAttachedPropertyValue(ui, SERIES_DATAITEM));
293
+ const item = pacemCore.Utils.extend({ series: series.label, color: color || series.color }, data);
294
+ pacemCore.CustomElementUtils.setAttachedPropertyValue(ui, SERIES_DATAITEM, item);
295
+ pacemCore.CustomElementUtils.setAttachedPropertyValue(ui, SERIES_SERIES, series);
296
+ if (!alreadyRegistered) {
297
+ MANAGED_EVENTS.forEach(type => {
298
+ ui.addEventListener(type, this._broadcastHandler);
299
+ });
300
+ }
301
+ }
302
+ disposeUiBehaviors(ui) {
303
+ pacemCore.CustomElementUtils.deleteAttachedPropertyValue(ui, SERIES_DATAITEM);
304
+ pacemCore.CustomElementUtils.deleteAttachedPropertyValue(ui, SERIES_SERIES);
305
+ MANAGED_EVENTS.forEach(type => {
306
+ ui.removeEventListener(type, this._broadcastHandler);
307
+ });
308
+ }
309
+ ensureChartContainer() {
310
+ if (pacemCore.Utils.isNull(this._div)) {
311
+ let div = this._div = this.target || document.createElement('div');
312
+ div.classList.add(pacemCore.PCSS + '-chart-area');
313
+ if (div != this.target) {
314
+ this.parentElement.insertBefore(div, this);
315
+ }
316
+ }
317
+ return this._div;
318
+ }
319
+ ensureChartBody(type, w, h) {
320
+ if (pacemCore.Utils.isNull(this._body)) {
321
+ let svg = this._body = document.createElementNS(SVG_NS$2, 'svg');
322
+ svg.setAttribute('pacem', '');
323
+ svg.setAttribute('class', pacemCore.PCSS + '-' + type + '-chart');
324
+ svg.setAttribute('preserveAspectRatio', 'xMinYMax slice');
325
+ const g = this._grid = document.createElementNS(SVG_NS$2, 'svg');
326
+ g.setAttribute('pacem', '');
327
+ g.setAttribute('class', 'chart-grid');
328
+ // put mask on series
329
+ let defs = document.createElementNS(SVG_NS$2, 'defs');
330
+ let mask = this._mask = document.createElementNS(SVG_NS$2, 'mask');
331
+ // black (hides)
332
+ let rect = document.createElementNS(SVG_NS$2, 'rect');
333
+ rect.setAttribute('x', '0');
334
+ rect.setAttribute('y', '0');
335
+ rect.setAttribute('width', '100%');
336
+ rect.setAttribute('height', '100%');
337
+ // white (shows)
338
+ let rect0 = document.createElementNS(SVG_NS$2, 'rect');
339
+ rect0.setAttribute('y', '0');
340
+ rect0.setAttribute('width', '100%');
341
+ rect0.setAttribute('fill', '#fff');
342
+ mask.id = 'gnrc_mask_' + this._key;
343
+ mask.appendChild(rect);
344
+ mask.appendChild(rect0);
345
+ // place mask on series so that lines won't be rendered outside the grid borders
346
+ //g2.setAttribute('mask', 'url(#' + mask.id + ')');
347
+ defs.appendChild(mask);
348
+ svg.appendChild(defs);
349
+ svg.appendChild(g);
350
+ this._div.appendChild(svg);
351
+ }
352
+ return this._body;
353
+ }
354
+ chartDataItemToPoint(input, source) {
355
+ switch (this.xAxisType || 'string') {
356
+ case 'number':
357
+ return { x: parseFloat(input.label), y: input.value };
358
+ case 'date':
359
+ return { x: pacemCore.Utils.parseDate(input.label).valueOf(), y: input.value };
360
+ case 'string':
361
+ return { x: source.findIndex(e => e.label == input.label), y: input.value };
362
+ default:
363
+ throw 'Not supported.';
364
+ }
365
+ }
366
+ getVirtualGrid(items, minX, maxX, minY, maxY, xAxisType = this.xAxisType, steps, labels) {
367
+ const rangeY = getRoundedBoundaries(minY, maxY, steps), stepY = rangeY.round;
368
+ // fill y-axis array
369
+ var y = [];
370
+ for (let j = rangeY.min; j <= rangeY.max; j += stepY) {
371
+ y.push(j.roundoff());
372
+ }
373
+ // fill x-axis array;
374
+ let lang = pacemCore.Utils.lang(this);
375
+ let format = null;
376
+ const intl = this.xAxisFormat;
377
+ if (!pacemCore.Utils.isNullOrEmpty(intl)) {
378
+ switch (xAxisType) {
379
+ case 'number':
380
+ format = (n) => Intl.NumberFormat(lang, intl).format(n);
381
+ break;
382
+ case 'date':
383
+ format = (n) => Intl.DateTimeFormat(lang, intl).format(pacemCore.Utils.parseDate(n));
384
+ break;
385
+ }
386
+ }
387
+ const x = getEvenlySpaced(items, xAxisType, minX, maxX, format ?? lang, labels);
388
+ return { x, y };
389
+ }
390
+ wipeOut(series = this._series, startIndex = 0) {
391
+ for (var j = series.length - 1; j >= startIndex; j--) {
392
+ series[j].remove();
393
+ }
394
+ series.splice(startIndex);
395
+ }
396
+ buildLinearGradient(seriesIndex, invert = false) {
397
+ const grad = document.createElementNS(SVG_NS$2, 'linearGradient');
398
+ grad.id = this.chartKey + '_grad' + seriesIndex + (invert ? '_inverted' : '');
399
+ if (invert) {
400
+ pacemCore.Utils.addClass(grad, 'bottom-up');
401
+ }
402
+ grad.setAttribute('x1', '0%');
403
+ grad.setAttribute('x2', '0%');
404
+ grad.setAttribute('y1', '0%');
405
+ grad.setAttribute('y2', '100%');
406
+ grad.setAttribute('spreadMethod', 'pad');
407
+ const stop1 = document.createElementNS(SVG_NS$2, 'stop');
408
+ stop1.setAttribute('offset', '0%');
409
+ const stop2 = document.createElementNS(SVG_NS$2, 'stop');
410
+ stop2.setAttribute('offset', '100%');
411
+ grad.appendChild(stop1);
412
+ grad.appendChild(stop2);
413
+ return grad;
414
+ }
415
+ setGradientColor(grad, color) {
416
+ for (let j = 0; j < grad.children.length; j++) {
417
+ const stop = grad.children.item(j);
418
+ if (stop instanceof SVGStopElement) {
419
+ stop.style.stopColor = color;
420
+ }
421
+ }
422
+ }
423
+ estimateYAxisLabelWidth(max) {
424
+ const txt = this.formatYAxisLabel(max);
425
+ return this.estimateLabelWidth(txt);
426
+ }
427
+ estimateLabelWidth(txt) {
428
+ const grid = this._grid;
429
+ if (pacemCore.Utils.isNull(grid)) {
430
+ throw new Error('Unable to estimate label without an underlying grid available.');
431
+ }
432
+ const lbl = document.createElementNS(SVG_NS$2, 'text');
433
+ lbl.textContent = txt;
434
+ grid.appendChild(lbl);
435
+ const size = pacemCore.Utils.offset(lbl);
436
+ lbl.remove();
437
+ return size.width;
438
+ }
439
+ formatYAxisLabel(y) {
440
+ const intl = this.yAxisFormat;
441
+ return pacemCore.Utils.isNullOrEmpty(intl) ? y.toString() : Intl.NumberFormat(pacemCore.Utils.lang(this), intl).format(y);
442
+ }
443
+ estimateXAxisLabelWidth(max) {
444
+ const txt = this.formatXAxisLabel(max);
445
+ return this.estimateLabelWidth(txt);
446
+ }
447
+ formatXAxisLabel(x) {
448
+ const intl = this.xAxisFormat, lang = pacemCore.Utils.lang(this);
449
+ switch (this.xAxisType) {
450
+ case 'date':
451
+ const date = pacemCore.Utils.Dates.parse(x);
452
+ return pacemCore.Utils.isNullOrEmpty(intl) ? date.toLocaleString(lang) : Intl.DateTimeFormat(lang, intl).format(date);
453
+ case 'number':
454
+ const num = x;
455
+ return pacemCore.Utils.isNullOrEmpty(intl) ? num.toLocaleString(lang) : Intl.NumberFormat(lang, intl).format(num);
456
+ default:
457
+ return x;
458
+ }
459
+ }
460
+ draw() {
461
+ this.drawSeries(this._datasource);
462
+ }
463
+ /**
464
+ * Default implementation.
465
+ * @param element
466
+ */
467
+ getAnchorPoint(element) {
468
+ const rect = pacemCore.Utils.offset(element);
469
+ return { x: rect.left + rect.width * .5, y: rect.top + rect.height * .5 };
470
+ }
471
+ }
472
+ __decorate$3([
473
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Element })
474
+ ], PacemSeriesChartElement.prototype, "target", void 0);
475
+ __decorate$3([
476
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.String })
477
+ ], PacemSeriesChartElement.prototype, "xAxisType", void 0);
478
+ __decorate$3([
479
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.String })
480
+ ], PacemSeriesChartElement.prototype, "xAxisPosition", void 0);
481
+ __decorate$3([
482
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Json })
483
+ ], PacemSeriesChartElement.prototype, "datasource", void 0);
484
+ __decorate$3([
485
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
486
+ ], PacemSeriesChartElement.prototype, "yAxisDensity", void 0);
487
+ __decorate$3([
488
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
489
+ ], PacemSeriesChartElement.prototype, "xAxisDensity", void 0);
490
+ __decorate$3([
491
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
492
+ ], PacemSeriesChartElement.prototype, "yAxisMin", void 0);
493
+ __decorate$3([
494
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
495
+ ], PacemSeriesChartElement.prototype, "yAxisMax", void 0);
496
+ __decorate$3([
497
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Json })
498
+ ], PacemSeriesChartElement.prototype, "yAxisFormat", void 0);
499
+ __decorate$3([
500
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Json })
501
+ ], PacemSeriesChartElement.prototype, "xAxisFormat", void 0);
502
+ __decorate$3([
503
+ pacemCore.Throttle(true)
504
+ ], PacemSeriesChartElement.prototype, "draw", null);
505
+
506
+ var __decorate$2 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
507
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
508
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
509
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
510
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
511
+ };
512
+ //namespace Pacem.Components.Charts {
513
+ /**
514
+ * Returns the anchor points for a Bézier curve.
515
+ * @param p The actual point.
516
+ * @param p0 The previous point, if any.
517
+ * @param p1 The next point, if any.
518
+ */
519
+ function getSplineCtrlPoints(p, p0, p1) {
520
+ let c0 = p, c1 = p;
521
+ const p0Null = pacemCore.Utils.isNull(p0), p1Null = pacemCore.Utils.isNull(p1);
522
+ if (!(p0Null && p1Null)) {
523
+ const portion = 3;
524
+ let m0, m1;
525
+ if (!p0Null) {
526
+ m0 = (p.y - p0.y) / (p.x - p0.x);
527
+ }
528
+ if (!p1Null) {
529
+ m1 = (p1.y - p.y) / (p1.x - p.x);
530
+ }
531
+ // average slope
532
+ const m = ((m1 || (m0 || 0)) + (m0 || (m1 || 0))) / 2;
533
+ const dx0 = p0Null ? 0 : (p.x - p0.x) / portion;
534
+ const dx1 = p1Null ? 0 : (p1.x - p.x) / portion;
535
+ c0 = { x: p.x - dx0, y: p.y - dx0 * m };
536
+ c1 = { x: p.x + dx1, y: p.y + dx1 * m };
537
+ }
538
+ return { c0: c0, c1: c1 };
539
+ }
540
+ const GET_VAL = pacemCore.CustomElementUtils.getAttachedPropertyValue;
541
+ const SET_VAL = pacemCore.CustomElementUtils.setAttachedPropertyValue;
542
+ pacemCore.CustomElementUtils.deleteAttachedPropertyValue;
543
+ const PADDING_PIXELS$1 = 24;
544
+ const SERIES_MAGNITUDE = 'pacem:chart-series:area';
545
+ const SVG_NS$1 = "http://www.w3.org/2000/svg";
546
+ let PacemChartElement = class PacemChartElement extends PacemSeriesChartElement {
547
+ constructor() {
548
+ super(...arguments);
549
+ this.#hover = false;
550
+ this._enterHandler = (evt) => {
551
+ this.#hover = true;
552
+ };
553
+ this._leaveHandler = (evt) => {
554
+ this.#hover = false;
555
+ };
556
+ this._moveHandler = (evt) => {
557
+ if (!this.#hover) {
558
+ return;
559
+ }
560
+ };
561
+ this._chartFillSeries = [];
562
+ }
563
+ // TODO: implement
564
+ // @Watch({ converter: PropertyConverters.String }) hoverMode: 'abscissa' | 'point'; // 'point' assumed as default
565
+ _getVirtualGrid(items, minX, maxX, minY, maxY, xAxisType = this.xAxisType, steps, labels) {
566
+ return super.getVirtualGrid(items, minX, maxX, minY, maxY, xAxisType, steps, labels);
567
+ }
568
+ _wipe(series = this.chartSeries, startIndex = 0) {
569
+ super.wipeOut(series, startIndex);
570
+ }
571
+ viewActivatedCallback() {
572
+ super.viewActivatedCallback();
573
+ this._setupBehavior();
574
+ }
575
+ disconnectedCallback() {
576
+ this._dismantleBehavior();
577
+ super.disconnectedCallback();
578
+ }
579
+ propertyChangedCallback(name, old, val, first) {
580
+ super.propertyChangedCallback(name, old, val, first);
581
+ switch (name) {
582
+ case 'type':
583
+ case 'aspectRatio':
584
+ this.draw();
585
+ break;
586
+ }
587
+ }
588
+ _setupBehavior() {
589
+ this.addEventListener('mouseenter', this._enterHandler, false);
590
+ this.addEventListener('mouseleave', this._enterHandler, false);
591
+ this.addEventListener('mousemove', this._moveHandler, false);
592
+ }
593
+ _dismantleBehavior() {
594
+ this.removeEventListener('mouseenter', this._enterHandler, false);
595
+ this.removeEventListener('mouseleave', this._leaveHandler, false);
596
+ this.removeEventListener('mousemove', this._moveHandler, false);
597
+ }
598
+ #hover;
599
+ _buildLinearGradient(seriesIndex) {
600
+ return super.buildLinearGradient(seriesIndex);
601
+ }
602
+ _setGradientColor(grad, color) {
603
+ super.setGradientColor(grad, color);
604
+ }
605
+ drawSeries(datasource) {
606
+ if (!this.isReady || pacemCore.Utils.isNull(this.chartSize)) {
607
+ return;
608
+ }
609
+ this.ensureChartContainer();
610
+ const type = this.type || 'line';
611
+ const padding = PADDING_PIXELS$1;
612
+ // resize all
613
+ var size = this.chartSize;
614
+ if (size.height <= padding || size.width <= padding) {
615
+ return;
616
+ }
617
+ // items && labels?
618
+ if (pacemCore.Utils.isNullOrEmpty(datasource) || datasource.every(i => pacemCore.Utils.isNullOrEmpty(i.values))) {
619
+ this._wipe();
620
+ return;
621
+ }
622
+ const body = this.ensureChartBody('line', size.width, size.height);
623
+ // from now on, drawing...
624
+ this.log(pacemCore.Logging.LogLevel.Debug, `Drawing ${type} chart.`);
625
+ // #region computations
626
+ const xAxisType = this.xAxisType || 'string';
627
+ let minY = this.yAxisMin ?? Number.NaN, maxY = this.yAxisMax ?? Number.NaN, minX = Number.NaN, maxX = Number.NaN;
628
+ let stretch = 1;
629
+ // individuate the min/max x & y in order correctly apply aspect ratio...
630
+ for (let series of datasource) {
631
+ let data = series.values;
632
+ if (data && data.length) {
633
+ let j = 0;
634
+ for (let item of data) {
635
+ let pt = this.chartDataItemToPoint(item, data);
636
+ if (pacemCore.Utils.isNull(this.yAxisMin)) {
637
+ minY = isNaN(minY) ? pt.y : Math.min(minY, pt.y);
638
+ }
639
+ if (pacemCore.Utils.isNull(this.yAxisMax)) {
640
+ maxY = isNaN(maxY) ? pt.y : Math.max(maxY, pt.y);
641
+ }
642
+ if (j === 0)
643
+ minX = isNaN(minX) ? pt.x : Math.min(minX, pt.x);
644
+ else if (j === data.length - 1)
645
+ maxX = isNaN(maxX) ? pt.x : Math.max(maxX, pt.x);
646
+ j++;
647
+ }
648
+ }
649
+ }
650
+ /** virtual grid made of x- and y-axis labels */
651
+ const withValues = datasource.find(i => !pacemCore.Utils.isNullOrEmpty(i.values));
652
+ const grid = this._getVirtualGrid(withValues.values, minX, maxX, minY, maxY, xAxisType, this.yAxisDensity, this.xAxisDensity);
653
+ const topGrid = grid.y[grid.y.length - 1], bottomGrid = grid.y[0];
654
+ if (topGrid === bottomGrid)
655
+ return;
656
+ // estimate y-axis max width
657
+ const halfPad = padding * .5;
658
+ const maxYLabelLength = grid.y.reduce((max, i) => Math.max(max, this.estimateYAxisLabelWidth(i) + halfPad), padding);
659
+ const maxXLabelHalfLength = grid.x.reduce((max, i) => Math.max(max, this.estimateXAxisLabelWidth(i)), padding) * .5;
660
+ const paddingYAxis = Math.max(maxXLabelHalfLength, maxYLabelLength), paddingYAxisEnd = maxXLabelHalfLength; // Math.max(padding, this.estimateXAxisLabelWidth(minX) * .5 + PADDING_PIXELS);
661
+ /** width of the WHOLE series dedicated area */
662
+ const seriesWidth = size.width - paddingYAxis - paddingYAxisEnd;
663
+ /** height of the WHOLE series dedicated area */
664
+ const gridHeight = (size.height - 2 * padding);
665
+ const seriesHeight = gridHeight * (1 - (topGrid - bottomGrid - (maxY - minY)) / (topGrid - bottomGrid));
666
+ const seriesY = gridHeight * (topGrid - maxY) / (topGrid - bottomGrid);
667
+ // const seriesY2 = gridHeight * (minY - bottomGrid) / (topGrid - bottomGrid);
668
+ // if not a `graph`
669
+ if (xAxisType !== 'number' || (this.aspectRatio !== 'monometric' && this.aspectRatio !== 'logaritmic')) {
670
+ // consider padding
671
+ stretch = seriesWidth / seriesHeight;
672
+ body.setAttribute('height', size.height.toString());
673
+ body.setAttribute('width', size.width.toString());
674
+ }
675
+ body.setAttribute('viewBox', `0 0 ${size.width} ${size.height}`);
676
+ // #endregion
677
+ // #region render series
678
+ let iter = 0;
679
+ // normalize
680
+ const spanX = maxX - minX, spanY = maxY - minY;
681
+ const normX = 100 * stretch / spanX, normY = 100 / spanY;
682
+ const normPadding = 100 * padding / seriesHeight;
683
+ const buildPoint = (it, series) => {
684
+ let p = this.chartDataItemToPoint(it, series);
685
+ //pt.x *= normX;
686
+ p.y *= normY;
687
+ // Limit as much as possible the magnitude of a number inclued in the svg.
688
+ // Big numbers "overflow the renderer".
689
+ p.x = (p.x - minX) * normX;
690
+ //pt.y = (pt.y - minY) * normY;
691
+ return p;
692
+ };
693
+ const chartSeries = this.chartSeries;
694
+ const chartFillSeries = this._chartFillSeries;
695
+ const chartGrid = this.chartGrid;
696
+ const splineHere = type === 'spline' || type === 'splinearea';
697
+ for (let series of datasource) {
698
+ // does the series svg exist?
699
+ let svg, svgFill;
700
+ let grad;
701
+ if (chartSeries.length > iter) {
702
+ svg = chartSeries[iter];
703
+ svgFill = chartFillSeries[iter];
704
+ grad = svgFill.firstElementChild.firstElementChild;
705
+ }
706
+ else {
707
+ svg = document.createElementNS(SVG_NS$1, 'svg');
708
+ svg.setAttribute('pacem', '');
709
+ body.appendChild(svg);
710
+ svgFill = document.createElementNS(SVG_NS$1, 'svg');
711
+ svgFill.setAttribute('pacem', '');
712
+ body.insertBefore(svgFill, body.children.item(iter + /* <defs> should remain the very first child and 'grid' the very second */ 2));
713
+ // 1st child - defs (gradient)
714
+ const defs = document.createElementNS(SVG_NS$1, 'defs');
715
+ defs.appendChild(grad = this._buildLinearGradient(iter));
716
+ svgFill.appendChild(defs);
717
+ // 2nd child - fill path
718
+ svgFill.appendChild(document.createElementNS(SVG_NS$1, 'path'));
719
+ chartFillSeries.push(svgFill);
720
+ // 1st child stroke path
721
+ svg.appendChild(document.createElementNS(SVG_NS$1, 'path'));
722
+ // 2nd + nth+1 child will be point circles
723
+ chartSeries.push(svg);
724
+ }
725
+ // series positioning:
726
+ /*
727
+ --------------------------------------
728
+ | |--------------------------------|
729
+ |pad| series here |
730
+ | |--------------------------------|
731
+ --------------------------------------
732
+ | | pad |
733
+ --------------------------------------
734
+ */
735
+ let className = 'chart-series';
736
+ const fill = type === 'area' || type === 'splinearea';
737
+ if (!pacemCore.Utils.isNullOrEmpty(series.className)) {
738
+ className += ' ' + series.className;
739
+ }
740
+ [svg, svgFill].forEach(s => {
741
+ s.setAttribute('class', className);
742
+ s.setAttribute('x', paddingYAxis.toString());
743
+ s.setAttribute('y', seriesY.toString());
744
+ s.setAttribute('width', seriesWidth.toString());
745
+ s.setAttribute('height', (seriesHeight + 2 * padding).toString());
746
+ });
747
+ pacemCore.Utils.addClass(svgFill, pacemCore.PCSS + '-inert');
748
+ // pick path as single child element for the series.
749
+ let pathFill = svgFill.children.item(1);
750
+ let path = svg.firstElementChild;
751
+ path.style.stroke = series.color;
752
+ pathFill.style.stroke =
753
+ path.style.fill = 'none';
754
+ this._setGradientColor(grad, series.color);
755
+ pathFill.style.fill = `url(#${grad.id})`;
756
+ pathFill.style.display = fill ? '' : 'none';
757
+ let d = '';
758
+ let data = series.values;
759
+ if (data && data.length) {
760
+ const addInteractivePoint = (center, j, series, dataItem, color) => {
761
+ const ndx = j + /* count the <path> child */ 1;
762
+ let circle;
763
+ if (svg.children.length > ndx) {
764
+ circle = svg.children.item(ndx);
765
+ }
766
+ else {
767
+ circle = document.createElementNS(SVG_NS$1, 'line');
768
+ circle.setAttribute('class', 'circle');
769
+ svg.appendChild(circle);
770
+ }
771
+ const x1 = center.x.toString(), y1 = (-center.y).toString();
772
+ circle.setAttribute('x1', x1);
773
+ circle.setAttribute('y1', y1);
774
+ circle.setAttribute('x2', x1);
775
+ circle.setAttribute('y2', y1);
776
+ circle.style.stroke = color;
777
+ this.assignUiBehaviors(circle, series, dataItem, color);
778
+ };
779
+ const wipeExceedingPoints = () => {
780
+ const remaining = series.datapoints ? (data.length + 1) : 1;
781
+ for (let k = svg.children.length - 1; k >= remaining; k--) {
782
+ var circle = svg.children.item(k);
783
+ this.disposeUiBehaviors(circle);
784
+ circle.remove();
785
+ }
786
+ };
787
+ if (splineHere) {
788
+ // #region SPLINE
789
+ let pt0, pt, c0;
790
+ for (let j = 0; j < data.length; j++) {
791
+ const item = data[j];
792
+ if (isNaN(item.value)) {
793
+ continue;
794
+ }
795
+ if (!pt) {
796
+ pt = buildPoint(item, data);
797
+ }
798
+ let pt1;
799
+ if (splineHere && j < (data.length - 1)) {
800
+ pt1 = buildPoint(data[j + 1], data);
801
+ }
802
+ // accumulate `area` for sorting
803
+ let areaSoFar = GET_VAL(series, SERIES_MAGNITUDE, 0);
804
+ areaSoFar += item.value;
805
+ SET_VAL(series, SERIES_MAGNITUDE, areaSoFar);
806
+ var c = getSplineCtrlPoints(pt, pt0, pt1);
807
+ d += pacemCore.Utils.isNullOrEmpty(d) ? `M${pt.x},${-pt.y} ` : `C${c0.x},${-c0.y} ${c.c0.x},${-c.c0.y} ${pt.x},${-pt.y} `;
808
+ if (series.datapoints) {
809
+ addInteractivePoint(pt, j, series, item, series.color);
810
+ }
811
+ // step next
812
+ pt0 = pt;
813
+ pt = pt1, c0 = c.c1;
814
+ }
815
+ // #endregion
816
+ }
817
+ else {
818
+ // #region LINE
819
+ let j = 0;
820
+ for (let item of data) {
821
+ if (isNaN(item.value)) {
822
+ continue;
823
+ }
824
+ const pt = buildPoint(item, data);
825
+ // accumulate `area` for sorting
826
+ let areaSoFar = GET_VAL(series, SERIES_MAGNITUDE, 0);
827
+ areaSoFar += item.value;
828
+ SET_VAL(series, SERIES_MAGNITUDE, areaSoFar);
829
+ d += pacemCore.Utils.isNullOrEmpty(d) ? `M${pt.x},${-pt.y} ` : `L${pt.x},${-pt.y} `;
830
+ if (series.datapoints) {
831
+ addInteractivePoint(pt, j, series, item, series.color);
832
+ }
833
+ j++;
834
+ }
835
+ // #endregion
836
+ }
837
+ wipeExceedingPoints();
838
+ }
839
+ path.setAttribute('d', d);
840
+ pathFill.setAttribute('d', d + `V${(-minY * normY)} H0 Z`);
841
+ // tick
842
+ iter++;
843
+ }
844
+ // remove exceeding series
845
+ this._wipe(chartFillSeries, iter);
846
+ this._wipe(chartSeries, iter);
847
+ const w0 = 100 * stretch, h0 = 100 + 2 * normPadding, x0 = 0, //minX * normX,
848
+ y0 = maxY * normY + normPadding;
849
+ const svbox = `${x0} ${-y0} ${w0} ${h0}`;
850
+ for (var svg of chartSeries.concat(chartFillSeries)) {
851
+ svg.setAttribute('viewBox', svbox);
852
+ }
853
+ const chartMask = this.chartMask;
854
+ let mask = chartMask.children.item(1);
855
+ mask.setAttribute('x', x0.toString());
856
+ mask.setAttribute('height', (size.height - padding).toString());
857
+ // #endregion
858
+ // #region grid
859
+ chartGrid.setAttribute('viewBox', `0 0 ${size.width} ${size.height}`);
860
+ if (grid.x.length <= 1 || grid.y.length <= 1) {
861
+ for (let j = chartGrid.children.length - 1; j >= 0; j--) {
862
+ chartGrid.children.item(j).remove();
863
+ }
864
+ return;
865
+ }
866
+ let pgrid;
867
+ if (chartGrid.children.length > 0) {
868
+ pgrid = chartGrid.children.item(0);
869
+ }
870
+ else {
871
+ pgrid = document.createElementNS(SVG_NS$1, 'path');
872
+ chartGrid.appendChild(pgrid);
873
+ }
874
+ const tick = padding * .25;
875
+ let lblCounter = 0;
876
+ let ensureLabel = (index, x, y, txt) => {
877
+ const ndx = index + /* <path> is the first child element */ 1;
878
+ let lbl;
879
+ if (chartGrid.children.length <= ndx) {
880
+ lbl = document.createElementNS(SVG_NS$1, 'text');
881
+ chartGrid.appendChild(lbl);
882
+ }
883
+ else {
884
+ lbl = chartGrid.children.item(ndx);
885
+ }
886
+ lbl.textContent = txt;
887
+ lbl.setAttribute('x', x.toString());
888
+ lbl.setAttribute('y', y.toString());
889
+ return lbl;
890
+ };
891
+ let dgrid = `M${paddingYAxis},${padding} v${gridHeight}`; //H${w}
892
+ // x
893
+ let j = 0;
894
+ const xincr = seriesWidth / (grid.x.length - 1), yincr = gridHeight / (grid.y.length - 1);
895
+ if (this.xAxisPosition !== 'none') {
896
+ for (var x of grid.x) {
897
+ const xcoord = paddingYAxis + j * xincr;
898
+ if (this.xAxisPosition === 'top') {
899
+ dgrid += ` M${xcoord},${padding} v${-tick}`;
900
+ let lbl = ensureLabel(lblCounter++, xcoord, 0, x);
901
+ lbl.setAttribute('text-anchor', 'middle');
902
+ lbl.setAttribute('alignment-baseline', 'hanging');
903
+ }
904
+ else {
905
+ let ycoord = gridHeight + padding;
906
+ dgrid += ` M${xcoord},${ycoord} v${tick}`;
907
+ ensureLabel(lblCounter++, xcoord, ycoord + padding, x).setAttribute('text-anchor', 'middle');
908
+ }
909
+ j++;
910
+ }
911
+ }
912
+ // y
913
+ j = 0;
914
+ for (var y of grid.y) {
915
+ const ycoord = gridHeight + padding - j * yincr, xcoord = paddingYAxis - tick;
916
+ dgrid += ` M${xcoord},${ycoord} H${(seriesWidth + paddingYAxis)}`;
917
+ let txt = this.formatYAxisLabel(y);
918
+ ensureLabel(lblCounter++, xcoord - tick, ycoord, txt).setAttribute('text-anchor', 'end');
919
+ j++;
920
+ }
921
+ pgrid.setAttribute('d', dgrid);
922
+ // exceeding labels?
923
+ for (let j = chartGrid.children.length - 1; j > lblCounter; j--) {
924
+ chartGrid.children.item(j).remove();
925
+ }
926
+ // #endregion
927
+ // #region abscissa cursor
928
+ // #endregion
929
+ }
930
+ };
931
+ __decorate$2([
932
+ pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.String })
933
+ ], PacemChartElement.prototype, "type", void 0);
934
+ __decorate$2([
935
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.String })
936
+ ], PacemChartElement.prototype, "aspectRatio", void 0);
937
+ PacemChartElement = __decorate$2([
938
+ pacemCore.CustomElement({ tagName: pacemCore.P + '-chart' })
939
+ ], PacemChartElement);
940
+
941
+ var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
942
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
943
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
944
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
945
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
946
+ };
947
+ //namespace Pacem.Components.Charts {
948
+ const SVG_NS = "http://www.w3.org/2000/svg";
949
+ const PADDING_PIXELS = 24;
950
+ let PacemColumnChartElement = class PacemColumnChartElement extends PacemSeriesChartElement {
951
+ constructor() {
952
+ super(...arguments);
953
+ /** Set a value between 0 and 1, for the columns' stack/cluster horizontal size (percentage of the available space). */
954
+ this.groupWidth = .0;
955
+ }
956
+ propertyChangedCallback(name, old, val, first) {
957
+ super.propertyChangedCallback(name, old, val, first);
958
+ if (name === 'type' || name === 'groupWidth') {
959
+ this.draw();
960
+ }
961
+ }
962
+ _safen(w = this.groupWidth) {
963
+ return Math.min(1, Math.max(w || .75, 0));
964
+ }
965
+ drawSeries(datasource) {
966
+ if (!this.isReady || pacemCore.Utils.isNull(this.chartSize)) {
967
+ return;
968
+ }
969
+ this.ensureChartContainer();
970
+ const type = this.type || 'cluster';
971
+ const padding = PADDING_PIXELS;
972
+ // resize all
973
+ var size = this.chartSize;
974
+ if (size.height <= padding || size.width <= padding) {
975
+ return;
976
+ }
977
+ // items && labels?
978
+ if (pacemCore.Utils.isNullOrEmpty(datasource) || datasource.every(i => pacemCore.Utils.isNullOrEmpty(i.values))) {
979
+ this.wipeOut();
980
+ return;
981
+ }
982
+ const body = this.ensureChartBody('column', size.width, size.height);
983
+ // from now on, drawing...
984
+ this.log(pacemCore.Logging.LogLevel.Debug, `Drawing ${type} chart.`);
985
+ // #region computations
986
+ const xAxisType = this.xAxisType || 'string';
987
+ let minY = this.yAxisMin ?? 0, maxY = this.yAxisMax ?? 0, minX = 0, maxX = 0, maxCount = 0;
988
+ let stretch = 1;
989
+ const accumulator = { negative: [], positive: [] };
990
+ // individuate the min/max x & y in order correctly apply aspect ratio...
991
+ for (let series of datasource) {
992
+ let data = series.values;
993
+ if (!pacemCore.Utils.isNullOrEmpty(data)) {
994
+ let j = 0;
995
+ for (let item of data) {
996
+ accumulator.positive[j] = accumulator.positive[j] || 0;
997
+ accumulator.negative[j] = accumulator.negative[j] || 0;
998
+ let pt = this.chartDataItemToPoint(item, data);
999
+ if (pacemCore.Utils.isNull(this.yAxisMin)) {
1000
+ minY = Math.min(minY, pt.y);
1001
+ }
1002
+ if (pacemCore.Utils.isNull(this.yAxisMax)) {
1003
+ maxY = Math.max(maxY, pt.y);
1004
+ }
1005
+ minX = Math.min(minX, pt.x);
1006
+ maxX = Math.max(maxX, pt.x);
1007
+ if (pt.y > 0) {
1008
+ accumulator.positive[j] += pt.y;
1009
+ }
1010
+ else if (pt.y < 0) {
1011
+ accumulator.negative[j] += pt.y;
1012
+ }
1013
+ j++;
1014
+ }
1015
+ maxCount = Math.max(maxCount, data.length);
1016
+ }
1017
+ }
1018
+ const stacked = type === 'stack';
1019
+ if (stacked) {
1020
+ if (pacemCore.Utils.isNull(this.yAxisMin))
1021
+ minY = Math.min.apply(null, accumulator.negative);
1022
+ if (pacemCore.Utils.isNull(this.yAxisMax))
1023
+ maxY = Math.max.apply(null, accumulator.positive);
1024
+ }
1025
+ if (maxX === 0 && maxX === minX) {
1026
+ maxX = 1;
1027
+ }
1028
+ // add "1 slot" (half at the beginning and half after the end)
1029
+ const slot = (maxX - minX) / maxCount, halfSlot = slot * .5,
1030
+ // the following are usefule during the very rendering
1031
+ availSlot = slot * this._safen(this.groupWidth), halfAvailSlot = availSlot * .5;
1032
+ /** virtual grid made of x- and y-axis labels */
1033
+ const withValues = datasource.find(i => !pacemCore.Utils.isNullOrEmpty(i.values));
1034
+ const grid = this.getVirtualGrid(withValues.values, minX - halfSlot, maxX + halfSlot, minY, maxY, xAxisType, this.yAxisDensity, this.xAxisDensity);
1035
+ const topGrid = grid.y[grid.y.length - 1], bottomGrid = grid.y[0];
1036
+ if (topGrid === bottomGrid) {
1037
+ return;
1038
+ }
1039
+ // estimate y-axis max width
1040
+ const halfPad = PADDING_PIXELS * .5;
1041
+ const paddingYAxis = grid.y.reduce((max, i) => Math.max(max, this.estimateYAxisLabelWidth(i) + halfPad), padding);
1042
+ /** width of the WHOLE series dedicated area */
1043
+ const seriesWidth = size.width - paddingYAxis - padding;
1044
+ /** height of the WHOLE series dedicated area */
1045
+ const gridHeight = (size.height - 2 * padding);
1046
+ const seriesHeight = gridHeight * (1 - (topGrid - bottomGrid - (maxY - minY)) / (topGrid - bottomGrid));
1047
+ const seriesY = gridHeight * (topGrid - maxY) / (topGrid - bottomGrid);
1048
+ // consider padding
1049
+ stretch = seriesWidth / seriesHeight;
1050
+ body.setAttribute('height', size.height.toString());
1051
+ body.setAttribute('width', size.width.toString());
1052
+ body.setAttribute('viewBox', `0 0 ${size.width} ${size.height}`);
1053
+ // #endregion
1054
+ // #region render series
1055
+ let iter = 0;
1056
+ // normalize
1057
+ const spanX = maxX - minX, spanY = maxY - minY;
1058
+ const normX = 100 * stretch / spanX, normY = 100 / spanY;
1059
+ const normPadding = 100 * padding / seriesHeight;
1060
+ const chartSeries = this.chartSeries;
1061
+ const chartGrid = this.chartGrid;
1062
+ const xPad = (halfSlot - minX) * normX;
1063
+ const buildPoint = (it, series) => {
1064
+ const p = this.chartDataItemToPoint(it, series);
1065
+ return {
1066
+ x: xPad + p.x * 2 * xPad,
1067
+ y: p.y * normY
1068
+ };
1069
+ };
1070
+ var accumulators = new Array(maxCount);
1071
+ for (let series of datasource) {
1072
+ // does the series svg exist?
1073
+ let svg;
1074
+ let grad;
1075
+ let gradInv;
1076
+ let g;
1077
+ if (chartSeries.length > iter) {
1078
+ svg = chartSeries[iter];
1079
+ grad = svg.firstElementChild.firstElementChild;
1080
+ gradInv = svg.firstElementChild.lastElementChild;
1081
+ g = svg.lastElementChild;
1082
+ }
1083
+ else {
1084
+ svg = document.createElementNS(SVG_NS, 'svg');
1085
+ svg.setAttribute('pacem', '');
1086
+ chartGrid.insertAdjacentElement('afterend', svg);
1087
+ const defs = document.createElementNS(SVG_NS, 'defs');
1088
+ defs.appendChild(grad = this.buildLinearGradient(iter));
1089
+ defs.appendChild(gradInv = this.buildLinearGradient(iter, true));
1090
+ svg.appendChild(defs);
1091
+ svg.appendChild(g = document.createElementNS(SVG_NS, 'g'));
1092
+ chartSeries.push(svg);
1093
+ }
1094
+ // series positioning:
1095
+ /*
1096
+ --------------------------------------
1097
+ | |--------------------------------|
1098
+ |pad| series here |
1099
+ | |--------------------------------|
1100
+ --------------------------------------
1101
+ | | pad |
1102
+ --------------------------------------
1103
+ */
1104
+ var className = 'chart-series series-fill';
1105
+ if (!pacemCore.Utils.isNullOrEmpty(series.className)) {
1106
+ className += ' ' + series.className;
1107
+ }
1108
+ svg.setAttribute('class', className);
1109
+ svg.setAttribute('x', paddingYAxis.toString());
1110
+ svg.setAttribute('y', seriesY.toString());
1111
+ svg.setAttribute('width', seriesWidth.toString());
1112
+ svg.setAttribute('height', (seriesHeight + 2 * padding).toString());
1113
+ const data = series.values;
1114
+ const spinRect = (index) => {
1115
+ while (index >= g.children.length) {
1116
+ g.appendChild(document.createElementNS(SVG_NS, 'rect'));
1117
+ }
1118
+ const rect = g.children.item(index);
1119
+ rect.style.stroke = series.color;
1120
+ const gradient = data[index].value < 0 ? gradInv : grad;
1121
+ this.setGradientColor(gradient, series.color);
1122
+ rect.style.fill = `url(#${gradient.id})`;
1123
+ return rect;
1124
+ };
1125
+ // fix 0 y
1126
+ const precision = 10;
1127
+ const assignVerticalCoordsCoords = (rect, pt0, pt, pt0Start = pt0) => {
1128
+ const y = -Math.max(pt0.y, pt.y), h = Math.abs(pt.y - pt0.y);
1129
+ const fnAssign = () => {
1130
+ rect.setAttribute('y', y.toFixed(precision));
1131
+ rect.setAttribute('height', h.toFixed(precision));
1132
+ };
1133
+ if (!rect.hasAttribute('y')) {
1134
+ // boostrap easing animated transition
1135
+ rect.setAttribute('y', '-' + pt0Start.y.toFixed(precision));
1136
+ rect.setAttribute('height', '0');
1137
+ requestAnimationFrame(fnAssign);
1138
+ }
1139
+ else {
1140
+ fnAssign();
1141
+ }
1142
+ };
1143
+ if (!pacemCore.Utils.isNullOrEmpty(data)) {
1144
+ const pt00 = buildPoint({ value: 0, label: data[0].label }, data);
1145
+ if (stacked) {
1146
+ // #region STACK
1147
+ const iHalfAvailSlot = halfAvailSlot * normX, iAvailSlotAttr = (availSlot * normX).toFixed(precision);
1148
+ for (let j = 0; j < data.length; j++) {
1149
+ const item = data[j];
1150
+ if (pacemCore.Utils.isNullOrEmpty(accumulators[j])) {
1151
+ accumulators[j] = { positive: 0, negative: 0 };
1152
+ }
1153
+ const accumulator = accumulators[j];
1154
+ let posCursor = accumulator.positive, negCursor = accumulator.negative;
1155
+ const neg = item.value < 0, y = neg ? negCursor : (posCursor + item.value), y0 = neg ? (negCursor + item.value) : posCursor;
1156
+ const pt = buildPoint({ label: item.label, value: y }, data);
1157
+ const pt0 = buildPoint({ label: item.label, value: y0 }, data);
1158
+ const x = pt.x - iHalfAvailSlot;
1159
+ const rect = spinRect(j);
1160
+ this.assignUiBehaviors(rect, series, item);
1161
+ rect.setAttribute('x', x.toFixed(precision));
1162
+ rect.setAttribute('width', iAvailSlotAttr);
1163
+ assignVerticalCoordsCoords(rect, pt0, pt, pt00);
1164
+ if (neg) {
1165
+ accumulator.negative = y0;
1166
+ }
1167
+ else {
1168
+ accumulator.positive = y;
1169
+ }
1170
+ }
1171
+ // #endregion
1172
+ }
1173
+ else {
1174
+ // #region CLUSTER
1175
+ const iHalfAvailSlot = halfAvailSlot * normX, iSlot = (iHalfAvailSlot * 2) / datasource.length, //,
1176
+ iSlotAttr = iSlot.toFixed(precision);
1177
+ for (let j = 0; j < data.length; j++) {
1178
+ // looping through the series-data
1179
+ const item = data[j];
1180
+ const pt = buildPoint(item, data);
1181
+ const x = pt.x - iHalfAvailSlot + iSlot * iter;
1182
+ const rect = spinRect(j);
1183
+ this.assignUiBehaviors(rect, series, item);
1184
+ rect.setAttribute('x', x.toFixed(precision));
1185
+ rect.setAttribute('width', iSlotAttr);
1186
+ assignVerticalCoordsCoords(rect, pt00, pt);
1187
+ }
1188
+ // #endregion
1189
+ }
1190
+ }
1191
+ // cleanup exceeding rects
1192
+ for (let j = g.children.length - 1; j >= data?.length || 0; j--) {
1193
+ const rect = g.children.item(j);
1194
+ this.disposeUiBehaviors(rect);
1195
+ rect.remove();
1196
+ }
1197
+ // tick
1198
+ iter++;
1199
+ }
1200
+ // remove exceeding series
1201
+ this.wipeOut(chartSeries, iter);
1202
+ const w0 = 100 * stretch, h0 = 100 + 2 * normPadding, x0 = 0, //minX * normX,
1203
+ y0 = maxY * normY + normPadding;
1204
+ const svbox = `${x0} ${-y0} ${w0} ${h0}`;
1205
+ for (var svg of chartSeries) {
1206
+ svg.setAttribute('viewBox', svbox);
1207
+ }
1208
+ const chartMask = this.chartMask;
1209
+ let mask = chartMask.children.item(1);
1210
+ mask.setAttribute('x', x0.toString());
1211
+ mask.setAttribute('height', (size.height - padding).toString());
1212
+ // #endregion
1213
+ // #region grid
1214
+ chartGrid.setAttribute('viewBox', `0 0 ${size.width} ${size.height}`);
1215
+ if (grid.x.length < 1 || grid.y.length <= 1) {
1216
+ for (let j = chartGrid.children.length - 1; j >= 0; j--) {
1217
+ chartGrid.children.item(j).remove();
1218
+ }
1219
+ return;
1220
+ }
1221
+ let pgrid;
1222
+ if (chartGrid.children.length > 0) {
1223
+ pgrid = chartGrid.children.item(0);
1224
+ }
1225
+ else {
1226
+ pgrid = document.createElementNS(SVG_NS, 'path');
1227
+ chartGrid.appendChild(pgrid);
1228
+ }
1229
+ const tick = PADDING_PIXELS * .25;
1230
+ let lblCounter = 0;
1231
+ let ensureLabel = (index, x, y, txt) => {
1232
+ const ndx = index + /* <path> is the first child element */ 1;
1233
+ let lbl;
1234
+ if (chartGrid.children.length <= ndx) {
1235
+ lbl = document.createElementNS(SVG_NS, 'text');
1236
+ chartGrid.appendChild(lbl);
1237
+ }
1238
+ else {
1239
+ lbl = chartGrid.children.item(ndx);
1240
+ }
1241
+ lbl.textContent = txt;
1242
+ lbl.setAttribute('x', x.toString());
1243
+ lbl.setAttribute('y', y.toString());
1244
+ return lbl;
1245
+ };
1246
+ let dgrid = `M${paddingYAxis},${padding} v${gridHeight}`; //H${w}
1247
+ // x
1248
+ let j = 0;
1249
+ const xincr = seriesWidth / (grid.x.length /*- 1 consider the extra slot */), yincr = gridHeight / (grid.y.length - 1);
1250
+ if (this.xAxisPosition !== 'none') {
1251
+ const paddingX = xincr * .5 + paddingYAxis;
1252
+ for (var x of grid.x) {
1253
+ let xcoord = paddingX + j * xincr;
1254
+ if (this.xAxisPosition === 'top') {
1255
+ dgrid += ` M${xcoord},${padding} v${-tick}`;
1256
+ let lbl = ensureLabel(lblCounter++, xcoord, 0, x);
1257
+ lbl.setAttribute('text-anchor', 'middle');
1258
+ lbl.setAttribute('alignment-baseline', 'hanging');
1259
+ }
1260
+ else {
1261
+ let ycoord = gridHeight + padding;
1262
+ dgrid += ` M${xcoord},${ycoord} v${tick}`;
1263
+ ensureLabel(lblCounter++, xcoord, ycoord + padding, x).setAttribute('text-anchor', 'middle');
1264
+ }
1265
+ j++;
1266
+ }
1267
+ }
1268
+ // y
1269
+ j = 0;
1270
+ for (var y of grid.y) {
1271
+ const ycoord = gridHeight + padding - j * yincr, xcoord = paddingYAxis - tick;
1272
+ dgrid += ` M${xcoord},${ycoord} H${(seriesWidth + paddingYAxis)}`;
1273
+ let txt = this.formatYAxisLabel(y);
1274
+ ensureLabel(lblCounter++, xcoord - tick, ycoord, txt).setAttribute('text-anchor', 'end');
1275
+ j++;
1276
+ }
1277
+ pgrid.setAttribute('d', dgrid);
1278
+ // exceeding labels?
1279
+ for (let j = chartGrid.children.length - 1; j > lblCounter; j--) {
1280
+ chartGrid.children.item(j).remove();
1281
+ }
1282
+ // #endregion
1283
+ }
1284
+ };
1285
+ __decorate$1([
1286
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.String })
1287
+ ], PacemColumnChartElement.prototype, "type", void 0);
1288
+ __decorate$1([
1289
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Number })
1290
+ ], PacemColumnChartElement.prototype, "groupWidth", void 0);
1291
+ PacemColumnChartElement = __decorate$1([
1292
+ pacemCore.CustomElement({ tagName: pacemCore.P + '-column-chart' })
1293
+ ], PacemColumnChartElement);
1294
+
1295
+ var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1296
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1297
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1298
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1299
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1300
+ };
1301
+ //namespace Pacem.Components.Charts {
1302
+ let PacemPieSliceElement = class PacemPieSliceElement extends pacemCore.Components.PacemItemElement {
1303
+ constructor() {
1304
+ super(...arguments);
1305
+ this._broadcastHandler = (e) => {
1306
+ this.emit(e);
1307
+ };
1308
+ }
1309
+ findContainer() {
1310
+ return pacemCore.CustomElementUtils.findAncestorOfType(this, PacemPieChartElement);
1311
+ }
1312
+ get chart() {
1313
+ return this.container;
1314
+ }
1315
+ /** Returns the center of mass (point) of this pie/doughnut slice, in absolute coords (pixels). */
1316
+ getCenterOfMass() {
1317
+ const area = this.chart && this.chart.area;
1318
+ if (pacemCore.Utils.isNull(area)) {
1319
+ return null;
1320
+ }
1321
+ const rect = pacemCore.Utils.offset(area), center = { x: rect.width / 2 + rect.left, y: rect.top + rect.height / 2 }, r = Math.min(rect.width, rect.height) * .5;
1322
+ const pos = this.normalizedPolarCoords, angle = PI1_2 - pos.angle;
1323
+ return {
1324
+ y: center.y - r * pos.radius * Math.sin(angle),
1325
+ x: center.x + r * pos.radius * Math.cos(angle)
1326
+ };
1327
+ }
1328
+ propertyChangedCallback(name, old, val, first) {
1329
+ super.propertyChangedCallback(name, old, val, first);
1330
+ if (!first && this.chart && name != 'normalizedPolarCoords')
1331
+ this.chart.draw();
1332
+ }
1333
+ /** @internal */
1334
+ _assignUi(el) {
1335
+ const ui = this._ui = el;
1336
+ MANAGED_EVENTS.forEach(type => {
1337
+ ui.addEventListener(type, this._broadcastHandler);
1338
+ });
1339
+ }
1340
+ /** @internal */
1341
+ _disposeUi() {
1342
+ if (!pacemCore.Utils.isNull(this._ui)) {
1343
+ MANAGED_EVENTS.forEach(type => {
1344
+ this._ui.removeEventListener(type, this._broadcastHandler);
1345
+ });
1346
+ }
1347
+ }
1348
+ };
1349
+ __decorate([
1350
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Number })
1351
+ ], PacemPieSliceElement.prototype, "value", void 0);
1352
+ __decorate([
1353
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.String })
1354
+ ], PacemPieSliceElement.prototype, "label", void 0);
1355
+ __decorate([
1356
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.String })
1357
+ ], PacemPieSliceElement.prototype, "color", void 0);
1358
+ __decorate([
1359
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Json })
1360
+ ], PacemPieSliceElement.prototype, "normalizedPolarCoords", void 0);
1361
+ PacemPieSliceElement = __decorate([
1362
+ pacemCore.CustomElement({ tagName: pacemCore.P + '-pie-slice' })
1363
+ ], PacemPieSliceElement);
1364
+ const TWO_PI = Math.PI * 2;
1365
+ const PI1_2 = Math.PI * .5;
1366
+ let PacemPieChartElement = class PacemPieChartElement extends pacemCore.Components.PacemItemsContainerElement {
1367
+ constructor() {
1368
+ super();
1369
+ /** Set a value between 0 and 1, for doughnut appearance. */
1370
+ this.cutout = .0;
1371
+ /** Distance between two consecutive slices, in pixels. */
1372
+ this.slicePadding = .0;
1373
+ this._slices = new WeakMap();
1374
+ this._key = pacemCore.Utils.uniqueCode();
1375
+ }
1376
+ validate(item) {
1377
+ return item instanceof PacemPieSliceElement;
1378
+ }
1379
+ viewActivatedCallback() {
1380
+ super.viewActivatedCallback();
1381
+ this.draw();
1382
+ }
1383
+ propertyChangedCallback(name, old, val, first) {
1384
+ super.propertyChangedCallback(name, old, val, first);
1385
+ if (name === 'target') {
1386
+ this._g = null;
1387
+ this._div && this._div.remove();
1388
+ const eold = old;
1389
+ if (eold) {
1390
+ eold.classList.remove(pacemCore.PCSS + '-chart-area');
1391
+ eold.innerHTML = '';
1392
+ }
1393
+ this.draw();
1394
+ }
1395
+ else if (!first && (name === 'cutout' || name === 'items' || name === 'slicePadding'))
1396
+ this.draw();
1397
+ }
1398
+ get area() {
1399
+ return this._svg;
1400
+ }
1401
+ disconnectedCallback() {
1402
+ this._div && this._div.remove();
1403
+ super.disconnectedCallback();
1404
+ }
1405
+ _ensureArea() {
1406
+ if (pacemCore.Utils.isNull(this._g)) {
1407
+ let div = this.target || (this._div = document.createElement('div'));
1408
+ div.classList.add(pacemCore.PCSS + '-chart-area');
1409
+ let svg = this._svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1410
+ svg.setAttribute('pacem', '');
1411
+ svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
1412
+ svg.setAttribute('viewBox', '0 0 100 100');
1413
+ //svg.style.height =
1414
+ // svg.style.width = '100%';
1415
+ svg.classList.add(pacemCore.PCSS + '-pie-chart');
1416
+ let defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
1417
+ let g = this._g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
1418
+ svg.appendChild(defs);
1419
+ svg.appendChild(g);
1420
+ div.appendChild(svg);
1421
+ this._div &&
1422
+ this.parentElement.insertBefore(div, this);
1423
+ }
1424
+ if (this.maskBasedRendering) {
1425
+ if (pacemCore.Utils.isNull(this._mask)) {
1426
+ let mask = document.createElementNS('http://www.w3.org/2000/svg', 'mask');
1427
+ mask.id = 'pie_mask_' + this._key;
1428
+ let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
1429
+ rect.setAttribute('x', '0');
1430
+ rect.setAttribute('y', '0');
1431
+ rect.setAttribute('width', '100');
1432
+ rect.setAttribute('height', '100');
1433
+ rect.setAttribute('fill', '#fff');
1434
+ let circle = this._mask = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
1435
+ circle.setAttribute('cx', '50');
1436
+ circle.setAttribute('cy', '50');
1437
+ const defs = this._svg.firstElementChild;
1438
+ mask.appendChild(rect);
1439
+ mask.appendChild(circle);
1440
+ defs.appendChild(mask);
1441
+ this._g.setAttribute('mask', `url(#${mask.id})`);
1442
+ }
1443
+ const cutout = 50.0 * this._safeCutout;
1444
+ this._mask.setAttribute('r', `${cutout}`);
1445
+ }
1446
+ else {
1447
+ if (!pacemCore.Utils.isNull(this._mask)) {
1448
+ this._svg.firstElementChild.innerHTML = '';
1449
+ this._mask = null;
1450
+ this._g.removeAttribute('mask');
1451
+ }
1452
+ }
1453
+ // has padded slices?
1454
+ const paddingPixels = this._safeSlicePaddingPixels;
1455
+ if (paddingPixels > 0) {
1456
+ const matrix = this._svg.getCTM();
1457
+ const paddingUnits = (paddingPixels / matrix.a).roundoff();
1458
+ const maskId = this._sliceMaskId;
1459
+ const defs = this._svg.firstElementChild;
1460
+ let mask = defs.querySelector(`#${maskId}`);
1461
+ if (pacemCore.Utils.isNull(mask)) {
1462
+ mask = document.createElementNS('http://www.w3.org/2000/svg', 'mask');
1463
+ mask.id = maskId;
1464
+ defs.appendChild(mask);
1465
+ }
1466
+ else {
1467
+ mask.innerHTML = '';
1468
+ }
1469
+ const maskPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1470
+ const d = `M${(50 + paddingUnits)},0 H100 V100 H0 V0 H50 V50 h${paddingUnits} Z`;
1471
+ maskPath.setAttribute('d', d);
1472
+ maskPath.setAttribute('fill', '#fff');
1473
+ mask.appendChild(maskPath);
1474
+ }
1475
+ return this._g;
1476
+ }
1477
+ get _sliceMaskId() {
1478
+ return 'pieslice_mask_' + this._key;
1479
+ }
1480
+ get _safeCutout() {
1481
+ return Math.min(1, Math.max(0, this.cutout)) || .0;
1482
+ }
1483
+ get _safeSlicePaddingPixels() {
1484
+ return Math.max(0, this.slicePadding ?? 0);
1485
+ }
1486
+ _drawSlice(path, slice, whole, partial) {
1487
+ const largeFlag = slice.value > .5 * whole ? 1 : 0;
1488
+ const angle = TWO_PI * slice.value / whole;
1489
+ const rot = 360.0 * partial / whole;
1490
+ const x = (slice.value >= whole) ? /* handling single slice */ 49.9 : 50 * (1 + Math.sin(angle));
1491
+ const y = 50 * (1 - Math.cos(angle));
1492
+ // set geometry data
1493
+ const c = this._safeCutout, r = c * 50.0;
1494
+ path.style.fill = slice.color; //.setAttribute('fill', slice.color || (path.getAttribute('fill') || '#000'));
1495
+ //path.setAttribute('transform', `rotate(${rot} 50 50)`);
1496
+ path.style.transform = `rotate(${rot}deg)`;
1497
+ path.style.transformOrigin = '50% 50%';
1498
+ const d = this.maskBasedRendering ?
1499
+ `M50,50 V0 A50,50 0 ${largeFlag} 1 ${x} ${y} L50,50 Z` :
1500
+ `M50,0 A50,50 0 ${largeFlag} 1 ${x} ${y} l${(50 - x) * (1.0 - c)},${(50 - y) * (1.0 - c)} A${r},${r} 0 ${largeFlag} 0 50,${(50 - r)} Z`;
1501
+ path.setAttribute('d', d);
1502
+ slice.normalizedPolarCoords = { radius: c + Math.SQRT1_2 * (1.0 - c), angle: /* deg to rad */ Math.PI * rot / 180.0 + angle / 2 };
1503
+ }
1504
+ _isSliceOk(slice) {
1505
+ return !slice.disabled //&& slice.value > 0
1506
+ ;
1507
+ }
1508
+ _padSlice(path) {
1509
+ const paddingPixels = this._safeSlicePaddingPixels;
1510
+ if (paddingPixels > 0) {
1511
+ path.setAttribute('mask', `url(#${this._sliceMaskId})`);
1512
+ }
1513
+ else {
1514
+ path.removeAttribute('mask');
1515
+ }
1516
+ }
1517
+ draw() {
1518
+ const g = this._ensureArea(), pCount = g.children.length, chartArea = this._svg.parentElement;
1519
+ let ndx = 0, sum = .0, progress = .0;
1520
+ if (pacemCore.Utils.isNullOrEmpty(this.items)) {
1521
+ g.innerHTML = '';
1522
+ pacemCore.Utils.removeClass(chartArea, 'chart-has-data');
1523
+ }
1524
+ else {
1525
+ pacemCore.Utils.addClass(chartArea, 'chart-has-data');
1526
+ for (let slice of this.items) {
1527
+ if (!this._isSliceOk(slice)) {
1528
+ continue;
1529
+ }
1530
+ sum += slice.value;
1531
+ }
1532
+ if (sum <= 0) {
1533
+ g.innerHTML = '';
1534
+ pacemCore.Utils.removeClass(chartArea, 'chart-has-data');
1535
+ }
1536
+ else {
1537
+ for (let slice of this.items) {
1538
+ if (!this._isSliceOk(slice)) {
1539
+ continue;
1540
+ }
1541
+ let p;
1542
+ if (ndx >= pCount) {
1543
+ const g_n = document.createElementNS('http://www.w3.org/2000/svg', 'g');
1544
+ g_n.setAttribute('class', 'chart-series ' + pacemCore.PCSS + '-pie-slice' + (pacemCore.Utils.isNullOrEmpty(slice.className) ? '' : (' ' + slice.className)));
1545
+ p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1546
+ g_n.appendChild(p);
1547
+ g.appendChild(g_n);
1548
+ // add listeners (click, mouse-..., touch-...)
1549
+ slice._assignUi(g_n);
1550
+ this._slices.set(g_n, slice);
1551
+ }
1552
+ else {
1553
+ p = g.children.item(ndx).firstElementChild;
1554
+ }
1555
+ if (slice.value > 0) {
1556
+ this._drawSlice(p, slice, sum, progress);
1557
+ this._padSlice(p);
1558
+ progress += slice.value;
1559
+ p.removeAttribute('display');
1560
+ }
1561
+ else {
1562
+ p.setAttribute('display', 'none');
1563
+ }
1564
+ ndx++;
1565
+ }
1566
+ }
1567
+ }
1568
+ while (ndx < g.children.length) {
1569
+ const slices = this._slices, g_n = g.children.item(ndx);
1570
+ // remove listeners
1571
+ if (slices.has(g_n)) {
1572
+ slices.get(g_n)._disposeUi();
1573
+ slices.delete(g_n);
1574
+ }
1575
+ g.removeChild(g_n);
1576
+ }
1577
+ }
1578
+ };
1579
+ __decorate([
1580
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Number })
1581
+ ], PacemPieChartElement.prototype, "cutout", void 0);
1582
+ __decorate([
1583
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Element })
1584
+ ], PacemPieChartElement.prototype, "target", void 0);
1585
+ __decorate([
1586
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Boolean })
1587
+ ], PacemPieChartElement.prototype, "maskBasedRendering", void 0);
1588
+ __decorate([
1589
+ pacemCore.Watch({ converter: pacemCore.PropertyConverters.Number })
1590
+ ], PacemPieChartElement.prototype, "slicePadding", void 0);
1591
+ __decorate([
1592
+ pacemCore.Debounce(true)
1593
+ ], PacemPieChartElement.prototype, "draw", null);
1594
+ PacemPieChartElement = __decorate([
1595
+ pacemCore.CustomElement({ tagName: pacemCore.P + '-pie-chart' })
1596
+ ], PacemPieChartElement);
1597
+
1598
+ var indexComponentsCharts = /*#__PURE__*/Object.freeze({
1599
+ __proto__: null,
1600
+ ChartEvent: ChartEvent,
1601
+ MANAGED_EVENTS: MANAGED_EVENTS,
1602
+ get PacemChartElement () { return PacemChartElement; },
1603
+ get PacemChartSeriesElement () { return PacemChartSeriesElement; },
1604
+ get PacemColumnChartElement () { return PacemColumnChartElement; },
1605
+ get PacemPieChartElement () { return PacemPieChartElement; },
1606
+ get PacemPieSliceElement () { return PacemPieSliceElement; },
1607
+ PacemSeriesChartElement: PacemSeriesChartElement
1608
+ });
1609
+
1610
+ var indexComponents = /*#__PURE__*/Object.freeze({
1611
+ __proto__: null,
1612
+ Charts: indexComponentsCharts
1613
+ });
1614
+
1615
+ var Output = /*#__PURE__*/Object.freeze({
1616
+ __proto__: null,
1617
+ Components: indexComponents
1618
+ });
1619
+
1620
+ pacemFoundation.DeepMerger.merge(Output);
1621
+
1622
+ })(Pacem, Pacem);
1623
+ //# sourceMappingURL=pacem-charts.js.map