@vaadin/charts 24.7.0-alpha7 → 24.7.0-alpha9

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.
@@ -8,96 +8,12 @@
8
8
  * See https://vaadin.com/commercial-license-and-service-terms for the full
9
9
  * license.
10
10
  */
11
- import 'highcharts/es-modules/masters/highstock.src.js';
12
- import 'highcharts/es-modules/masters/modules/accessibility.src.js';
13
- import 'highcharts/es-modules/masters/modules/annotations.src.js';
14
- import 'highcharts/es-modules/masters/highcharts-more.src.js';
15
- import 'highcharts/es-modules/masters/highcharts-3d.src.js';
16
- import 'highcharts/es-modules/masters/modules/data.src.js';
17
- import 'highcharts/es-modules/masters/modules/drilldown.src.js';
18
- import 'highcharts/es-modules/masters/modules/exporting.src.js';
19
- import 'highcharts/es-modules/masters/modules/funnel.src.js';
20
- import 'highcharts/es-modules/masters/modules/heatmap.src.js';
21
- import 'highcharts/es-modules/masters/modules/solid-gauge.src.js';
22
- import 'highcharts/es-modules/masters/modules/treemap.src.js';
23
- import 'highcharts/es-modules/masters/modules/no-data-to-display.src.js';
24
- import 'highcharts/es-modules/masters/modules/sankey.src.js';
25
- import 'highcharts/es-modules/masters/modules/timeline.src.js';
26
- import 'highcharts/es-modules/masters/modules/organization.src.js';
27
- import 'highcharts/es-modules/masters/modules/xrange.src.js';
28
- import 'highcharts/es-modules/masters/modules/bullet.src.js';
29
- import 'highcharts/es-modules/masters/modules/gantt.src.js';
30
- import 'highcharts/es-modules/masters/modules/draggable-points.src.js';
31
- import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
32
- import { beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
11
+ import './vaadin-chart-series.js';
33
12
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
34
- import Pointer from 'highcharts/es-modules/Core/Pointer.js';
35
- import Highcharts from 'highcharts/es-modules/masters/highstock.src.js';
36
13
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
37
14
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
38
- import { get } from '@vaadin/component-base/src/path-utils.js';
39
- import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
40
15
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
41
- import { inflateFunctions } from './helpers.js';
42
- import { ChartSeries } from './vaadin-chart-series.js';
43
-
44
- /** @private */
45
- export function deepMerge(target, source) {
46
- const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);
47
-
48
- if (isObject(source) && isObject(target)) {
49
- Object.keys(source).forEach((key) => {
50
- if (isObject(source[key])) {
51
- if (!target[key]) {
52
- Object.assign(target, { [key]: {} });
53
- }
54
-
55
- deepMerge(target[key], source[key]);
56
- } else {
57
- Object.assign(target, { [key]: source[key] });
58
- }
59
- });
60
- }
61
-
62
- return target;
63
- }
64
-
65
- ['exportChart', 'exportChartLocal', 'getSVG'].forEach((methodName) => {
66
- /* eslint-disable @typescript-eslint/no-invalid-this, prefer-arrow-callback */
67
- Highcharts.wrap(Highcharts.Chart.prototype, methodName, function (proceed, ...args) {
68
- Highcharts.fireEvent(this, 'beforeExport');
69
- const result = proceed.apply(this, args);
70
- Highcharts.fireEvent(this, 'afterExport');
71
- return result;
72
- });
73
- /* eslint-enable no-invalid-this */
74
- });
75
-
76
- // Monkeypatch the onDocumentMouseMove method to fix the check for the source of the event
77
- // Due to the fact that the event is attached to the document, the target of the event is
78
- // the <vaadin-chart> element, so we need to use the composedPath to get the actual target (#7107)
79
- Pointer.prototype.onDocumentMouseMove = function (e) {
80
- const chart = this.chart;
81
- const chartPosition = this.chartPosition;
82
- const pEvt = this.normalize(e, chartPosition);
83
- const tooltip = chart.tooltip;
84
- // If we're outside, hide the tooltip
85
- if (
86
- chartPosition &&
87
- (!tooltip || !tooltip.isStickyOnContact()) &&
88
- !chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
89
- visiblePlotOnly: true,
90
- }) &&
91
- // Use the first element from the composed path instead of the actual target
92
- !this.inClass(pEvt.composedPath()[0], 'highcharts-tracker')
93
- ) {
94
- this.reset();
95
- }
96
- };
97
-
98
- // Init Highcharts global language defaults
99
- // No data message should be empty by default
100
- Highcharts.setOptions({ lang: { noData: '' } });
16
+ import { ChartMixin } from './vaadin-chart-mixin.js';
101
17
 
102
18
  /**
103
19
  * `<vaadin-chart>` is a Web Component for creating high quality charts.
@@ -259,11 +175,11 @@ Highcharts.setOptions({ lang: { noData: '' } });
259
175
  *
260
176
  * @customElement
261
177
  * @extends HTMLElement
262
- * @mixes ResizeMixin
178
+ * @mixes ChartMixin
263
179
  * @mixes ThemableMixin
264
180
  * @mixes ElementMixin
265
181
  */
