@vaadin/charts 24.7.0-alpha1 → 24.7.0-alpha10

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