266
- class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
182
+ class Chart extends ChartMixin(ThemableMixin(ElementMixin(PolymerElement))) {
267
183
  static get template() {
268
184
  return html`
269
185
  <style>
@@ -289,1597 +205,6 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
289
205
  static get cvdlName() {
290
206
  return 'vaadin-chart';
291
207
  }
292
-
293
- static get properties() {
294
- return {
295
- /**
296
- * Configuration object that exposes the JS Api to configure the chart.
297
- *
298
- * Most important methods are:
299
- * - `addSeries (Object options, [Boolean redraw], [Mixed animation])`
300
- * - `addAxis (Object options, [Boolean isX], [Boolean redraw], [Mixed animation])`
301
- * - `setTitle (Object title, object subtitle, Boolean redraw)`
302
- *
303
- * Most important properties are:
304
- * - `configuration.series`: An array of the chart's series. Detailed API for Series object is
305
- * available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Series)
306
- * - `configuration.xAxis`: An array of the chart's x axes. Detailed API for Axis object is
307
- * available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Axis)
308
- * - `configuration.yAxis`: An array of the chart's y axes. Detailed API for Axis object is
309
- * available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Axis)
310
- * - `configuration.title`: The chart title.
311
- *
312
- * For detailed documentation of available API check the [API site](http://api.highcharts.com/class-reference/classes.list)
313
- * @type {!Highcharts.Chart | undefined}
314
- */
315
- configuration: Object,
316
-
317
- /**
318
- * If categories are present names are used instead of numbers for the category axis.
319
- * The format of categories can be an `Array` with a list of categories, such as `['2010', '2011', '2012']`
320
- * or a mapping `Object`, like `{0:'1',9:'Target (10)', 15: 'Max'}`.
321
- * @type {ChartCategories | undefined}
322
- */
323
- categories: {
324
- type: Object,
325
- reflectToAttribute: true,
326
- },
327
-
328
- /**
329
- * Category-axis maximum value. Defaults to `undefined`.
330
- * @attr {number} category-max
331
- */
332
- categoryMax: {
333
- type: Number,
334
- reflectToAttribute: true,
335
- },
336
-
337
- /**
338
- * Category-axis minimum value. Defaults to `undefined`.
339
- * @attr {number} category-min
340
- */
341
- categoryMin: {
342
- type: Number,
343
- reflectToAttribute: true,
344
- },
345
-
346
- /**
347
- * The position of the category axis. Acceptable values are `left`, `right`, `top` and `bottom`
348
- * except for bar charts which only accept `left` and `right`.
349
- * With the default value, charts appear as though they have `category-position="bottom"`
350
- * except for bar charts that appear as though they have `category-position="left"`.
351
- *
352
- * Defaults to `undefined`
353
- *
354
- * @attr {left|right|top|bottom} category-position
355
- * @type {ChartCategoryPosition | undefined}
356
- */
357
- categoryPosition: {
358
- type: String,
359
- reflectToAttribute: true,
360
- },
361
-
362
- /**
363
- * Specifies whether to hide legend or show.
364
- * Legend configuration can be set up via additionalOptions property
365
- * @attr {boolean} no-legend
366
- */
367
- noLegend: {
368
- type: Boolean,
369
- reflectToAttribute: true,
370
- },
371
-
372
- /**
373
- * Specifies how series are stacked on top of each other.
374
- * Possible values are null, "normal" or "percent".
375
- * If "stack" property is not defined on the vaadin-chart-series elements, then series will be put into
376
- * the default stack.
377
- * @attr {normal|percent} stacking
378
- * @type {ChartStacking | undefined}
379
- */
380
- stacking: {
381
- type: String,
382
- reflectToAttribute: true,
383
- },
384
-
385
- /**
386
- * Specifies whether the chart is a normal chart or a timeline chart.
387
- * Value of this property is ignored for Gantt charts (type="gantt").
388
- */
389
- timeline: {
390
- type: Boolean,
391
- reflectToAttribute: true,
392
- },
393
-
394
- /**
395
- * Represents the title of the chart.
396
- * @type {string}
397
- */
398
- title: {
399
- type: String,
400
- reflectToAttribute: true,
401
- },
402
-
403
- /**
404
- * Whether or not to show tooltip when hovering data points.
405
- */
406
- tooltip: {
407
- type: Boolean,
408
- reflectToAttribute: true,
409
- },
410
-
411
- /**
412
- * Sets the default series type of the chart.
413
- * Note that `'bar'`, `'gauge'` and `'solidgauge'` should be set as default series type.
414
- */
415
- type: {
416
- type: String,
417
- reflectToAttribute: true,
418
- },
419
-
420
- /**
421
- * Represents the subtitle of the chart.
422
- * @type {string | undefined}
423
- */
424
- subtitle: {
425
- type: String,
426
- reflectToAttribute: true,
427
- },
428
-
429
- /**
430
- * Specifies whether to show chart in 3 or in 2 dimensions.
431
- * Some display angles are added by default to the "chart.options3d" (`{alpha: 15, beta: 15, depth: 50}`).
432
- * 3D display options can be modified via `additionalOptions`.
433
- * The thickness of a Pie chart can be set on `additionalOptions` through `plotOptions.pie.depth`.
434
- * 3D is supported by Bar, Column, Pie and Scatter3D charts.
435
- * More info available at [Highcharts](https://www.highcharts.com/docs/chart-concepts/3d-charts).
436
- */
437
- chart3d: {
438
- type: Boolean,
439
- reflectToAttribute: true,
440
- },
441
-
442
- /**
443
- * Specifies the message displayed on a chart without displayable data.
444
- * @attr {string} empty-text
445
- * @type {string}
446
- */
447
- emptyText: {
448
- type: String,
449
- reflectToAttribute: true,
450
- },
451
-
452
- /**
453
- * Represents additional JSON configuration.
454
- * @type {Options | undefined}
455
- */
456
- additionalOptions: {
457
- type: Object,
458
- reflectToAttribute: true,
459
- },
460
-
461
- /**
462
- * When present, cartesian charts like line, spline, area and column are transformed
463
- * into the polar coordinate system.
464
- */
465
- polar: {
466
- type: Boolean,
467
- reflectToAttribute: true,
468
- },
469
- };
470
- }
471
-
472
- static get observers() {
473
- return [
474
- '__chart3dObserver(chart3d, configuration)',
475
- '__emptyTextObserver(emptyText, configuration)',
476
- '__hideLegend(noLegend, configuration)',
477
- '__polarObserver(polar, configuration)',
478
- '__stackingObserver(stacking, configuration)',
479
- '__tooltipObserver(tooltip, configuration)',
480
- '__updateCategories(categories, configuration)',
481
- '__updateCategoryMax(categoryMax, configuration)',
482
- '__updateCategoryMin(categoryMin, configuration)',
483
- '__updateCategoryPosition(categoryPosition, configuration)',
484
- '__updateSubtitle(subtitle, configuration)',
485
- '__updateTitle(title, configuration)',
486
- '__updateType(type, configuration)',
487
- '__updateAdditionalOptions(additionalOptions.*)',
488
- ];
489
- }
490
-
491
- /** @private */
492
- static __callHighchartsFunction(functionName, redrawCharts, ...args) {
493
- const functionToCall = Highcharts[functionName];
494
- if (functionToCall && typeof functionToCall === 'function') {
495
- args.forEach((arg) => inflateFunctions(arg));
496
- functionToCall.apply(this.configuration, args);
497
- if (redrawCharts) {
498
- Highcharts.charts.forEach((c) => {
499
- // Ignore `undefined` values that are preserved in the array
500
- // after their corresponding chart instances are destroyed.
501
- // See https://github.com/vaadin/flow-components/issues/6607
502
- if (c !== undefined) {
503
- c.redraw();
504
- }
505
- });
506
- }
507
- }
508
- }
509
-
510
- constructor() {
511
- super();
512
-
513
- this._baseConfig = {
514
- annotations: [],
515
- chart: {
516
- styledMode: true,
517
- },
518
- credits: {
519
- enabled: false,
520
- },
521
- exporting: {
522
- enabled: false,
523
- },
524
- title: {
525
- text: null,
526
- },
527
- series: [],
528
- xAxis: {},
529
- yAxis: {
530
- axisGenerated: true,
531
- },
532
- };
533
-
534
- this._baseChart3d = {
535
- enabled: true,
536
- alpha: 15,
537
- beta: 15,
538
- depth: 50,
539
- };
540
- }
541
-
542
- /**
543
- * @return {!Options}
544
- */
545
- get options() {
546
- const options = { ...this._baseConfig };
547
- deepMerge(options, this.additionalOptions);
548
-
549
- if (this.type) {
550
- options.chart.type = this.type;
551
- }
552
-
553
- if (this.polar) {
554
- options.chart.polar = true;
555
- }
556
-
557
- if (this.title) {
558
- options.title = {
559
- text: this.title,
560
- };
561
- }
562
-
563
- if (!options.tooltip) {
564
- // Workaround for highcharts#7398 to make updating tooltip works
565
- options.tooltip = {};
566
- if (!this.tooltip) {
567
- options.tooltip.enabled = false;
568
- }
569
- }
570
-
571
- if (this.subtitle) {
572
- options.subtitle = {
573
- text: this.subtitle,
574
- };
575
- }
576
-
577
- if (this.categories) {
578
- if (Array.isArray(options.xAxis)) {
579
- // Set categories on first X axis
580
- options.xAxis[0].categories = this.categories;
581
- } else {
582
- options.xAxis.categories = this.categories;
583
- }
584
- }
585
-
586
- if (isFinite(this.categoryMin)) {
587
- if (Array.isArray(options.xAxis)) {
588
- // Set category-min on first X axis
589
- options.xAxis[0].min = this.categoryMin;
590
- } else {
591
- options.xAxis.min = this.categoryMin;
592
- }
593
- }
594
-
595
- if (isFinite(this.categoryMax)) {
596
- if (Array.isArray(options.xAxis)) {
597
- // Set category-max on first x axis
598
- options.xAxis[0].max = this.categoryMax;
599
- } else {
600
- options.xAxis.max = this.categoryMax;
601
- }
602
- }
603
-
604
- if (this.noLegend) {
605
- options.legend = {
606
- enabled: false,
607
- };
608
- }
609
-
610
- if (this.emptyText) {
611
- if (!options.lang) {
612
- options.lang = {};
613
- }
614
- options.lang.noData = this.emptyText;
615
- }
616
-
617
- if (this.categoryPosition) {
618
- options.chart.inverted = this.__shouldInvert();
619
-
620
- if (Array.isArray(options.xAxis)) {
621
- options.xAxis.forEach((e) => {
622
- e.opposite = this.__shouldFlipOpposite();
623
- });
624
- } else if (options.xAxis) {
625
- options.xAxis.opposite = this.__shouldFlipOpposite();
626
- }
627
- }
628
-
629
- if (this.stacking) {
630
- if (!options.plotOptions) {
631
- options.plotOptions = {};
632
- }
633
- if (!options.plotOptions.series) {
634
- options.plotOptions.series = {};
635
- }
636
- options.plotOptions.series.stacking = this.stacking;
637
- }
638
-
639
- if (this.chart3d) {
640
- options.chart.options3d = { ...this._baseChart3d, ...options.chart.options3d };
641
- }
642
-
643
- return options;
644
- }
645
-
646
- /**
647
- * Name of the chart events to add to the configuration and its corresponding event for the chart element
648
- * @private
649
- */
650
- get __chartEventNames() {
651
- return {
652
- /**
653
- * Fired when a new series is added.
654
- * @event chart-add-series
655
- * @param {Object} detail.originalEvent object with details about the event sent
656
- * @param {Object} chart Chart object where the event was sent from
657
- */
658
- addSeries: 'chart-add-series',
659
-
660
- /**
661
- * Fired after a chart is exported.
662
- * @event chart-after-export
663
- * @param {Object} detail.originalEvent object with details about the event sent
664
- * @param {Object} chart Chart object where the event was sent from
665
- */
666
- afterExport: 'chart-after-export',
667
-
668
- /**
669
- * Fired after a chart is printed.
670
- * @event chart-after-print
671
- * @param {Object} detail.originalEvent object with details about the event sent
672
- * @param {Object} chart Chart object where the event was sent from
673
- */
674
- afterPrint: 'chart-after-print',
675
-
676
- /**
677
- * Fired before a chart is exported.
678
- * @event chart-before-export
679
- * @param {Object} detail.originalEvent object with details about the event sent
680
- * @param {Object} chart Chart object where the event was sent from
681
- */
682
- beforeExport: 'chart-before-export',
683
-
684
- /**
685
- * Fired before a chart is printed.
686
- * @event chart-before-print
687
- * @param {Object} detail.originalEvent object with details about the event sent
688
- * @param {Object} chart Chart object where the event was sent from
689
- */
690
- beforePrint: 'chart-before-print',
691
-
692
- /**
693
- * Fired when clicking on the plot background.
694
- * @event chart-click
695
- * @param {Object} detail.originalEvent object with details about the event sent
696
- * @param {Object} chart Chart object where the event was sent from
697
- */
698
- click: 'chart-click',
699
-
700
- /**
701
- * Fired when drilldown point is clicked.
702
- * @event chart-drilldown
703
- * @param {Object} detail.originalEvent object with details about the event sent
704
- * @param {Object} chart Chart object where the event was sent from
705
- */
706
- drilldown: 'chart-drilldown',
707
-
708
- /**
709
- * Fired when drilling up from a drilldown series.
710
- * @event chart-drillup
711
- * @param {Object} detail.originalEvent object with details about the event sent
712
- * @param {Object} chart Chart object where the event was sent from
713
- */
714
- drillup: 'chart-drillup',
715
-
716
- /**
717
- * Fired after all the series has been drilled up if chart has multiple drilldown series.
718
- * @event chart-drillupall
719
- * @param {Object} detail.originalEvent object with details about the event sent
720
- * @param {Object} chart Chart object where the event was sent from
721
- */
722
- drillupall: 'chart-drillupall',
723
-
724
- /**
725
- * Fired when the chart is finished loading.
726
- * @event chart-load
727
- * @param {Object} detail.originalEvent object with details about the event sent
728
- * @param {Object} chart Chart object where the event was sent from
729
- */
730
- load: 'chart-load',
731
-
732
- /**
733
- * Fired when the chart is redraw. Can be called after a `Chart.configuration.redraw()`
734
- * or after an axis, series or point is modified with the `redraw` option set to `true`.
735
- * @event chart-redraw
736
- * @param {Object} detail.originalEvent object with details about the event sent
737
- * @param {Object} chart Chart object where the event was sent from
738
- */
739
- redraw: 'chart-redraw',
740
-
741
- /**
742
- * Fired when an area of the chart has been selected.
743
- * @event chart-selection
744
- * @param {Object} detail.originalEvent object with details about the event sent
745
- * @param {Object} chart Chart object where the event was sent from
746
- */
747
- selection: 'chart-selection',
748
- };
749
- }
750
-
751
- /**
752
- * Name of the series events to add to the configuration and its corresponding event for the chart element
753
- * @private
754
- */
755
- get __seriesEventNames() {
756
- return {
757
- /**
758
- * Fired when the series has finished its initial animation.
759
- * @event series-after-animate
760
- * @param {Object} detail.originalEvent object with details about the event sent
761
- * @param {Object} series Series object where the event was sent from
762
- */
763
- afterAnimate: 'series-after-animate',
764
-
765
- /**
766
- * Fired when the checkbox next to the series' name in the legend is clicked.
767
- * @event series-checkbox-click
768
- * @param {Object} detail.originalEvent object with details about the event sent
769
- * @param {Object} series Series object where the event was sent from
770
- */
771
- checkboxClick: 'series-checkbox-click',
772
-
773
- /**
774
- * Fired when the series is clicked.
775
- * @event series-click
776
- * @param {Object} detail.originalEvent object with details about the event sent
777
- * @param {Object} series Series object where the event was sent from
778
- */
779
- click: 'series-click',
780
-
781
- /**
782
- * Fired when the series is hidden after chart generation time.
783
- * @event series-hide
784
- * @param {Object} detail.originalEvent object with details about the event sent
785
- * @param {Object} series Series object where the event was sent from
786
- */
787
- hide: 'series-hide',
788
-
789
- /**
790
- * Fired when the legend item belonging to the series is clicked.
791
- * @event series-legend-item-click
792
- * @param {Object} detail.originalEvent object with details about the event sent
793
- * @param {Object} series Series object where the event was sent from
794
- */
795
- legendItemClick: 'series-legend-item-click',
796
-
797
- /**
798
- * Fired when the mouses leave the graph.
799
- * @event series-mouse-out
800
- * @param {Object} detail.originalEvent object with details about the event sent
801
- * @param {Object} series Series object where the event was sent from
802
- */
803
- mouseOut: 'series-mouse-out',
804
-
805
- /**
806
- * Fired when the mouse enters the graph.
807
- * @event series-mouse-over
808
- * @param {Object} detail.originalEvent object with details about the event sent
809
- * @param {Object} series Series object where the event was sent from
810
- */
811
- mouseOver: 'series-mouse-over',
812
-
813
- /**
814
- * Fired when the series is show after chart generation time.
815
- * @event series-show
816
- * @param {Object} detail.originalEvent object with details about the event sent
817
- * @param {Object} series Series object where the event was sent from
818
- */
819
- show: 'series-show',
820
- };
821
- }
822
-
823
- /**
824
- * Name of the point events to add to the configuration and its corresponding event for the chart element
825
- * @private
826
- */
827
- get __pointEventNames() {
828
- return {
829
- /**
830
- * Fired when the point is clicked.
831
- * @event point-click
832
- * @param {Object} detail.originalEvent object with details about the event sent
833
- * @param {Object} point Point object where the event was sent from
834
- */
835
- click: 'point-click',
836
-
837
- /**
838
- * Fired when the legend item belonging to the point is clicked.
839
- * @event point-legend-item-click
840
- * @param {Object} detail.originalEvent object with details about the event sent
841
- * @param {Object} point Point object where the event was sent from
842
- */
843
- legendItemClick: 'point-legend-item-click',
844
-
845
- /**
846
- * Fired when the mouse leaves the area close to the point.
847
- * @event point-mouse-out
848
- * @param {Object} detail.originalEvent object with details about the event sent
849
- * @param {Object} point Point object where the event was sent from
850
- */
851
- mouseOut: 'point-mouse-out',
852
-
853
- /**
854
- * Fired when the mouse enters the area close to the point.
855
- * @event point-mouse-over
856
- * @param {Object} detail.originalEvent object with details about the event sent
857
- * @param {Object} point Point object where the event was sent from
858
- */
859
- mouseOver: 'point-mouse-over',
860
-
861
- /**
862
- * Fired when the point is removed from the series.
863
- * @event point-remove
864
- * @param {Object} detail.originalEvent object with details about the event sent
865
- * @param {Object} point Point object where the event was sent from
866
- */
867
- remove: 'point-remove',
868
-
869
- /**
870
- * Fired when the point is selected either programmatically or by clicking on the point.
871
- * @event point-select
872
- * @param {Object} detail.originalEvent object with details about the event sent
873
- * @param {Object} point Point object where the event was sent from
874
- */
875
- select: 'point-select',
876
-
877
- /**
878
- * Fired when the point is unselected either programmatically or by clicking on the point
879
- * @event point-unselect
880
- * @param {Object} detail.originalEvent object with details about the event sent
881
- * @param {Object} point Point object where the event was sent from
882
- */
883
- unselect: 'point-unselect',
884
-
885
- /**
886
- * Fired when the point is updated programmatically through `.updateConfiguration()` method.
887
- * @event point-update
888
- * @param {Object} detail.originalEvent object with details about the event sent
889
- * @param {Object} point Point object where the event was sent from
890
- */
891
- update: 'point-update',
892
-
893
- /**
894
- * Fired when starting to drag a point.
895
- * @event point-drag-start
896
- * @param {Object} detail.originalEvent object with details about the event sent
897
- * @param {Object} point Point object where the event was sent from
898
- */
899
- dragStart: 'point-drag-start',
900
-
901
- /**
902
- * Fired when the point is dropped.
903
- * @event point-drop
904
- * @param {Object} detail.originalEvent object with details about the event sent
905
- * @param {Object} point Point object where the event was sent from
906
- */
907
- drop: 'point-drop',
908
-
909
- /**
910
- * Fired while dragging a point.
911
- * @event point-drag
912
- * @param {Object} detail.originalEvent object with details about the event sent
913
- * @param {Object} point Point object where the event was sent from
914
- */
915
- drag: 'point-drag',
916
- };
917
- }
918
-
919
- /** @private */
920
- get __xAxesEventNames() {
921
- return {
922
- /**
923
- * Fired when when the minimum and maximum is set for the x axis.
924
- * @event xaxes-extremes-set
925
- * @param {Object} detail.originalEvent object with details about the event sent
926
- * @param {Object} axis Point object where the event was sent from
927
- */
928
- afterSetExtremes: 'xaxes-extremes-set',
929
- };
930
- }
931
-
932
- /** @private */
933
- get __yAxesEventNames() {
934
- return {
935
- /**
936
- * Fired when when the minimum and maximum is set for the y axis.
937
- * @event yaxes-extremes-set
938
- * @param {Object} detail.originalEvent object with details about the event sent
939
- * @param {Object} axis Point object where the event was sent from
940
- */
941
- afterSetExtremes: 'yaxes-extremes-set',
942
- };
943
- }
944
-
945
- /** @protected */
946
- connectedCallback() {
947
- super.connectedCallback();
948
- this.__updateStyles();
949
- beforeNextRender(this, () => {
950
- // Detect if the chart had already been initialized. This might happen in
951
- // environments where the chart is lazily attached (e.g Grid).
952
- if (this.configuration) {
953
- this.__reflow();
954
- return;
955
- }
956
-
957
- this.__resetChart();
958
- this.__addChildObserver();
959
- this.__checkTurboMode();
960
- });
961
- }
962
-
963
- /** @protected */
964
- ready() {
965
- super.ready();
966
-
967
- this.addEventListener('chart-redraw', this.__onRedraw.bind(this));
968
- }
969
-
970
- /**
971
- * Implements resize callback from `ResizeMixin`
972
- * to reflow when the chart element is resized.
973
- * @protected
974
- * @override
975
- */
976
- _onResize(contentRect) {
977
- if (!this.configuration) {
978
- return;
979
- }
980
-
981
- const { height, width } = contentRect;
982
- const { chartHeight, chartWidth } = this.configuration;
983
-
984
- if (height !== chartHeight || width !== chartWidth) {
985
- this.__reflow();
986
- }
987
- }
988
-
989
- /** @private */
990
- __reflow() {
991
- if (!this.configuration) {
992
- return;
993
- }
994
- this.configuration.reflow();
995
- }
996
-
997
- /** @private */
998
- __addChildObserver() {
999
- this._childObserver = new FlattenedNodesObserver(this.$.slot, (info) => {
1000
- this.__addSeries(info.addedNodes.filter(this.__filterSeriesNodes));
1001
- this.__removeSeries(info.removedNodes.filter(this.__filterSeriesNodes));
1002
- this.__cleanupAfterSeriesRemoved(info.removedNodes.filter(this.__filterSeriesNodes));
1003
- });
1004
- }
1005
-
1006
- /** @private */
1007
- __filterSeriesNodes(node) {
1008
- return node.nodeType === Node.ELEMENT_NODE && node instanceof ChartSeries;
1009
- }
1010
-
1011
- /** @private */
1012
- __addSeries(series) {
1013
- if (this.__isSeriesEmpty(series)) {
1014
- return;
1015
- }
1016
- const seriesNodes = Array.from(this.childNodes).filter(this.__filterSeriesNodes);
1017
-
1018
- const yAxes = this.configuration.yAxis.reduce((acc, axis, index) => {
1019
- acc[axis.options.id || index] = axis;
1020
- return acc;
1021
- }, {});
1022
-
1023
- for (let i = 0, len = series.length; i < len; i++) {
1024
- const seriesElement = series[i];
1025
- const { yAxis: unit, yAxisValueMin: valueMin, yAxisValueMax: valueMax } = seriesElement.options;
1026
-
1027
- const idxOnChildList = seriesNodes.indexOf(seriesElement);
1028
- if (!unit && !this.configuration.yAxis.some((e) => e.userOptions.id === undefined)) {
1029
- yAxes[unit] = this.__addAxis({ axisGenerated: true });
1030
- } else if (unit && !yAxes[unit]) {
1031
- yAxes[unit] = this.__addAxis({ id: unit, title: { text: unit }, axisGenerated: true });
1032
- }
1033
- if (isFinite(valueMin)) {
1034
- this.__setYAxisProps(yAxes, unit, { min: valueMin });
1035
- }
1036
- if (isFinite(valueMax)) {
1037
- this.__setYAxisProps(yAxes, unit, { max: valueMax });
1038
- }
1039
-
1040
- const seriesConfiguration = this.__updateOrAddSeriesInstance(seriesElement.options, idxOnChildList, false);
1041
-
1042
- seriesElement.setSeries(seriesConfiguration);
1043
- }
1044
- this.__removeAxisIfEmpty();
1045
-
1046
- this.configuration.redraw();
1047
- }
1048
-
1049
- /** @private */
1050
- __removeSeries(seriesNodes) {
1051
- if (this.__isSeriesEmpty(seriesNodes)) {
1052
- return;
1053
- }
1054
-
1055
- seriesNodes.forEach((series) => {
1056
- if (series instanceof ChartSeries) {
1057
- series._series.remove();
1058
- }
1059
- });
1060
- }
1061
-
1062
- /** @private */
1063
- __setYAxisProps(yAxes, yAxisId, props) {
1064
- if (yAxisId) {
1065
- yAxes[yAxisId].update(props);
1066
- } else {
1067
- this.configuration.yAxis[0].update(props);
1068
- }
1069
- }
1070
-
1071
- /** @private */
1072
- __isSeriesEmpty(series) {
1073
- return series === null || series.length === 0;
1074
- }
1075
-
1076
- /** @private */
1077
- __cleanupAfterSeriesRemoved(series) {
1078
- if (this.__isSeriesEmpty(series)) {
1079
- return;
1080
- }
1081
-
1082
- this.__removeAxisIfEmpty();
1083
-
1084
- // Best effort to make chart display custom empty-text messages when series are removed.
1085
- // This is needed because Highcharts currently doesn't react. A condition not catered for is
1086
- // when all points are removed from all series without removing any series.
1087
- this.__updateNoDataElement(this.configuration);
1088
- }
1089
-
1090
- /** @private */
1091
- __initChart(options) {
1092
- this.__initEventsListeners(options);
1093
- this.__updateStyledMode(options);
1094
- if (options.chart.type === 'gantt') {
1095
- this.configuration = Highcharts.ganttChart(this.$.chart, options);
1096
- } else if (this.timeline) {
1097
- this.configuration = Highcharts.stockChart(this.$.chart, options);
1098
- } else {
1099
- this.configuration = Highcharts.chart(this.$.chart, options);
1100
- }
1101
- }
1102
-
1103
- /** @private */
1104
- __updateStyledMode(options) {
1105
- const styledMode = options.chart.styledMode;
1106
- this.$.chart.toggleAttribute('styled-mode', !!styledMode);
1107
- }
1108
-
1109
- /** @protected */
1110
- disconnectedCallback() {
1111
- super.disconnectedCallback();
1112
-
1113
- if (this.configuration) {
1114
- this._jsonConfigurationBuffer = this.configuration.userOptions;
1115
- }
1116
-
1117
- queueMicrotask(() => {
1118
- if (this.isConnected) {
1119
- return;
1120
- }
1121
-
1122
- if (this.configuration) {
1123
- this.configuration.destroy();
1124
- this.configuration = undefined;
1125
-
1126
- // Reset series objects to avoid errors while detached
1127
- const seriesNodes = Array.from(this.childNodes).filter(this.__filterSeriesNodes);
1128
- seriesNodes.forEach((series) => {
1129
- series.setSeries(null);
1130
- });
1131
- }
1132
-
1133
- if (this._childObserver) {
1134
- this._childObserver.disconnect();
1135
- }
1136
- });
1137
- }
1138
-
1139
- /** @private */
1140
- __resetChart() {
1141
- const initialOptions = { ...this.options, ...this._jsonConfigurationBuffer };
1142
- this.__initChart(initialOptions);
1143
- this._jsonConfigurationBuffer = null;
1144
- }
1145
-
1146
- /**
1147
- * Search for axis with given `id`.
1148
- *
1149
- * @param {string} id contains the id that will be searched
1150
- * @param {boolean} isXAxis indicates if it will remove x or y axes. Defaults to `false`.
1151
- * @return {Axis}
1152
- * @protected
1153
- */
1154
- __getAxis(id, isXAxis) {
1155
- id = Number.parseInt(id) || id;
1156
- if (this.configuration) {
1157
- return (isXAxis ? this.configuration.xAxis : this.configuration.yAxis).find((axis) => axis.options.id === id);
1158
- }
1159
- }
1160
-
1161
- /**
1162
- * Add an axis with given options
1163
- *
1164
- * @param {Object} options axis options
1165
- * @param {boolean} isXAxis indicates if axis is X (`true`) or Y (`false`). Defaults to `false`.
1166
- * @return {!Axis}
1167
- * @protected
1168
- */
1169
- __addAxis(options, isXAxis) {
1170
- if (this.configuration) {
1171
- this.__createEventListeners(isXAxis ? this.__xAxesEventNames : this.__yAxesEventNames, options, 'events', 'axis');
1172
- return this.configuration.addAxis(options, isXAxis);
1173
- }
1174
- }
1175
-
1176
- /**
1177
- * Iterates over axes (y or x) and removes whenever it doesn't contain any series and was created for unit
1178
- *
1179
- * @param {boolean} isXAxis indicates if it will remove x or y axes. Defaults to `false`.
1180
- * @protected
1181
- */
1182
- __removeAxisIfEmpty(isXAxis) {
1183
- if (this.configuration) {
1184
- (isXAxis ? this.configuration.xAxis : this.configuration.yAxis).forEach((axis) => {
1185
- if (axis.userOptions.axisGenerated && axis.series.length === 0) {
1186
- axis.remove();
1187
- }
1188
- });
1189
- }
1190
- }
1191
-
1192
- /**
1193
- * Update the chart configuration.
1194
- * This JSON API provides a simple single-argument alternative to the configuration property.
1195
- *
1196
- * Styling properties specified in this configuration will be ignored. To learn about chart styling
1197
- * please see the CSS Styling section above.
1198
- *
1199
- * @param {!Options} jsonConfiguration Object chart configuration. Most important properties are:
1200
- *
1201
- * - annotations `Object[]` custom labels or shapes that can be tied to points, axis coordinates or chart pixel coordinates.
1202
- * Detailed API for annotations object is available in [API Site](http://api.highcharts.com/highcharts/annotations)
1203
- * - chart `Object` with options regarding the chart area and plot area as well as general chart options.
1204
- * Detailed API for chart object is available in [API Site](http://api.highcharts.com/highcharts/chart)
1205
- * - credits `Object` with options regarding the chart area and plot area as well as general chart options.
1206
- * Detailed API for credits object is available in [API Site](http://api.highcharts.com/highcharts/credits)
1207
- * - plotOptions `Object` wrapper for config objects for each series type.
1208
- * Detailed API for plotOptions object is available in [API Site](http://api.highcharts.com/highcharts/plotOptions)
1209
- * - series `Object[]` the actual series to append to the chart.
1210
- * Detailed API for series object is available in [API Site](http://api.highcharts.com/highcharts/series)
1211
- * - subtitle `Object` the chart's subtitle.
1212
- * Detailed API for subtitle object is available in [API Site](http://api.highcharts.com/highcharts/subtitle)
1213
- * - title `Object` the chart's main title.
1214
- * Detailed API for title object is available in [API Site](http://api.highcharts.com/highcharts/title)
1215
- * - tooltip `Object` Options for the tooltip that appears when the user hovers over a series or point.
1216
- * Detailed API for tooltip object is available in [API Site](http://api.highcharts.com/highcharts/tooltip)
1217
- * - xAxis `Object[]` The X axis or category axis. Normally this is the horizontal axis.
1218
- * Detailed API for xAxis object is available in [API Site](http://api.highcharts.com/highcharts/xAxis)
1219
- * - yAxis `Object[]` The Y axis or value axis. Normally this is the vertical axis.
1220
- * Detailed API for yAxis object is available in [API Site](http://api.highcharts.com/highcharts/yAxis)
1221
- * - zAxis `Object[]` The Z axis or depth axis for 3D plots.
1222
- * Detailed API for zAxis object is available in [API Site](http://api.highcharts.com/highcharts/zAxis)
1223
- *
1224
- * @param {boolean=} resetConfiguration Optional boolean that should be set to true if no other chart configuration was set before or
1225
- * if existing configuration should be discarded.
1226
- */
1227
- updateConfiguration(jsonConfiguration, resetConfiguration) {
1228
- if (resetConfiguration || !this._jsonConfigurationBuffer) {
1229
- this._jsonConfigurationBuffer = {};
1230
- }
1231
-
1232
- const configCopy = deepMerge({}, jsonConfiguration);
1233
- inflateFunctions(configCopy);
1234
- this._jsonConfigurationBuffer = this.__makeConfigurationBuffer(this._jsonConfigurationBuffer, configCopy);
1235
-
1236
- beforeNextRender(this, () => {
1237
- if (!this.configuration || !this._jsonConfigurationBuffer) {
1238
- return;
1239
- }
1240
-
1241
- if (resetConfiguration) {
1242
- this.__resetChart();
1243
- return;
1244
- }
1245
-
1246
- this.configuration.update(this._jsonConfigurationBuffer, false);
1247
- if (this._jsonConfigurationBuffer.credits) {
1248
- this.__updateOrAddCredits(this._jsonConfigurationBuffer.credits);
1249
- }
1250
- if (this._jsonConfigurationBuffer.xAxis) {
1251
- this.__updateOrAddAxes(this._jsonConfigurationBuffer.xAxis, true, false);
1252
- }
1253
- if (this._jsonConfigurationBuffer.yAxis) {
1254
- this.__updateOrAddAxes(this._jsonConfigurationBuffer.yAxis, false, false);
1255
- }
1256
- if (this._jsonConfigurationBuffer.series) {
1257
- this.__updateOrAddSeries(this._jsonConfigurationBuffer.series, false);
1258
- }
1259
- this._jsonConfigurationBuffer = null;
1260
-
1261
- this.configuration.redraw();
1262
- });
1263
- }
1264
-
1265
- /** @private */
1266
- __makeConfigurationBuffer(target, source) {
1267
- const _source = Highcharts.merge(source);
1268
- const _target = Highcharts.merge(target);
1269
-
1270
- this.__mergeConfigurationArray(_target, _source, 'series');
1271
- this.__mergeConfigurationArray(_target, _source, 'xAxis');
1272
- this.__mergeConfigurationArray(_target, _source, 'yAxis');
1273
-
1274
- return Highcharts.merge(_target, _source);
1275
- }
1276
-
1277
- /** @private */
1278
- __mergeConfigurationArray(target, configuration, entry) {
1279
- if (!configuration || !configuration[entry] || !Array.isArray(configuration[entry])) {
1280
- return;
1281
- }
1282
-
1283
- if (!target[entry]) {
1284
- target[entry] = Array.from(configuration[entry]);
1285
- return;
1286
- }
1287
-
1288
- const maxLength = Math.max(target[entry].length, configuration[entry].length);
1289
- for (let i = 0; i < maxLength; i++) {
1290
- target[entry][i] = Highcharts.merge(target[entry][i], configuration[entry][i]);
1291
- }
1292
- delete configuration[entry];
1293
- }
1294
-
1295
- /** @private */
1296
- __initEventsListeners(configuration) {
1297
- this.__initChartEventsListeners(configuration);
1298
- this.__initSeriesEventsListeners(configuration);
1299
- this.__initPointsEventsListeners(configuration);
1300
- this.__initAxisEventsListeners(configuration, true);
1301
- this.__initAxisEventsListeners(configuration, false);
1302
- }
1303
-
1304
- /** @private */
1305
- __initChartEventsListeners(configuration) {
1306
- this.__createEventListeners(this.__chartEventNames, configuration, 'chart.events', 'chart');
1307
- }
1308
-
1309
- /** @private */
1310
- __initSeriesEventsListeners(configuration) {
1311
- this.__createEventListeners(this.__seriesEventNames, configuration, 'plotOptions.series.events', 'series');
1312
- }
1313
-
1314
- /** @private */
1315
- __initPointsEventsListeners(configuration) {
1316
- this.__createEventListeners(this.__pointEventNames, configuration, 'plotOptions.series.point.events', 'point');
1317
- }
1318
-
1319
- /** @private */
1320
- __initAxisEventsListeners(configuration, isXAxis) {
1321
- let eventNames, axes;
1322
-
1323
- if (isXAxis) {
1324
- eventNames = this.__xAxesEventNames;
1325
- axes = configuration.xAxis;
1326
- } else {
1327
- eventNames = this.__yAxesEventNames;
1328
- axes = configuration.yAxis;
1329
- }
1330
-
1331
- if (Array.isArray(axes)) {
1332
- axes.forEach((axis) => this.__createEventListeners(eventNames, axis, 'events', 'axis'));
1333
- } else {
1334
- this.__createEventListeners(eventNames, axes, 'events', 'axis');
1335
- }
1336
- }
1337
-
1338
- /** @private */
1339
- __createEventListeners(eventList, configuration, pathToAdd, eventType) {
1340
- const eventObject = this.__ensureObjectPath(configuration, pathToAdd);
1341
- const self = this;
1342
-
1343
- for (let keys = Object.keys(eventList), i = 0; i < keys.length; i++) {
1344
- const key = keys[i];
1345
- if (!eventObject[key]) {
1346
- eventObject[key] = function (event) {
1347
- const customEvent = {
1348
- bubbles: false,
1349
- composed: true,
1350
- detail: {
1351
- originalEvent: event,
1352
- [eventType]: event.target,
1353
- },
1354
- };
1355
-
1356
- if (key === 'dragStart') {
1357
- // for dragStart there is no information about point in the
1358
- // event object. However, 'this' references the point being dragged
1359
- customEvent.detail[eventType] = this;
1360
- }
1361
-
1362
- if (event.type === 'afterSetExtremes') {
1363
- if (event.min == null || event.max == null) {
1364
- return;
1365
- }
1366
- }
1367
-
1368
- // Workaround for vaadin-charts-flow because of https://github.com/vaadin/flow/issues/3102
1369
- if (event.type === 'selection') {
1370
- if (event.xAxis && event.xAxis[0]) {
1371
- customEvent.detail.xAxisMin = event.xAxis[0].min;
1372
- customEvent.detail.xAxisMax = event.xAxis[0].max;
1373
- }
1374
- if (event.yAxis && event.yAxis[0]) {
1375
- customEvent.detail.yAxisMin = event.yAxis[0].min;
1376
- customEvent.detail.yAxisMax = event.yAxis[0].max;
1377
- }
1378
- }
1379
- if (event.type === 'click') {
1380
- if (event.xAxis && event.xAxis[0]) {
1381
- customEvent.detail.xValue = event.xAxis[0].value;
1382
- }
1383
- if (event.yAxis && event.yAxis[0]) {
1384
- customEvent.detail.yValue = event.yAxis[0].value;
1385
- }
1386
- }
1387
-
1388
- // Workaround for https://github.com/vaadin/vaadin-charts/issues/389
1389
- // Hook into beforePrint and beforeExport to ensure correct styling
1390
- if (['beforePrint', 'beforeExport'].indexOf(event.type) >= 0) {
1391
- // Guard against another print 'before print' event coming before
1392
- // the 'after print' event.
1393
- if (!self.tempBodyStyle) {
1394
- let effectiveCss = '';
1395
-
1396
- [...self.shadowRoot.querySelectorAll('style')].forEach((style) => {
1397
- effectiveCss += style.textContent;
1398
- });
1399
-
1400
- // Strip off host selectors that target individual instances
1401
- effectiveCss = effectiveCss.replace(/:host\(.+?\)/gu, (match) => {
1402
- const selector = match.substr(6, match.length - 7);
1403
- return self.matches(selector) ? '' : match;
1404
- });
1405
-
1406
- // Zoom out a bit to avoid clipping the chart's edge on paper
1407
- effectiveCss =
1408
- `${effectiveCss}body {` +
1409
- ` -moz-transform: scale(0.9, 0.9);` + // Mozilla
1410
- ` zoom: 0.9;` + // Others
1411
- ` zoom: 90%;` + // Webkit
1412
- `}`;
1413
-
1414
- self.tempBodyStyle = document.createElement('style');
1415
- self.tempBodyStyle.textContent = effectiveCss;
1416
- document.body.appendChild(self.tempBodyStyle);
1417
- if (self.options.chart.styledMode) {
1418
- document.body.setAttribute('styled-mode', '');
1419
- }
1420
- }
1421
- }
1422
-
1423
- // Hook into afterPrint and afterExport to revert changes made before
1424
- if (['afterPrint', 'afterExport'].indexOf(event.type) >= 0) {
1425
- if (self.tempBodyStyle) {
1426
- document.body.removeChild(self.tempBodyStyle);
1427
- delete self.tempBodyStyle;
1428
- if (self.options.chart.styledMode) {
1429
- document.body.removeAttribute('styled-mode');
1430
- }
1431
- }
1432
- }
1433
-
1434
- self.dispatchEvent(new CustomEvent(eventList[key], customEvent));
1435
-
1436
- if (event.type === 'legendItemClick' && self._visibilityTogglingDisabled) {
1437
- return false;
1438
- }
1439
- };
1440
- }
1441
- }
1442
- }
1443
-
1444
- /** @private */
1445
- __ensureObjectPath(object, path) {
1446
- if (typeof path !== 'string') {
1447
- return;
1448
- }
1449
-
1450
- path = path.split('.');
1451
- return path.reduce((obj, key) => {
1452
- if (!obj[key]) {
1453
- obj[key] = {};
1454
- }
1455
- return obj[key];
1456
- }, object);
1457
- }
1458
-
1459
- /** @private */
1460
- __hasConfigurationBuffer(path) {
1461
- return get(path, this._jsonConfigurationBuffer) !== undefined;
1462
- }
1463
-
1464
- /** @private */
1465
- __updateOrAddCredits(credits) {
1466
- if (this.configuration.credits) {
1467
- this.configuration.credits.update(credits);
1468
- } else {
1469
- this.configuration.addCredits(credits);
1470
- }
1471
- }
1472
-
1473
- /** @private */
1474
- __updateOrAddAxes(axes, isX, redraw) {
1475
- if (!Array.isArray(axes)) {
1476
- axes = [axes];
1477
- }
1478
- const confAxes = isX ? this.configuration.xAxis : this.configuration.yAxis;
1479
- for (let i = 0; i < axes.length; i++) {
1480
- const axis = axes[i];
1481
- if (confAxes[i]) {
1482
- confAxes[i].update(axis, redraw);
1483
- } else {
1484
- this.configuration.addAxis(axis, isX, redraw);
1485
- }
1486
- }
1487
- }
1488
-
1489
- /** @private */
1490
- __updateOrAddSeries(series, redraw) {
1491
- if (!Array.isArray(series)) {
1492
- throw new Error('The type of jsonConfiguration.series should be Object[]');
1493
- }
1494
- for (let i = 0; i < series.length; i++) {
1495
- const currentSeries = series[i];
1496
- this.__updateOrAddSeriesInstance(currentSeries, i, redraw);
1497
- }
1498
- }
1499
-
1500
- /** @private */
1501
- __updateOrAddSeriesInstance(seriesOptions, position, redraw) {
1502
- if (this.configuration.series[position]) {
1503
- this.configuration.series[position].update(seriesOptions, redraw);
1504
- } else {
1505
- this.configuration.addSeries(seriesOptions, redraw);
1506
- }
1507
- return this.configuration.series[position];
1508
- }
1509
-
1510
- /** @private */
1511
- __updateCategories(categories, config) {
1512
- if (categories === undefined || !config || this.__hasConfigurationBuffer('xAxis.categories')) {
1513
- return;
1514
- }
1515
-
1516
- this.__updateOrAddAxes([{ categories }], true);
1517
- }
1518
-
1519
- /** @private */
1520
- __updateCategoryMax(max, config) {
1521
- if (max === undefined || !config || this.__hasConfigurationBuffer('xAxis.max')) {
1522
- return;
1523
- }
1524
-
1525
- if (!isFinite(max)) {
1526
- console.warn('<vaadin-chart> Acceptable value for "category-max" are Numbers or null');
1527
- return;
1528
- }
1529
-
1530
- this.__updateOrAddAxes([{ max }], true);
1531
- }
1532
-
1533
- /** @private */
1534
- __updateCategoryMin(min, config) {
1535
- if (min === undefined || !config || this.__hasConfigurationBuffer('xAxis.min')) {
1536
- return;
1537
- }
1538
-
1539
- if (!isFinite(min)) {
1540
- console.warn('<vaadin-chart> Acceptable value for "category-min" are Numbers or null');
1541
- return;
1542
- }
1543
-
1544
- this.__updateOrAddAxes([{ min }], true);
1545
- }
1546
-
1547
- /** @private */
1548
- __shouldInvert() {
1549
- // A bar chart will never be inverted, consider using a column chart.
1550
- // See https://stackoverflow.com/questions/11235251#answer-21739793
1551
- if (this.type === 'bar' && ['top', 'bottom'].indexOf(this.categoryPosition) >= 0) {
1552
- console.warn(`<vaadin-chart> Acceptable "category-position" values for bar charts are
1553
- "left" and "right". For "top" and "bottom" positions please consider using a column chart.`);
1554
- return;
1555
- }
1556
-
1557
- const inverted = ['left', 'right'];
1558
- return inverted.indexOf(this.categoryPosition) >= 0;
1559
- }
1560
-
1561
- /** @private */
1562
- __shouldFlipOpposite() {
1563
- const opposite = ['top', 'right'];
1564
- const oppositeBar = ['right'];
1565
- return (this.type === 'bar' ? oppositeBar : opposite).indexOf(this.categoryPosition) >= 0;
1566
- }
1567
-
1568
- /** @private */
1569
- __updateCategoryPosition(categoryPosition, config) {
1570
- if (categoryPosition === undefined || !config || this.__hasConfigurationBuffer('chart.inverted')) {
1571
- return;
1572
- }
1573
-
1574
- const validPositions = ['left', 'right', 'top', 'bottom'];
1575
-
1576
- if (validPositions.indexOf(categoryPosition) < 0) {
1577
- console.warn(`<vaadin-chart> Acceptable "category-position" values are ${validPositions}`);
1578
- return;
1579
- }
1580
-
1581
- config.update({
1582
- chart: {
1583
- inverted: this.__shouldInvert(),
1584
- },
1585
- });
1586
-
1587
- config.xAxis.forEach((e) =>
1588
- e.update({
1589
- opposite: this.__shouldFlipOpposite(),
1590
- }),
1591
- );
1592
- }
1593
-
1594
- /** @private */
1595
- __hideLegend(noLegend, config) {
1596
- if (noLegend === undefined || !config || this.__hasConfigurationBuffer('legend')) {
1597
- return;
1598
- }
1599
-
1600
- if (config.legend) {
1601
- config.legend.update({ enabled: !noLegend });
1602
- } else {
1603
- config.legend = { enabled: !noLegend };
1604
- }
1605
- }
1606
-
1607
- /** @private */
1608
- __updateTitle(title, config) {
1609
- if (title === undefined || !config || this.__hasConfigurationBuffer('title')) {
1610
- return;
1611
- }
1612
-
1613
- config.title.update({ text: title });
1614
- }
1615
-
1616
- /** @private */
1617
- __tooltipObserver(tooltip, config) {
1618
- if (tooltip === undefined || !config || this.__hasConfigurationBuffer('tooltip')) {
1619
- return;
1620
- }
1621
-
1622
- config.tooltip.update({ enabled: tooltip });
1623
- }
1624
-
1625
- /** @private */
1626
- __updateType(type, config) {
1627
- if (type === undefined || !config || this.__hasConfigurationBuffer('chart.type')) {
1628
- return;
1629
- }
1630
-
1631
- config.update({
1632
- chart: { type: type || 'line' },
1633
- });
1634
- }
1635
-
1636
- /** @private */
1637
- __updateSubtitle(subtitle, config) {
1638
- if (subtitle === undefined || !config || this.__hasConfigurationBuffer('subtitle')) {
1639
- return;
1640
- }
1641
-
1642
- if (!config.subtitle) {
1643
- config.setSubtitle({ text: subtitle });
1644
- } else {
1645
- config.subtitle.update({ text: subtitle });
1646
- }
1647
- }
1648
-
1649
- /** @private */
1650
- __updateAdditionalOptions(options) {
1651
- if (this.configuration && options.base) {
1652
- this.updateConfiguration(options.base);
1653
- }
1654
- }
1655
-
1656
- /** @private */
1657
- __isStackingValid() {
1658
- if (['normal', 'percent', null].indexOf(this.stacking) === -1) {
1659
- this.__showWarn('stacking', '"normal", "percent" or null');
1660
- return false;
1661
- }
1662
- return true;
1663
- }
1664
-
1665
- /** @private */
1666
- __stackingObserver(stacking, config) {
1667
- if (stacking === undefined || !config || this.__hasConfigurationBuffer('plotOptions.series.stacking')) {
1668
- return;
1669
- }
1670
-
1671
- if (!this.__isStackingValid()) {
1672
- this.stacking = null;
1673
- return;
1674
- }
1675
-
1676
- config.update({
1677
- plotOptions: {
1678
- series: { stacking },
1679
- },
1680
- });
1681
- }
1682
-
1683
- /** @private */
1684
- __chart3dObserver(chart3d, config) {
1685
- if (chart3d === undefined || !config || this.__hasConfigurationBuffer('chart.options3d')) {
1686
- return;
1687
- }
1688
-
1689
- if (chart3d) {
1690
- config.update({
1691
- chart: {
1692
- options3d: {
1693
- ...this._baseChart3d,
1694
- ...(this.additionalOptions && this.additionalOptions.chart && this.additionalOptions.chart.options3d),
1695
- enabled: true,
1696
- },
1697
- },
1698
- });
1699
- } else {
1700
- config.update({
1701
- chart: {
1702
- options3d: {
1703
- enabled: false,
1704
- },
1705
- },
1706
- });
1707
- }
1708
- }
1709
-
1710
- /** @private */
1711
- __polarObserver(polar, config) {
1712
- if (polar === undefined || !config || this.__hasConfigurationBuffer('chart.polar')) {
1713
- return;
1714
- }
1715
-
1716
- config.update({
1717
- chart: { polar },
1718
- });
1719
- }
1720
-
1721
- /** @private */
1722
- __emptyTextObserver(emptyText, config) {
1723
- if (emptyText === undefined || !config || this.__hasConfigurationBuffer('lang.noData')) {
1724
- return;
1725
- }
1726
-
1727
- config.update({
1728
- lang: {
1729
- noData: emptyText,
1730
- },
1731
- });
1732
- this.__updateNoDataElement(config);
1733
- }
1734
-
1735
- /**
1736
- * Force the no data text element to become visible if the chart has no data.
1737
- * This is necessary in cases where Highcharts does not update the element
1738
- * automatically, for example when setting the language config
1739
- * @private
1740
- */
1741
- __updateNoDataElement(config) {
1742
- const isEmpty = config.series.every((e) => e.data.length === 0);
1743
- if (isEmpty) {
1744
- config.hideNoData();
1745
- config.showNoData(this.emptyText);
1746
- }
1747
- }
1748
-
1749
- /** @private */
1750
- __callChartFunction(functionName, ...args) {
1751
- if (this.configuration) {
1752
- const functionToCall = this.configuration[functionName];
1753
- if (functionToCall && typeof functionToCall === 'function') {
1754
- args.forEach((arg) => inflateFunctions(arg));
1755
- functionToCall.apply(this.configuration, args);
1756
- }
1757
- }
1758
- }
1759
-
1760
- /** @private */
1761
- __callSeriesFunction(functionName, seriesIndex, ...args) {
1762
- if (this.configuration && this.configuration.series[seriesIndex]) {
1763
- const series = this.configuration.series[seriesIndex];
1764
- const functionToCall = series[functionName];
1765
- if (functionToCall && typeof functionToCall === 'function') {
1766
- args.forEach((arg) => inflateFunctions(arg));
1767
- functionToCall.apply(series, args);
1768
- }
1769
- }
1770
- }
1771
-
1772
- /** @private */
1773
- __callAxisFunction(functionName, axisCategory, axisIndex, ...args) {
1774
- /*
1775
- * AxisCategory:
1776
- * 0 - xAxis
1777
- * 1 - yAxis
1778
- * 2 - zAxis
1779
- * 3 - colorAxis
1780
- */
1781
- if (this.configuration) {
1782
- let axes;
1783
- switch (axisCategory) {
1784
- case 0:
1785
- axes = this.configuration.xAxis;
1786
- break;
1787
- case 1:
1788
- axes = this.configuration.yAxis;
1789
- break;
1790
- case 2:
1791
- axes = this.configuration.zAxis;
1792
- break;
1793
- case 3:
1794
- axes = this.configuration.colorAxis;
1795
- break;
1796
- default:
1797
- break;
1798
- }
1799
- if (axes && axes[axisIndex]) {
1800
- const axis = axes[axisIndex];
1801
- const functionToCall = axis[functionName];
1802
- if (functionToCall && typeof functionToCall === 'function') {
1803
- args.forEach((arg) => inflateFunctions(arg));
1804
- functionToCall.apply(axis, args);
1805
- }
1806
- }
1807
- }
1808
- }
1809
-
1810
- /** @private */
1811
- __callPointFunction(functionName, seriesIndex, pointIndex, ...args) {
1812
- if (
1813
- this.configuration &&
1814
- this.configuration.series[seriesIndex] &&
1815
- this.configuration.series[seriesIndex].data[pointIndex]
1816
- ) {
1817
- const point = this.configuration.series[seriesIndex].data[pointIndex];
1818
- const functionToCall = point[functionName];
1819
- if (functionToCall && typeof functionToCall === 'function') {
1820
- functionToCall.apply(point, args);
1821
- }
1822
- }
1823
- }
1824
-
1825
- /**
1826
- * Updates chart container and current chart style property depending on flex status
1827
- * @private
1828
- */
1829
- __updateStyles() {
1830
- // Chrome returns default value if property is not set
1831
- // check if flex is defined for chart, and different than default value
1832
- const isFlex = getComputedStyle(this).flex !== '0 1 auto';
1833
-
1834
- // If chart element is a flexible item the chartContainer should be flex too
1835
- if (isFlex) {
1836
- this.$.chart.setAttribute('style', 'flex: 1; ');
1837
- let style = '';
1838
- if (this.hasAttribute('style')) {
1839
- style = this.getAttribute('style');
1840
- if (!style.endsWith(';')) {
1841
- style += ';';
1842
- }
1843
- }
1844
- style += 'display: flex;';
1845
- this.setAttribute('style', style);
1846
- } else {
1847
- this.$.chart.setAttribute('style', 'height:100%; width:100%;');
1848
- }
1849
- }
1850
-
1851
- /** @private */
1852
- __showWarn(propertyName, acceptedValues) {
1853
- console.warn(`<vaadin-chart> Acceptable values for "${propertyName}" are ${acceptedValues}`);
1854
- }
1855
-
1856
- /** @private */
1857
- __onRedraw() {
1858
- this.__checkTurboMode();
1859
- }
1860
-
1861
- /** @private */
1862
- __checkTurboMode() {
1863
- const isDevelopmentMode = !!window.Vaadin.developmentMode;
1864
-
1865
- if (!this.configuration || !isDevelopmentMode || this.__turboModeWarningAlreadyLogged) {
1866
- return;
1867
- }
1868
-
1869
- const exceedsTurboThreshold = this.configuration.series.some((series) => {
1870
- const threshold = (series.options && series.options.turboThreshold) || 0;
1871
- const dataLength = series.data.length;
1872
-
1873
- return threshold > 0 && dataLength > threshold;
1874
- });
1875
-
1876
- if (exceedsTurboThreshold) {
1877
- this.__turboModeWarningAlreadyLogged = true;
1878
- console.warn(
1879
- '<vaadin-chart> Turbo mode has been enabled for one or more series, because the number of data items exceeds the configured threshold. Turbo mode improves the performance of charts with lots of data, but is not compatible with every type of series. Please consult the documentation on compatibility, or how to disable turbo mode.',
1880
- );
1881
- }
1882
- }
1883
208
  }
1884
209
 
1885
210
  defineCustomElement(Chart);