From 8bd2dd462e031c1f299f2dbfb60a7d6be8d0b88c Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Thu, 22 Feb 2024 10:49:16 +0100 Subject: [PATCH] spostamento bootstrap lib --- .../wwwroot/images/EgalwareLogo.svg | 1 + .../wwwroot/images/LogoEgw.png | Bin 0 -> 3051 bytes .../wwwroot/images/LogoMapoFull.png | Bin 0 -> 157981 bytes .../wwwroot/images/LogoSteamware.png | Bin 0 -> 87309 bytes .../wwwroot/images/favicon.ico | Bin 0 -> 31702 bytes .../wwwroot/images/favicon.png | Bin 0 -> 87309 bytes .../wwwroot/images/linuxLogo.png | Bin 0 -> 23552 bytes .../wwwroot/images/winLogo.png | Bin 0 -> 11471 bytes .../wwwroot/lib/Chart.js/chart.js | 23528 +++++++--------- .../wwwroot/lib/Chart.js/chart.min.js | 14 +- .../wwwroot/lib/Chart.js/helpers.js | 9 + .../wwwroot/lib/Chart.js/helpers.min.js | 1 + .../bootstrap/css/bootstrap-grid.css | 0 .../bootstrap/css/bootstrap-grid.css.map | 0 .../bootstrap/css/bootstrap-grid.min.css | 0 .../bootstrap/css/bootstrap-grid.min.css.map | 0 .../bootstrap/css/bootstrap-grid.rtl.css | 0 .../bootstrap/css/bootstrap-grid.rtl.css.map | 0 .../bootstrap/css/bootstrap-grid.rtl.min.css | 0 .../css/bootstrap-grid.rtl.min.css.map | 0 .../bootstrap/css/bootstrap-reboot.css | 0 .../bootstrap/css/bootstrap-reboot.css.map | 0 .../bootstrap/css/bootstrap-reboot.min.css | 0 .../css/bootstrap-reboot.min.css.map | 0 .../bootstrap/css/bootstrap-reboot.rtl.css | 0 .../css/bootstrap-reboot.rtl.css.map | 0 .../css/bootstrap-reboot.rtl.min.css | 0 .../css/bootstrap-reboot.rtl.min.css.map | 0 .../bootstrap/css/bootstrap-utilities.css | 0 .../bootstrap/css/bootstrap-utilities.css.map | 0 .../bootstrap/css/bootstrap-utilities.min.css | 0 .../css/bootstrap-utilities.min.css.map | 0 .../bootstrap/css/bootstrap-utilities.rtl.css | 0 .../css/bootstrap-utilities.rtl.css.map | 0 .../css/bootstrap-utilities.rtl.min.css | 0 .../css/bootstrap-utilities.rtl.min.css.map | 0 .../lib/{css => }/bootstrap/css/bootstrap.css | 0 .../{css => }/bootstrap/css/bootstrap.css.map | 0 .../{css => }/bootstrap/css/bootstrap.min.css | 0 .../bootstrap/css/bootstrap.min.css.map | 0 .../{css => }/bootstrap/css/bootstrap.rtl.css | 0 .../bootstrap/css/bootstrap.rtl.css.map | 0 .../bootstrap/css/bootstrap.rtl.min.css | 0 .../bootstrap/css/bootstrap.rtl.min.css.map | 0 .../bootstrap/js/bootstrap.bundle.js | 0 .../bootstrap/js/bootstrap.bundle.js.map | 0 .../bootstrap/js/bootstrap.bundle.min.js | 0 .../bootstrap/js/bootstrap.bundle.min.js.map | 0 .../{css => }/bootstrap/js/bootstrap.esm.js | 0 .../bootstrap/js/bootstrap.esm.js.map | 0 .../bootstrap/js/bootstrap.esm.min.js | 0 .../bootstrap/js/bootstrap.esm.min.js.map | 0 .../lib/{css => }/bootstrap/js/bootstrap.js | 0 .../{css => }/bootstrap/js/bootstrap.js.map | 0 .../{css => }/bootstrap/js/bootstrap.min.js | 0 .../bootstrap/js/bootstrap.min.js.map | 0 .../{css => }/bootstrap/scss/_accordion.scss | 0 .../lib/{css => }/bootstrap/scss/_alert.scss | 0 .../lib/{css => }/bootstrap/scss/_badge.scss | 0 .../{css => }/bootstrap/scss/_breadcrumb.scss | 0 .../bootstrap/scss/_button-group.scss | 0 .../{css => }/bootstrap/scss/_buttons.scss | 0 .../lib/{css => }/bootstrap/scss/_card.scss | 0 .../{css => }/bootstrap/scss/_carousel.scss | 0 .../lib/{css => }/bootstrap/scss/_close.scss | 0 .../{css => }/bootstrap/scss/_containers.scss | 0 .../{css => }/bootstrap/scss/_dropdown.scss | 0 .../lib/{css => }/bootstrap/scss/_forms.scss | 0 .../{css => }/bootstrap/scss/_functions.scss | 0 .../lib/{css => }/bootstrap/scss/_grid.scss | 0 .../{css => }/bootstrap/scss/_helpers.scss | 0 .../lib/{css => }/bootstrap/scss/_images.scss | 0 .../{css => }/bootstrap/scss/_list-group.scss | 0 .../lib/{css => }/bootstrap/scss/_maps.scss | 0 .../lib/{css => }/bootstrap/scss/_mixins.scss | 0 .../lib/{css => }/bootstrap/scss/_modal.scss | 0 .../lib/{css => }/bootstrap/scss/_nav.scss | 0 .../lib/{css => }/bootstrap/scss/_navbar.scss | 0 .../{css => }/bootstrap/scss/_offcanvas.scss | 0 .../{css => }/bootstrap/scss/_pagination.scss | 0 .../bootstrap/scss/_placeholders.scss | 0 .../{css => }/bootstrap/scss/_popover.scss | 0 .../{css => }/bootstrap/scss/_progress.scss | 0 .../lib/{css => }/bootstrap/scss/_reboot.scss | 0 .../lib/{css => }/bootstrap/scss/_root.scss | 0 .../{css => }/bootstrap/scss/_spinners.scss | 0 .../lib/{css => }/bootstrap/scss/_tables.scss | 0 .../lib/{css => }/bootstrap/scss/_toasts.scss | 0 .../{css => }/bootstrap/scss/_tooltip.scss | 0 .../bootstrap/scss/_transitions.scss | 0 .../lib/{css => }/bootstrap/scss/_type.scss | 0 .../{css => }/bootstrap/scss/_utilities.scss | 0 .../{css => }/bootstrap/scss/_variables.scss | 0 .../bootstrap/scss/bootstrap-grid.scss | 0 .../bootstrap/scss/bootstrap-reboot.scss | 0 .../bootstrap/scss/bootstrap-utilities.scss | 0 .../{css => }/bootstrap/scss/bootstrap.scss | 0 .../scss/forms/_floating-labels.scss | 0 .../bootstrap/scss/forms/_form-check.scss | 0 .../bootstrap/scss/forms/_form-control.scss | 0 .../bootstrap/scss/forms/_form-range.scss | 0 .../bootstrap/scss/forms/_form-select.scss | 0 .../bootstrap/scss/forms/_form-text.scss | 0 .../bootstrap/scss/forms/_input-group.scss | 0 .../bootstrap/scss/forms/_labels.scss | 0 .../bootstrap/scss/forms/_validation.scss | 0 .../bootstrap/scss/helpers/_clearfix.scss | 0 .../bootstrap/scss/helpers/_color-bg.scss | 0 .../scss/helpers/_colored-links.scss | 0 .../bootstrap/scss/helpers/_position.scss | 0 .../bootstrap/scss/helpers/_ratio.scss | 0 .../bootstrap/scss/helpers/_stacks.scss | 0 .../scss/helpers/_stretched-link.scss | 0 .../scss/helpers/_text-truncation.scss | 0 .../scss/helpers/_visually-hidden.scss | 0 .../{css => }/bootstrap/scss/helpers/_vr.scss | 0 .../bootstrap/scss/mixins/_alert.scss | 0 .../bootstrap/scss/mixins/_backdrop.scss | 0 .../bootstrap/scss/mixins/_banner.scss | 0 .../bootstrap/scss/mixins/_border-radius.scss | 0 .../bootstrap/scss/mixins/_box-shadow.scss | 0 .../bootstrap/scss/mixins/_breakpoints.scss | 0 .../bootstrap/scss/mixins/_buttons.scss | 0 .../bootstrap/scss/mixins/_caret.scss | 0 .../bootstrap/scss/mixins/_clearfix.scss | 0 .../bootstrap/scss/mixins/_color-scheme.scss | 0 .../bootstrap/scss/mixins/_container.scss | 0 .../bootstrap/scss/mixins/_deprecate.scss | 0 .../bootstrap/scss/mixins/_forms.scss | 0 .../bootstrap/scss/mixins/_gradients.scss | 0 .../bootstrap/scss/mixins/_grid.scss | 0 .../bootstrap/scss/mixins/_image.scss | 0 .../bootstrap/scss/mixins/_list-group.scss | 0 .../bootstrap/scss/mixins/_lists.scss | 0 .../bootstrap/scss/mixins/_pagination.scss | 0 .../bootstrap/scss/mixins/_reset-text.scss | 0 .../bootstrap/scss/mixins/_resize.scss | 0 .../scss/mixins/_table-variants.scss | 0 .../bootstrap/scss/mixins/_text-truncate.scss | 0 .../bootstrap/scss/mixins/_transition.scss | 0 .../bootstrap/scss/mixins/_utilities.scss | 0 .../scss/mixins/_visually-hidden.scss | 0 .../bootstrap/scss/utilities/_api.scss | 0 .../{css => }/bootstrap/scss/vendor/_rfs.scss | 0 144 files changed, 10863 insertions(+), 12690 deletions(-) create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/EgalwareLogo.svg create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/LogoEgw.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/LogoMapoFull.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/LogoSteamware.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/favicon.ico create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/favicon.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/linuxLogo.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/images/winLogo.png create mode 100644 EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/helpers.js create mode 100644 EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/helpers.min.js rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.rtl.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.rtl.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.rtl.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-grid.rtl.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.rtl.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.rtl.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.rtl.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-reboot.rtl.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.rtl.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.rtl.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.rtl.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap-utilities.rtl.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.rtl.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.rtl.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.rtl.min.css (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/css/bootstrap.rtl.min.css.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.bundle.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.bundle.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.bundle.min.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.bundle.min.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.esm.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.esm.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.esm.min.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.esm.min.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.min.js (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/js/bootstrap.min.js.map (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_accordion.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_alert.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_badge.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_breadcrumb.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_button-group.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_buttons.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_card.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_carousel.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_close.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_containers.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_dropdown.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_forms.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_functions.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_grid.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_helpers.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_images.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_list-group.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_maps.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_mixins.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_modal.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_nav.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_navbar.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_offcanvas.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_pagination.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_placeholders.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_popover.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_progress.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_reboot.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_root.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_spinners.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_tables.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_toasts.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_tooltip.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_transitions.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_type.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_utilities.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/_variables.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/bootstrap-grid.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/bootstrap-reboot.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/bootstrap-utilities.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/bootstrap.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_floating-labels.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_form-check.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_form-control.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_form-range.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_form-select.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_form-text.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_input-group.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_labels.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/forms/_validation.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_clearfix.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_color-bg.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_colored-links.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_position.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_ratio.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_stacks.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_stretched-link.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_text-truncation.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_visually-hidden.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/helpers/_vr.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_alert.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_backdrop.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_banner.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_border-radius.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_box-shadow.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_breakpoints.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_buttons.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_caret.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_clearfix.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_color-scheme.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_container.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_deprecate.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_forms.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_gradients.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_grid.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_image.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_list-group.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_lists.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_pagination.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_reset-text.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_resize.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_table-variants.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_text-truncate.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_transition.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_utilities.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/mixins/_visually-hidden.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/utilities/_api.scss (100%) rename EgwCoreLib.BlazorTest/wwwroot/lib/{css => }/bootstrap/scss/vendor/_rfs.scss (100%) diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/EgalwareLogo.svg b/EgwCoreLib.BlazorTest/wwwroot/images/EgalwareLogo.svg new file mode 100644 index 0000000..0e67e74 --- /dev/null +++ b/EgwCoreLib.BlazorTest/wwwroot/images/EgalwareLogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/LogoEgw.png b/EgwCoreLib.BlazorTest/wwwroot/images/LogoEgw.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5a7c1fa3da8f7edbd0edfaa5b299fee87505ec GIT binary patch literal 3051 zcmds3YgAKL8jbZq0hOT&S|Xr8u}TBhLKG1gPy(!$hk&>wMZknm@Cp@>M0up*R79|Z zN0qk<6lE}oH*hI0k%AC`BvJ@)3E@q6n1n|vhygO^I{)VH{Fyab>zLJ0< zR8!9^(m4?Qn{aUQZ9(Hmqd@c;m3n6KUk{9xwN6yF35BCGH`xO{qYGSADw=wWbPO~I zM2YMHkz|Qk-hZW}7w(iiY8n+!D^fXwJh8mFcdqQ!#JyVaz~o~6o0;CR1;Nnd@QmWk z@O*3E+w!)FoVwwQ`Q2iPtfoucIXH*#rplVT2Pfx%cD<6IPrzgw?d9&R`Y%2>b&IC~ zAd&iyF6X0gxScK7v#CAe2^ELah;}{g;KR5e6VJj!i1w|Z^U3+guj~u)$a0EVjvpyj zHdWw!DF65-iF0LOZ=85u;eGam>4I^jbEfYo4RVwp`na-r9F} zFnsNV(=pb^AfCnOBIyFim>hujh3>PxV9e2!M}6m^M&B zGDmn;Ik;L?nt3cw#h}iE*dVm|7gGH2`kqjZ&`PsjEy(^)Eku4Ev+%0n-MWIlXgFBGTv@RJM4b{9s6u_|4i#NfF;B_o zH&VVw*V0G@Nq%nsgf?ni?t{*hbolnqcB}yLhcNM7H`y*(pu%3}6QN0m@449yB?ukN zQ+7X5g7&!)Rg2u)fcA?#RlSOZeIff7m2Y}%RbT>0&JaWbhe)czUQge$H!PA`t{FY` z0SMTQ4yBRW!3#M`1*L7rhgqq^t4&I+gi0NCxHiq11ayywM1f=0yNN9jvDUs0h z+DZUR=I6Z~nA<-z5hJMh<~0VqO1oaElLXm6w~g^+HvC>@0KGaO!iy+s@7gcrVftkn zijSv)U^TJ>(n+&s&$47iIk)_FpyqHvt_EtJGmVMTG(CYu8a}tfDpN>eF~+AThU4c< z?3&b}+E8GOn4kSuvoA|lrJe*r?zwX8u(t&GizUlC^l>j6+#=Rxaq43$eVEOW<>;Wk zyc4})T!dDEUA@b%N6pA)6zgkY&N7yV;*I?h=;x_025u_`v$axSeepn%E;%Q% zjB1np0YeTC0gLTJ?U?cUqO8>^E-mG*u@mxO@ZtoQb$R2)2Ja}9^BXB+zeoU;rMC)} zqsXCOE^<&uiuwb$iw~Kc88jj2?RHZJ5-@nQSiO)SAsoGq1fYjo)C*+&2$$g)!m--6 z+nU^Slr^>Th*bGEba7SKAmq?6>j z#oOI{-Su--9vS?5)1b0HQFz#>niIS)ZSNSAV^?Won$PoPWrQQGH7;XNEw+)ztFS*L zgscy8)rwF!K9K&MWuAY$UoN`zi*qU!i394ryYA5w;~r)c)(Kum$#a0D^WHVEai3>? z@>nhOy4{#WAj^S3KVrR9+6phqRloQm(p{6A%b*7$r&EXVHC)mmJXk-1n9skx_kj#?B`2y4YOz zt|QT|GM01zqzl=Cq2-3b0TO|le>69T zgPt9CL35KiUpv@6lJXkBzB~)IR?s+?TE7X7D&@5?CQD!&4vlg$(hn_k#c;(^K?(Z1 zQ{kEA5Iz(aNOwmc9^x$C5T6fDD(#}(Pr4eMMC$_Q8epegG)iKe16r)kL0^q!!On`{ z39%{zcKsGPhqUhu$Mo&_)!z?pthSB$F^X7kneQ7DiaNyqZ_#l@s?yVV&>@@zqA>=(^eT+?JI<9~B#;H*cjt`6kT5#~DHMk)9S8t~si zB3e^3PZM4L4~BV8<8%8PIM~%F&*VP`-gHxh`Sk}fVam!z&6;}YvN^t$<@QEYqf-0+ Y*WH$Z+O?m9KczTVC->78j)95)0#(IYY5)KL literal 0 HcmV?d00001 diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/LogoMapoFull.png b/EgwCoreLib.BlazorTest/wwwroot/images/LogoMapoFull.png new file mode 100644 index 0000000000000000000000000000000000000000..3d766f04a316194349f47a61349de188238f3e1c GIT binary patch literal 157981 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

w7IJDwbQf*mUSGp5+LU85g&& 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�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�h~N4G~Ss=<-S@;ZY@H{qDbOr)+wQv5=u`L!li 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 literal 0 HcmV?d00001 diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/LogoSteamware.png b/EgwCoreLib.BlazorTest/wwwroot/images/LogoSteamware.png new file mode 100644 index 0000000000000000000000000000000000000000..0f58f8140e73f54123d5027fcafb5127dbca8349 GIT binary patch literal 87309 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�jum-t{U z_E2E%&qAq@JW(>S=Sw`pEmyBc$2oM%vQnB1>t@e6B4g_3)JOu0YvxWkKWagBufk6x zLiz6PN9Z$F|LuJI6S}hwv;E+CX%ZI?#+e`VuKJp}IpI#yXKF+)+!v)GuhD`4UZetN z#a1pkGJEy;m|#e+)CO1!sZj-n=knA6PgZsatGQp^u~w{GSJ@X`AEjvp?#0mhV506Z z7i6ZBZ+t7kl(iv!ljs}Nar#qp&3^s5y-QC+M6d!}30-v5l^$1RZj(P7y($X4tSHJ` zamuV>U3m{5fvp&%1Pin7Sn4S1?pkK37}vQ2KdUaKZ7OaroH+>h(*%tIb215t((ULx zy1ZzOneU!&l8ndZ%)r}4M}O!y-U0Z6i!b zts3%|$dEnX;uyE0=6=zMeqqj!g5idA(V?t6Z6l$kt9xmnY9USjxvefmGdqagSsEVS z{_Lv7&6e31mMpq9sDyy22CYL3xQdb!J>IB;v2O%B&U3QKZ=o8+PrZ6ZMl*2O(LU!` z`T>10vdL9^W`6MKA-&eZi}J*ZYit8%<|mJ9qv<>>Q|U~MOn?x9T^PP%PbV=qA|WXM zMuOsaUYWevvC82tm0xnb4zvMYS(7vwAK-F3x~efK8de?UlibK+o#q!IG&z~KKwfMr zx9A>nTh|yV3+Ei{i9uTr>;&Ki>sQgnHHBs+mER#mznG!JEG#j26`#Y1lI2Qeh z3U7{ED@t)p7__b@t$nd_ z9oDhz5>=iYw^Eeinb)H!MTdzHAZu?IN&L9Np$q zGi)RAKlEPVk4a#gGP=8-)EsiCM2@canhR&7(C;}U1RkyL z`x*Pbc_qK16U$$sj0HIMrQX&6p>czh( z42nhBPc}*bk$?Lu!&*{iB96K~C%pdY{VH8s`$e@CK^Ya^$ukah@}-H4niE#yQnlr+ z1NxX3&-rB9u7JChBPBxNaZ2J++3&F86*+b0;Z37>NpsEMY7&4L&QS~c|7ILJwNc}c zWcH|+Ta*q3F_OSNk)G;oAo>4xUao)abK-6t*ov_}NX-5C#f4}uW-fCk{u-lW)sHC* zKF2qDCfwhXW{?1!nL;`9BwPY4m3jVePO$N+cG4ZDQSEGJ2t`$S+so172K=J3-|1znV9v zxZgowN>oU7ySj7a=c?wA$TwNB2{XIyS=jOw$g<&n1>oG6_X-@drl39=QBe1(C1} zCQayT#sPgr`ku5iJTZx77Lc_Q@VPl<<@~FrlJ~MYBBvozGn}`rFlYc(8rRLHggdrp z8FpZuENb&!wk_L=;$FUTtdtmVj(_3UKJqVJg=zp~lAbruM(WQW3#|CkC(Wp%*)*e6H|^a-rZ-d z)SkDG#{1u$3U@>dIcEzdGCH#5xEl%>OW=?vtj5qhag{&4X}dd<4%+A&MJ1M*WZ0w= z?J(2-r6(RdF*d;ySM4SpL1isz9c)X2lGzVJoa)D%{!35WK-N?JJe3aUlIrkI2aa0I z5vT#K&TnGI|99unEXBasOjDxRh49XK7vxr_q*#?3fE&;MTT!vK`0XThtFFlgOemm6 zT>>FHm^a7P#I>43edqv&!4hbxt7wUNz(xAakUa+zBTp<=ojuP#n0>WUf^u}#s_q?$ z#6|YVhfB$mDh)Z)!IZM+=iyYR|5<>a5RlyT#RFXu{m0a22h%Z2dN3#Zw+ypxm7b#y zxsJdcmlwSNO6?d2f#?_^O8dfrt;?36?t37)y0IfyE)K2MIOp=mcvN0mGCuyz870}S zEb(7m(%wQ_iiv-f^SIXKXC0dVu(T!?xaa*w7m{Gq%ZP!miUW|!9jdYtHC)rGtlPE_ zObbF6_V4YAZZ)$0M#lGfp3+F?l>h}U{I6=e7Ln6q5UwCkx(L*Yqtw3LDvXPoiFH={ zuZ~o~m4kT&D5J}s!7_fv16X#ah1%4bx#b#*!!{eO755Gfd)g#E2VibdkYXDU^&0AT zPO!h+RWJmyFsD!Gl2JiMRE}(bvNEj!wi{S2F3EW-Ox)wuUX z`0*hi#|D|saq#GwrbWQnA684B0EZT;GH`P+CX+~9+og8a$Bk_7>rQUo`kRAU65h$G z7Fk#QifUy7x(fWCG%kbPQF2fNwcFk8&xIt@IRVKMW{Z*!{3C+gVoW_DI{gSi`oX3StwK~O z?ffw|6|A+uaTnYaZb6b+1JK-@Diaol#<&3x3%Ba}c?ACx6;3Odjb$qMSO7@g<0sZG z2$Bza9gN;iHKsx;Efb2t>KmEn#IyrIoeDFaZuNm6!6`wQ5OUbz=fd{B zU+t{tYBf#@NWqN)BbFZ^!vi?x6S|erT73=*4^srMWxPM4g=Wnr4Px@oaa+Eq=Ghk7 zK3WS^4_{$%;RhOA8ag2|u;pX&(|OXt%%h^kTY)Z#c z?`fgi6r+(O4K&b6)4jK;Aqa#Vz5&N`YjN z@3SlLtpIAB4GSrsmbQu_} z>nXa+)}ybq{g-{>^LB_>%gmPxY=8J@@%>k!+eaYEul%jRAA)Je+QKV8yYpJZS3@j( zSynW1`tRQ_#{?6Xlb+JeDBXgL8OB~@FVYOrM^sFKb)v5OSVeTu_NYshEb0dd4@sergpyghC%lvVW5F<*IN z)Y#&APhIsm)Sdk19GaGNeS+SGvbX4ZUi=KMd`;X1Bg}^r+f)|`ufWR3`ueH4L;{#@Q=D+jI73gnjoJ*hKj2DSiDo|t==qf zovogbm?}Y15VXAU7Y)lS)GnAUqtVskovgN}`r+-`4=5X$Rq)`JO7rChU%jhdGIM?; z$V{dRk%aDJyP&6lLQKR#sN@$J%GAv!65kZy`b^lt}1P|{CrX+CSl9sgv9m}N zBR4nnf(l`gXO3u-KeEtU%p$Hp_I2}>YMp$P~FTwO~ z`Cx+Ky7aW3FHk72HjYnzeVHgF#+6{cXEEvFjh8hmUcC;gsu;*Y8GM0x;WZC9t(! zfJ%!e)ZpZ$0(J}(IB#xv~gd&hsGz!$1bmZg?FF@R39zt@NqBE3CFnDao*L<~?% z>2+b3+vfi@;O-lw7H!(>!6^7P$@qr4h6wcvNONFQJnj0tx^Q6|6v+y+7;fCbsqGMH$8b ztuRtj#P8jnfE%7aa*EzusZVrYjcSo z9hM84CB^}7 zmPuX*QJ&P}oYg-GkAfXsS!OK7wBz1)`3cWdCxDP&Ya6RWIR#1FwJv>*4!AE$0BRzZ! z`d+gFUTa=T@!NA1T1l~ex_eL08#oiT61#dp!Dkpo=D{Zw4`Wu-dswNd*dD4w{<6L< zUX$DTZSos;mZqFsWUJg4a53_;D0GIPVnMIiML+sIt3UZDFXfG;RovUvS%CHSbmD9# zgUEVL8&GcX2<62cPR>S4j{DKa63cEx`hs7}WmH7{d_*UfZP3nB+McPj1u`;T?nQZuTwu`-L4TV)~iQRRhoynEe)QAF8%v$AP<12h)NHL~e@_S!$wU;2-#MZ;k z43Z!EM_^7o!^JH4T$Id$yMAY%r>abJ*+^avsKUYt4XUC;wxP-I;z+Co|%@aus zg4wr6x8p0>DM4sY-x#=jV3HRwRj73j1Khd7mGSDUTroeKxfaM5U0h-wuBDiPsr?Wl7-R3w-16Q6(w7qru(jO&lSXwjLi?E(~=TuNmDyNYE;-U+~o| zWRGv#4}k=!k=ZNHC&U>yS$TqmK3gSVMbD>{h_{MXaO#2)=DRJu=O z;q&x#(=UVDn{>*RO07}ofqqq28xV~k?92*~P*9kX@Z;tV_nB_!A`;SR^=w5inV-SI zK>u(U&;=o`MW61q5cW?&5|;)s+q|5ZXa+eV0cW(*f+>jIQ}pX);mmsEAJ>-XX|*$X zytod3i!?8^l|NDS`m~lSfI}aviwDjiE%&fR$G52#%~uOlVzkdM{wmFD^_J)~ikBm? zg9F7^a`h`zn`RsKshxFSaU4zpGwD}qPi5l6wmjVZHd+m94eFdXw*Cw>wWfLAU3W-` z3e~85>Xm*NYcvXz3bnuM!|Rnw3!lG}A-?4T>s*sA1vt-jwqR(&9a;$hftF*b*X<@< zu+!0AS6&ZqMP5N1yTsEOIdUje7}7L0sfEx5#KV9@3#f+lVFhBTXYm*&@OcImotFW%`8xKDcNE2CYdI(+ z=(rtjaNS?4t$X72$e|h)rW|5{9B_^8&sl$6o$`Ew$T+{ly<8U(v^;y8{CdI^L}t`gRLX}512+;MHKO11I!Q3pomSq=5}1vNqa3s0iw{&9`!&$0S#gqR@1KoHtB z?^Y=2W*;*RzO%i3LijO?%CodN4ce11<{`xymik8j8vWZmmiZI7AIEdUG^F>vC}k5< z!u5K8+9hTtW1ecw3RsurEF&QPW5e`-UEc=6I|r0d?T5fz^yOXF8kpS}rgdNk%qmXa zJtw05_L#>40DU)}2sWAHD%Q2%Ffk&$=Sm+d6_O{BV3cFS+!5#rjm$uKAGPB7s!tpZ zVEh5w-9p~>D#5$6=Z`rO5`SsMwu@f z7Mbu=-S?lM6J(BYHE17OIzJjPB@nyVp%0VQ{>@-H9_i{DpbqIZmKRsIelX|K%xUCG zUaO&~q{h1McON@BKk~tdA*6r>&7T5QIHo<)6w)gc()%Z~M(#}7@YUBN|J^H`<%~75 zFwWSyRy~!TKI%LSjCcgR*!rSy<`N@;W`}XWkG9@5!W#01DM3rYtjWTrNk@w0RJWNW zbo(X~t{4ntHr~w>?8rxkT5hN&-(fa2g474r)Jh%@Qv)3!4t)Nl;7e0{m;^$2vfU)8 z_@DxmCc4evEWUnUy_JH;0Y{jVna0jzmxKm$tZGEGOO#5rK!3OBdZdAN2f{3YCwa@a zOPvPQac8J~Y(~)8eg$>W_{Q@e_k4Z3a~Zv-7u~4b&F5W*{q>UZfD!jZXFQ`AJHOL? zCbM%>w`%d*D2x&2eY8>7*Xlu9F*t_3&W}hiBNO;yM0nkqB(qi)bU(wL<}A-|sp>)A$3{6B}wadvZ4qt}fGV(ikE_fo#!bo&%$E87w@V zB+0L*Sk#&PW>&uYL^v>cdAh^Oj`^M43lf*sT9Qh`76(FH5QPbecw}AXysu0D|67&lZo7>P>!Qo#TcI zIv8Kag%0BFw9Kr*d44(+nr@f1H*L2a^auRItXcJaS$x6YC%(2G!k8#*6t149y_0+o z`<`b4Hrbq};UFogISHzVIJ2%wxeKi9pqP~)8QD zqLq>+Uf2XW9_=eFpn_PBp^HP+V0cDMzpTqJg5<(@yBxt&ur2CTo8BswWwzCxLJL_spPxyWSe@{)c_-YE66k|` z%@be^juLTZ5K@gmHf)J>G8TcJ2Pm?+yHuh0tq$^-@xip>PU&Hc3*-#eX#3qH%sb=t zO2?XH;PG8F<|Z5(&-g);6-{^UAvE@`&V9raG@Q2Il#Oa`OIW9lrS5rIa1!&niKXPD8aNDM8$k(q? ze)4$wIshDVAkWHi3y6gTg)K~`+L-^#aU>g}w+(tTtx6fm-T`fqfRFaW7og)R_mw=C#km#27k)ma?UwJBj9L z7OeQ}7=-CJ{~Lvu;l_ziQcFkAI_u%{?)yrT*~p9b#XqR)(lq9cPo$=>wCo2X3Bu;1 z3~(6e6b(wCA%5-@j8;vpbWRel|ErYc&kUaWF$ zrQdx!={cneDc%7{d{w?ko7{q!^nk$$N^{B%#|uic0M)AfJ#?U|{y5WfTU-3>Y;4Bn zN!F0t+cktn&Lq3Z*YAQ(II?+lAQwMYH+;Ot=!G!I!+E$8oX;~T5Mo7hZ~v<;+z&bH zX^0G@2asWIMtpMgG!LVrf2FHwlLo<*6w_v;^-aRH4-shNfs&n+1Jjzk%!o0bxV8@3 z;Jj&vOI;FbkR;g@XvT=e{T@{a7ilty>qDVZw8?9K51K5(gvO(Oi7Tl8&2oL+U0p9~ z*C^)5Y9_sh__PFR&~8*qx(Kvj6Z4aw4r8Tb<6lL>q&C5;1>xgu5!HYH@$UZsy4znU zTi;d!*5GJ9!~Xn&qXe#ud`N0wi+^nLD{!jpLE!EzZb2u<+|0c7As`PJ0D2!0$eX=G ztQP)w_f|zdsibg3bd3LIg#0*fAYIv?#Omv6I`YJHCBG~T(qS4g3_<5YiosR=LIo-U znG+YqKOoA?V@F9a8cSg(GZ(&wU;bR5a|OSV@G|3AX%2I^a{6#xFssYM&xL6fG5^rJ|E*D$$Dd_ z29n<-pk|N_*wNMq{{3lQ^&B%$J}BoHE3kkcTN*#LhGUd#U@yK;vL0l$xSj=hn!;4< zK37j9;dRL5!`C0wX80Vn)J25UoJNaJFD}a9>ygmi(92O>%-qv}ssY$vFk3j*OMFn~ z%u`Xulf}tHsq0V$^0{xR(^s(~bhbQdyB zuKslt=7O^4HnAzLt?TyVD%rGo=RVpO<4^w88KyuhmLKv+UQ9>q)Rmpx5Ess&Rl5*4 zx64n|m|ntzIi@-|?fzpY(XvEhZcXX0Sg*~v4lsMv6@X$KgBaP)71{82bm`AV*Qi%_ z{;j$2q-4$*31##_;-I*bRE-`2{dulA(Fnaew~6SaJpoGnE_mVK&jw@;`riHAj5_Fh zKN^UI>uDg;R6DZ@_TN$mpr=v1d`u%qS_`qJMr{*WKh5W$slmOgv5Pz9B6F)>n^YTtaQ>4)|c~0v0sL)c#H}B;l2)4O|9a z!M-S5c^aU{7Efx!8~{!_o-&N_I|=azqt1O3;}g1jOrbnN46Va2QSI?U=Z9;f_$)S3i*gKds+ z-a()2C3a+xVm15gD27LhJ5m@0_2fv4mxGJv35b%miDQg1bqVvHH>|v%u;oIiZW}E} z^Isd)Vyv^|;3k!Wr^d(2P;p2<{&(>dQcB4ZKWi?Hy45ehuVO8dELB% z!U)v0oP)iz*y^zFHdUM2{n&}(REtDTazpT9EBnMZtVWO=AGOQq{^G;_8N z%nVQa4dKmQMfM9OwszOengagCnUb36jv3q%e1n@T8G;Ozo7I0z!O7n*e!u6u-doyJ zm0SmQhI-k+fwSdv%&Ns z#>c;prJfWwAz0X#H9>skf5?WcH6_}f(G*z}t28281;lEzQED5WHGWn3>BAi+5q0V7 z*J+w3+WnU!?W8+;XZZcLLxdU1zNsQ4Pb6YjlAq4D5skj>JM0wq+RBaig(8Gb$u9Q4 zBK?mGlwCU2NOyrcv|RF%O4lf^Gp(8Y^e@z=9<_nfT2z2L_E#xW332!ae%7>u<}Djl zEe_{B^T!`qUhppqf>(n$B(xIxwvV1o+hUm=k&B~q4scic1IVD#dvY7}-9^X;16m|> z1+^K+hKAs%LYkXzsy3%MX6e1d*t8hhz@dLh^m`*W@?8SqLjKj>Kk?9jYR&e+s!AUS zw~L*T0K#QP9*WHkfd3Yi*Z@fB^I-p0V?%6h!8 zqz;F!`+Ji$7Emy6qbg2!T#O7N6rabReL}Pk4#pd<3o{sb=n~Mn_eSBD0?jrX)!AGF zaf`GaqgXx7z(68M(sGYacD*>0BP+)HhHoZbYP%TMl8B^6+}U-1o7eyoP|saV3Yzb3 zVX>vha(GjZ1JwYg)cGU_UHK}M#)nZc<=Z-uLM%g*{?wJqFQ&qH9DpL(W zv1eJnSindB#91-2i1YBRKo>$re@`!jLxnRQn{Rhr4q*?^?eq$@Xm0!wDc6?V>8hP$ zVEZk4EJf7Ukolt1b_MrDPM{Q_QSf=XB9 zIejd+<{Jzi6ov8xWJexu8Trl*u`EXT3g-3@UDbza-A z26#(K3uqiqCDe~&DM~+gA{n_)n5|=1M9CsZJVyB|^V>`l`0zAYrR$Tl4$L&6d`Tt()c9KH#O`ttYDik-1&XBa-0ma@>SkfYxKf z=dMjl4Q{%>kr0#k`T5ChwZ}C@U_^Rtty=Zw{@;x5lTnw@QhB!;ebB?)H)GIY%!f6D zPJg+tN@7K(1HVMx@;FgxK;WxUBHAx4IaY z%kVbeqmp1*MHH~`>3;!mr;A?kdvkFnWWa%(dgqrNn+x1QLh_+1IG(}JyAJ+%(e#*J zwG-?=SX0E1uW|>|3VDjqiGOsMT&^Ic2Z0ZbAJ3>D|XE(N27 zH%gSq0nH=P$t{tc>U~YX;Dbun+o+ErOTf%RKZ>pj^wz_t15?hiC^U!N7U!^MiH%}J z_CXGVuHAx9!V^pXY|scC3_wN|J!dNhyhvbQl^o*0K;4di26y@uzc1!dj>6Z6_DWv! zd&8d^^El}?r(SMBp#!ujZG^#C2XN<0)AvLN# z6~;4gpL&i|5%ZpRuJDzjHn%pPHs@T-sLXRQBeQT0G!Z>rwFEl4hoye62j}c3qkQ|! z?_b7O`qn~fRsQ8BaXO*>A9J@Z_JayZ=Vc3e!dib z+I84{ueP+d~?0cyU3w=yqGp{ALwB;J3+FOR3eC^g%i$2>0!mk8(Qq)(+f-UW9l3Q?8 zE-#29ag+P?{&}aQfqE&+8pt}H1c?{-z&vQ|^&DJ4gtsvI-Ua>izN&>CB^WP>K^dn8 zt1{z82Qv1O>PNiP*euv$UkM-cWpYc* zy%IDyB?$|!>>0k4E)`w`3VDID=G9A@NG z#Z4<92h<}^%W&ARraM8Z z@J@`=ddaN7&!fO=(!X@aa`r{}YGZr08jO!)yj~EnWj|!l*y|?27Ltf5ylXDhvC7A; zW*x46b=^Jon>zMZP3V2m`~NWUFj)0_hAsF`!I@&E>zAaIM*iP?Q7KJsiKEV%2V1at zvn_PXO|v8|3|E&#P!YxkZ(`1mt+}7%0_iqzgJy@Th>yQ=L0@U)JA*iQ169?qM-N$& zi3RuHhslS@jazdeXd!5(biD@CkuY`T0{Gf5mP7F@E^jpb{&g2j*N$Y}oma)Rvs(UX zhaj#}bIEv_GXx3sOM2g9iQ@_cr9>A3h)#_VGZ>7ztYz?VdABu;;a;&3H+i<`J)GFx*8E|jDuH>_Oo85;4&v^oGf~!VyKVNGIfb&Of89JSOSj2$k zo=Q)I1q~^K9VnG^Gw-Y{zQw(up}S`-GY(~iMi}xl*)}fH()M15VG-3P?aZidIAb_D)f2X7AXkT`Tq zuFH``p={U$$V0qNz!oMA&;ro!PeJ)zpS;-he@DK53EFYaJM?bI(6Cb?eZ-%gnL8G( z+`bc*RPH4XT?jLctxb z0tghmxoNOTcURi(0XE*pb-}3pWIF6RFI7imwT{l!^AXDJl_OXw<)O7cx9VE~l zcUBd-1OQ?cwG_>Bu(MpWeN8?@HOC zjcPt76cnN5Q=_GmB)m6s?W$juI$7M+;jNva)35U1bD828VXW}IkswuOcV1C={m{2W zO*cp%`>@5)Q>lFUY)d}CK=_>iG?`*M=Q>~bu3Y?sDtmj~^T|Ho(om{Bco0<^)hLWK zI4_TPI*cGoC#Uc>m;P-V&AR^lUJrTG&DR*|OYyHh-F7U;POX_(JF#Yb{vWdZ)R=p*u@;ot(zZk!v@5h#Z?k8( z<)>Djq?Dmo*uXJS!&Y~O9hC#A>~tNAg%WvfqTf;Og_Ixyme}(3zNM4FXqpcy;;YF3 zI^w{JIYS+7?aa;1PksZRchb(vC^3ji5v~p~{J~2iTyE;*5h;G;9wFCO^M22g5TkwstaD95{t_S_?73ZJQZ%K0JtZ^%#tu>79jVm}z^qvRH6Mg<(A^KG4L zKA61YuQh$gupWFZwKim)@(9xVOeT%AE33Tv8(|ihm zir}I@cmg2)#Hx2|=5~;iprNtHu&1YYQzu{bF(`*<=C648X5Ds%N6zt(HOXFRO%Q*T zt_oL^UMqp~5*pOth{tB=igBsI9FIFBcFv5CWdk>Z+I}-`QY!$5G=h^f+N>9{Q^bH6G(`1KzUu@84GALXBb7Tq~{=3ZnB#QS<2 zMs<%gkK{3`7~^oQ_ys##J3H|qJ!qBeZyvEKD?CLf&GNejca(n3OK#c8@Tcap-6V|O zOKv$?VSLWk)(+;}uF}z5_4O|N%q8zHsXu5qU@vFqrqa7m^QkjEkOD^J6P?&VG4dGH zwdgxk^rMM>1vG2Or2IcyGc41pt3Nesd94?bB^hW2{&GV6QL)y(Ja&AR?ijScs+N0B zhbi;fGj+|RX-hpWJlXH}$>xz6_-P{n4^0vH%_H7gqw3qn;n<1EZN9&M3jNW;y4)U= zJoYy75~c!I*W)l|v;#d=^apheL*hBJcEYz8jc0k?U%{f}b=S?o815qAbiU0a@@2yN zGKurX4YhAE+Uw`Sn@60Kt{)v7Ka^P12N8*#qA^+CXU9HjGLI!!fG0Z}@Z#RM%Fk*1 z0&j_DK+A?RYid!D*$z;PgP?cBZq<>8Yat#aKQ8_wjp{9^&3QJLct}K%lDr~SczG1O zy9+`n8xhjkzvO)*D<8WVuKgDs4$gDrm=KZN)TRUqdzoS!KrPD%=UzA+aB<_v!*k6eN03-X z5ui5ZJD9r>Wu@x^pzeI&XU}&T-q2U6cIWuZN9lqC+u^cXbv=aOltKU`8%XsX-V%eQ zTrk4}N5uYq0C4YERJx2@2?6SU(&eLT+gVp=o6~U8C#@Xj%IPJ9ok-+h}ss zcyFS>6IzbI*CM;cSh!gAxyYG!+e!Adj|vLWpl_#iT@T)_BA8XQQkTr(q)h;~3mgL_ z1guTkN^iZcJiO1)j&tUG=MAWnwB&YzGiOgHpYntm!xwBM2u0^DML{3#8To`(Z+W<< ztLwHS%=*EgqdlRX;QgkjcRJVjGX!BlrT}uk_499&&P7fN5lu;9mgpitOM>L{@B>2z zsE4a4JD;!w$YJe9T@NWxfCQ|e&>-K~O~yI1h-`C=MPdN%c~jhiH1a^!CcOh($1XC! zuo_<<&Mk*$;@MB@r$@heeJK2 z3+xm;xdoCYp{PsBZnYz$gj~G~lianz`q9_rhnqWAQNAyVdgY* z207Qs_X9F#TZA1^2h1DsX7t&rR=_WR&>UCogy#_WZpqEl;XlY+8J2S84v zASX9+_dD>R6&&%ogMa+rOLFNOL0$vDY8RAmQ|sJ3qJX62ceR4A=7b+oi7FF1O|97( z_{*qs(+^1FB$*+u31cZbKO7L6rPDbr6za(Vk7U3+iPV)9dpkY8Aie0xxCC#8jH0Td zJojM7Ylx0}YYLm8f2(_foB0ZeyMY>2H2_Cuhtlyk5mCF_4t^(F97uI>M`*q2ceg`q-{Y>|DbC?SNT?4?4o#9+!cb2_CGI+G{{ zg%Yw9!VuF@90}Ql$z)%mkwV%2*E8PE`Taki-p}WK-|;-peP8!=U+ed}uKy*b;&8g$ z<%m)?Mq(>234uCN!~jCHtQ5rMJ;6^?mmS%QGThAA?(+64iIGgx1xervt~n-Lv`3eA zuGs}62?9nQBKtXwbz}ednuZxR7todIC+MQx<-R6Mf5hf}THUX=Umw4y7Vt!ILnRW# z7uUWzKljupi~(e46 z1E?3Mx{RF;DWyePe^L4#iZl(#@%RPq$m*9-CK#Xg{!bY5$8LSAdQy-Kn}fLOCg{zU zH!kXutwe5#clgVkq9Fz{>J@RkCTEuH4V&4`EE|xGmdR^EQyw`@uBt7YV%DwKQpnaM(td zAGDc_6C~jgE_s%dr^4*ganwn|#QRN7F2If0hJ-#FTJer0Vc^#x0j~#w8Q3QsDXm!~zx48c#CUHUKi!J9o2;X+ zve*BoQ<^y=PzKRCaJqY$&*>Eq4)o?P>GQwv0Fg0-=a}aAO@TUZ=IAbBrtok&aPklzv7|-du+9=z(`5pOKJ@hT0NJ zB_7%L-_EDYG@P(&;IUA$a3B#olnRa|jK2R&he*AKx-uFrZf7V+;REl^@gweGa(UA2 zmNyBq-jkpWozM%nXYQj5z9q==YR2I15ca{BFYo0&c z%kU&ia%^2$Y~fJ)8aGw1S`hw=C)N`Zi$Bd*qH^y3M{8iwYYItNQXx8R;4yrQ?vp7q z`hGi6v{k=Hinwq3Wd~?FMebX7iw!=2H<#?Dkd*SFnkT~FU1)W$c0caq!0eux-D9o>A9Y6nBoyf<_qt*S0Ad@)h)HujuGdiM6?xdm;kLC9jvLlrI{x z<30B>h zpM&7eaj>8rhFX;F4!fUdd$CnI|G6G3pjVv%Qe9HKbmkZRRehN!Ch3WDH7-0de2J{M z#q&BiX?~ZkWn`UrcP^|~y2=kSD$SSWS%k$8rhaU29QtbuDa^dKJd0f&<|tZtf|)v7^TJ$zO7BONkPQqu|M72zVwm7BzJR~2X5;t?~zC1X;Z0YisB#Hg{E=Uh_DJ02|2HMip7d1vb?h`HZ zyb6ONFpKBjjVLK3xm-;tnUO?UFaiq{MdVy8?Hrg(vthI`yY zrb9y|zG7aMGZTD0@Q42fnW=t$3Zg~r=c*o0xV6uOeB0K0I(hYs5A!E|&Q95l6CfKP z24c<>6ATc}jX^%(1hy2~n#&cAVsofrfKl|#OGu>dj;yxE$P2dmi&4FWyRVk^6LKsN z20l^&%5wX31(}qejoQXYu8wg*}O>}B6L)TzFq08@$4Kg^i zMHV57iB(8S{UeMJ44nf(HjL>WOCY>Trd?5Ct$9UTCcCWR`hn(lnZ|Fn1J3?7z!u=0 z9Ng}AN7A#iO5r9a1^yIc*3;F=N`Krv|M~)RmJVjgSE~x}3S^NCkDM4*3^Y0cq|`6v z0MFh>ch5JzrQ3P690jA}eHGZ#9QvA2Nb=nO-H0e6-19RB&=632zX77^1?Q_uCw#oz zSSvy$#;TTGhfBJTtZI#X>p~3213}I3e*BnbaA_SmBP)2Xl%_%AJhx)m{!~FD&KZ!Z zVaYT{K%t{%xR;@DPj}=Y66)(hLVdSGo<3~=yNcJ#jhGyGdH3|T*?aWZt9M6V@1z%# z)a{g`fw6AklI=j+&TPSeBT&*@H?|vUPb8*Q&D*C=_9|J`h~YExE>+sOw7-U2D|_iO z(e8JL(jRM#!4cak$3sDf%i>@=j~2%Dh~CNYEAQU=Oep$rI75jdFDVEt|EwRXQU@6i zLUui#_$JS6phLtKvI3bkM=JV7h)7+GrxsKB|9f-2t#T#S4ZF9f!(YZl z4YMt_$;JvvoeD`~*a7s66eH88f}6FH&}d<&ECIP?-ZF!Gw9oP=iNjz%xeh(*IQVYF zh@6CN$uyulGQL>=hEg6c8`2vIyzy+stHu1U0=svQg}&%kPw!vaJz2^C9P-J=>2Rhe zeS&Tc$e$s;HI*aDg4rhA?{B!N8fG7ETZX-gFKYEZx<~WzU<%SR?UbViKp|#aJx>K& zN5YDebyUhs_-xv7&Vg(N|; z0XYm^IhVBkOw=FJ=LM&Q7uxH~zGCIkMswE`C&A0v?pqd@q*$F08g5h>2~=fS4Z7}m(oi875cqDy+tTHgk?#3A zsuX_PO=*Z}DU^@oWSvV4{KyLhVGHz~&-bZMC(%#SZTyPWB5akV-NVVQG+Z|5?Ib8Q zE(BB#>1ush>KPx=X&-tky&g_Jf^a)a8*EWOdVGf7lb&b@+PntNPPBe^Zr`-#gBEB5 z`+}&&`T{|Uo45y@psL75C?u&D^raS}tOAgO&cBn;I8UGRY5|rYHRxc8!mRC4CsSP& zlGMpgheMyXcYR39Bt{Z$?DPrWIq2c#@O`ZYiucR!hXl77fq{|_MMsdtk7&8>8Wj(k z4hmk|z5)CF84?{0KDO7X2tndm2&O^M48HG=359&bXip3%Yf1O3GHjpiwUa>^dFTfUUB12IKEBvr|OixnQ9%y#{$f@~a| zoo3(3$;~BK-zK5Qxa2KU>`2krFrYV*Bs|3J-4JpU_n{-;alHWSM|hMf30DNrg|GSCz{> zL_y%40jVvL2UacYSf)sZ#nT&uOR75&+@(YBBk5toApQ&X`sUY`$&%3~jt+(=o}7Gl z4or7payozms*MBM%xUs09cE3$y_XtVt6|~ogUdk#QdWb+n!w^Aq>t3*GF}$sCCg%4 znmc~Ydh#hWeJJ_FYP+`H3xs}Gx#Kv? zYu1qSxB=`2o_QQ}Sgt%&Mxcu`4d@ndD^+w4w|xTxY5{E(H*&eFCRFHiTH~kuPU)!O-&UR|D%kQqb0e~!6 z9?S=e>I=OW1(y}!9=|O<`}pIJGjuV*{vsj0qY3BhiTgVL0+>gs0hhMs$O{|7KO)~G z4=L1*L9h^f5)FHREOO1Dzwm$I{_>XK@^l5u+RS`2n}6wCUARSsGYWjFM>)@fAS3}L z2*IGb&BM65?4TvZKiB9+2s09HWHkUbZ9qtWJ1w(T865&q9i-=wBW+f7cDh9G_>t}r zJLvlh&V%k*M+hWvg9oy`>A@U1zkrt83koqu^OKdIG-M;B0O}SZ5c?~}f}D=Y#tvlQ zw?)?HD-j;g=530=JbGJhVdszy1rgIo5X6wHUkx%0uY`yvz@EE}vw1fAwrAQqs-W-M zd=*ux;8Ne6kS!6f?fu5EMwu@7@atj|v`1wdoGd(kV*x%4kmo%ILEaELj3CoC1{qse z^g^Kw$@5T|*KSE6eQ>yAGL4^rgZG5wS!AI&B@C&F$y|T1BD_Z-5taFBv1H28FGZ;~ zdRcJ#11q^KT~EK`hgrpU(rH5UlXuk+6#|LVofxQdCuG~pLxjczz0E`d5Hk+f`fiI` z_^Zv+F}3sPkn9y5znr`Um2AAS>yK+L1A+f+$%J@~42v=j@fzu#%Nkqaz@%1cT3q`0 znWVDe!c98Ut z8p7|C;_FWexpOlALv%II;_m5y*+uY;N)Aeg&Va|7f?eb6H>5rGz(JbVZ()yR#cb(y zt+q4?MWwDW5+o{vy$MIUA3M7WAT7L;W$Z!XR!vHPex-=Wj!?WDhK@{4`on%8O71u` zx5)^jzk_y;3ygn=iY^?E_S#$57d{}Q%|YB!WOi{Q3c5D&XaiC@2+(^jpxcF6zP(Bp zIsM`5D&QKF5EPOe(1p;4^|;=P9K{w!6&joXuh8^6CCgSmle=B!VkJxxAU#jd-&jgC zJghH-QaK|7a{nf0Z>dbO(lw}U!gzS{p1eW<01z27*wWA#6{47l-xINi+$_sO| zFT)|E*FsL7r_Npum4t4~JZ2V2ftLjU@-cN$;UlfEd9K<)7Pk2-w=JLXwk;*5~fg)t>lukw>3H8@+fQ&`%0t z>53{>L4fZK@FJKNacL7FnF!s`5FlMB%5VeY(SzBzghmLJ*fH<6qT8t2r+xjuBXxL} zG@(~$$EAl`z+zEn1vBFiRIoQ)ZAeMI^O8am!&bQ-WyH0b7IIR{avmd!pi^;#w}ZoQ zBNnj!@iRPu%1D%w2o*_LkAbtjYux&G(GICYVcP8M%QTu_TCuWHjZs^gL6i~*QL|e? zrwF7caeZ$%!BfC4%NGR!!ug6uKtf&}4IJRh??zO6i^(z z*Y?YSTiGDmVhA5t0Mcf|VyJsIR9dB_VCu7-{Y3F?rw2Hj0ZDbf-wa$tZ{Hf#Y3py0 zWIkW5>k>2Ku@fSQ7QO1i_?>k+TeSD+9&|_wJO#Q#d-}4b%GqBhWIx>rLl0P1RLPAD zHe-bMLaq!83R;x$;-K;q#^`rN@cDKQsxqsgYwD>=lyp#NT&d6G1;GN_gv7qq?jQW@ z?F|JSLB6&B-8tc2rF8qjY8Yk;1g;e>g{6$hEJ#{7SFLg@h#y!Ypn;-E@1)DK8w=iz_WK+Ld& zFyvdPUIgt9M&E_i>m3~54T4{C5qdytWEL!3Q~y6CJkR;q`2zDJ#0&E}>1qHwhIm-R zV$~ZlR66?QjTzqg<4g{fZbW&@X@H-r`K07{A`s{e&Q(ve{dCAN#-)C z1wCSmC*F-f)}$CfylGZ?$Mtv8&KYcW2jGmG5x|;E>W?JfPG~eBA@C+Y{Cy}G(9Q5k zrd=T2g^cmmpsRgXAd@Mpa0HT?sG6G~a&+``-K9V|pjYuddufNX#tmVJgv@!DcjugX z`8Bys%LpHu=~}kRbA-g<7a+05;HF(ARRYdr;aTPYR)qu6p!G18B$+zPf8kTS$`hMs zp|Md??VYb=0Bf;btj+IZ)GM~^oPzGPma%grK+BB2`CKCQVjtcWLgxO2H_rei#v3jH zokuOAebM2%Bi}L-V#KKOXJM0=FGBho77qk82Upymf5vcv@0WqGWCZ;SAP$MGJY?!M z^MkbTGpMdqQiux8kDG3Ifcfz{wS)apfIxS3PFT8BMD*?jIVVCqPly(U(0y076O?o( zCo~q6D87M$!v~l=n90x*k9z<)G9<;gtREoH+`trjZRX&Jm9(tfG0O=*h~QF&cZmDY|_1~}Fi@%3BB$DZOtnz$GwSW*YdpB|(V3aA) z`|$xFsKMTQpA51J-2LSZMT(H$;-{ZOD|n*)xo5N?eWoQYP`Q_xpaB_mL2@QZFw-e3 zkLZNNi*Ll~@C8JpyuBk)%Pq93Oi-beGdi+uv~SN}EW7e9aztD)FdPYthh7q@)i-|G zxF-RMzJw1ksluQO0~})%{O2p2+yXar^}jymV`NV-bSgcd<+Vi<74egJ;n z8v+IL0XwSyIY;>fG2?awcr- zmTAcQs{q{BaoO$C{c`ZgQc(W4WSn^7`VIQ-<-_kQ;Fy-WVv4*d8)H8UuN} zlCihG&}%L86I@S#-^ot=dh9&I(E%s~T^c_NQe6dJplMit03Y01-m>`5nW(!63l6S` z1(-n?tBE|g7g9YuRl6Woe@2G+6ZHJ>K05RjSHEb?ygKwcUpA-GRRX_FsZF9@uYd>Q zvuBagLvQmcT29`fbo|VI8wlq^sEH$71|o0!Fp(SZYMD~lFOv92=jO5ichS1h1$-I< z))xSf0U~(>9QCYHi;6FT`r42=&T_(7gYLL5hDCsH_|V;~*&javB_n4x$>s2Hf=2D= zxMzK1=f&_(|5!j4=b0aezPxS*piS~fq3FC!r_ncaVBH{L+x&ZZ!u#?;XU+0Gfd_CI%$uBed&tdvsLk9|=e+Se{ zpcbI4v#T9P-=>@4;VOv4*n&G0=$EFJQUHkutriDRk(;4gIE+AoT-ohFpNBt-bfD0~ zMC>ty`6ZQh#hJHLJ5gp=?RT^ z(C(v32sqKUUXnZ9PazZnc9g7{#beO?yT1O-H*Fr)nbqZTpLgfV#&0N_K}xSmmF5x0 z;3c{PtMHO);&FF&zOldM0GEW5?gM%Urz5RRP{C%uP z`vcIw%Ij@~`Rt?=_eE*E+L-I;?n7p`AYQ?6Vffjq*$}$L zAhImKONWvRzRx}>&_5FSZJr|}KJLSQF#_~wqz&9UK$o}Bi9dL!% z@PoTFbp*E^+>(-k6`8Sw>#z~8cGb_U($;d$yJno^HT1dDI79Edrvx@W4$@XSKZsSz zxgWp(GfpaiQ2X9q^*1VUet(_lDI=9xf5WZRDVW*TYan={;#NH0To4p~+}OHr0sB~| z%=F#4sqq``@fc0O>vfi&IZinNv66kPKY{uW^Z`6zLon%vM`f6gK?v~CM2H9N9E1%{ zu(!+j{%ag{P3K}bv1(@vIb%i`zv2C7`-Ogkk-#bNGm_Pp1`9SPyJ)>lzg*bZM=FFP zR2&wxblG>e+K#=!V?afe709w%dJ>DkRHrlyjQ}1zI96$S6QAXN z)m+smzVUQn@XLvt92;=EY(!q4!Y&>jd3VA_Lz`@Kvl^#u`rtTK?m*_v`@5RyWPY4V z#*Svv(`_lI4ry=O@hR{2!S>oE)6IWawns$g{<819Z0OT@;lzm(1KHD!8I{$g3qNH6 z8_bg0`Es(Zd_sngBJ-YjiJ*LJ<+igFNYB5MU&OtFSG(82{9cWUw7%O)I>(2k;yC9Pc}?QGFjueAB-}x zM}|yYKjfIi#q%XZ@@N&(ag((LP2IERZQCw0a(d6S%mfXWipypDjO$wmYtjx){^dbl z_^}j&%ni|4#yttbKdEcCbzhswmhCjc-J;n`)QCxK#y>2*LV)&zv6Z=gnlQQSLVQi; zHR-IB_?bBo^`bpAsP4d25jK2Pgvxb_#<00nH@Xm-?F@t$4HIk#Z?y9!&l@whLqm6Q zUrCX^MIWhst5RmRYX+i7AA61c@v*oqA#&MvWCu9p7?!+y?l56xTlIaU>sjXKlg#09 zo*(`GfHm@2keSEqY#{%EP#wL)) zMck-}94wXCmukUwM}>u*Z?xA8lo-c7_T9iR4vH&0s8 z$?8#svN=&N0Riv_ae6|ZkbY>vda-<~V4**%MNvm7c5x5~!YuYarQMQHFj%fkJ2dxl z6Vaw&BD8h8Qu~wHBSGy?zTVVaaWqY>aiDYngIrMLetUVhPAZqa;9?LVrsS4Crec^7 zbe!F>PUh+GcSYtohz6AzTUg1PnwH%0Z}YMD{gvj`UKrf*Gfd8GW$5A4m%R$Q?jrZ7 zk$n1_7Xf$D@xzz-kzverS`s0U4P#89S`A<_^IMq@nb%+TLe-yfw&j3u-0{rX0Y$S( zY3@U%oh!iWZb0STIxCXIy{eFH?*gkfbND-SltnJdVYnnRbZ#h2I^l+$k0H9hB!$G9 zCZ}i$YDKQa$7x2mnYYo82dndHKYiK+6yIVmmt8z@`<8=g+0)WUlz!$g!GplVz9qO% zeBqk92SX?8>8^6w=YTS!Yx9nsO08(@@WR@-SNpuKa@j#7d9(v( z_S1++fn~dfiRs-t7w}DUtb^&B*rR zckAxw8+}-QL@s-792Uft{nWq;o8}rQo?9csUJ#c#jB9Gi4BGt1^;$Xlj9m7|@eMzB zzM6RmMDqPr8mEh#y3xzqaOyg{=Jz*DV4!GqbE}egm?_p;NykM3{{ki+K-*=L1(E(4 zK+!n8Q6amSTP2xB^RO(hFl@k*u@kaINbm-4_vVylKZqKx9MFK*g%~^9RUD(3P!6f=U%#(l>77S|$ zenC+;GWK3q&J0p|8y)>KE)33cweFhI@Le`=HdYd_S-Us zOG<{nbGh>s?svKEMC!)cAq=-A-(^8)qWV;!Q|WBj=c;j3e&hiN`)Gqcbp9~W)tN`YpKOM1M zTYO}eQ!9LnY;L8MM8$DPnT^@(7Wa3?hKcBgPIey)4EuTdgd$XTXcVAxQG0u7yj!bD+nW!2IL>Uf+ zORk9aNDxmnOf0-sia@6f4M0AI1{`hh zmRwufZC3j?G_JxKsp_3Ix2oB#GtH&X%L>VAC8)C^nUCbM<6nNBg$cn>W)y2~C6+*S zr=(b3nJuz{|?tcxno+$koPqN66`K~2-SuUqWA0Ro) zYP$RL90Gqyu}s_@nBSR_O-<&^VtS%nc3Ft@^EN&Uq*%6XJZEzBHJzUvLCXIlXmoOc zK1ObVVy1_pxs#(|bm0s=k-;Bw*|nK68TP?Js;q)>96HtWnSO`jOSzn=T-s$+z-6!> zI6^?AY3m;Jf&0FRnGPI;hejY*%kwVoz}@mK`J-9=bf?b71*_$N3Dw1C&@b#q>iTKNk!EC0R>L>6 zND8{OgD;=kPr~+QfY_PFJANh|fiVN>_Kas1V|Iix-0d|~zt4WRRY#_zpTq`hMIDC5 z!@~THHl0ld6VwxoZL~w!;6Si^F}XAyE}|8|w2{H1pEXQC8r8)Xg9({6cfdGjT2oP{ z336|dw6D*72Xxx=LmppknL~8w<51kHR{I9|^tIf{^H?Co zPKNZ?!(&4A-TB{WA73APb*!^Voh%G$LbV&aprpgtfZuyGm-bUUb*$Knm57M~(-Hy1 z^*+o^X(yY4K}$YwZUym%r&_tR3KiBFcQ^MKCiT*s3)6^Hs7o(QYe5G4Juhg(LX@WOK550yb_PLB?h)`KuvpfBaoexg_=u)-jc zpmFWtZb4wM_ro9V8Z2GgMrU!* zn@b)9(v?C)H4-i~OdO)Gkh(Er9GI!{owV)9h6kki=abMzF(zb*e zVXb20wwx*COuLnSUMdUhyXxmkW>P? zaB@LQ4n#!M443RF_moBK1=*Znur!Vb&vClLDAXUFVd3+Wsfs!)wA_?hFe05C2M;o9 zA#&6K0|GBp0&-1b3!`RfxoSzbBsV3j?I-H<45J&1ncLyaA!+JqqF+2*vZLH{c>UG+ zIPB`ylbi4v)!Jg(;9_x9r8n1b3&rBR$t#sDf{C(%iB~gvn|)NBa>D{=PcnOQ{Sr}q z0e$6*9PU@?Rjy9FRBr00h!s>hUFiONqJJ7>_;N~ttHp_agy>&`*W~2W@9A*cGrsVJ ztJ6H*M?6{zmoRH1fyuws_2<)&Fk-_*5{y|@26td{4=0hM$YtS&>S52b%h&+%GQk^0 zi1n4Cu?j*3YAZFvRB*S3#=GgQts65lh6#c8THK#IvsVIfEM&mnh38wD;>?-W?Y5+I z#F3m6V3J}30v9;<+iOi>qgs5iL-~bGGUAm5SwU^fdzrS(qq^9^$7zO=`Y>V&*4+u~ zmb!my=9u*>P~Z>1jj-)((xoR|a{pRtgwac+MoIuM)fZ$y87cb^RH!y9=>Q;2+!stB z%tgU|i5`Lb&W-U?h2QM@F?(EU<7>l=9)hE4T6a!~}I zk+#SiaGdbwse(@a)5%dex+op@e4odVsJnH&iJ3TG_UDIBL%#jI=?I$S2f>P~z<%LW ztVH|eC!cNIE980WqYc^3s2&;ws7LQcu$+kZ!ExV_S!iTsMVZE|9;Le(C@wDH!j%(>heLHuAYa+ z1NLqSj9{Y>xU)fyW9RjlZSc+^xaM$qX-z)kR6@I#j_6__;mwvSihy2y!&AYBXklx} zD`s_m>$NLwGGmN=G_$ov9091kkjpkgg<%z;lbW+szFX>ZAp=><~hfS>U-)9L#A z%5i=5+3S!yY)igJ^{W$hx)9%vh}w;mI%pRNXH#-(#y(!<@7c5W@!a8ibTcf?t+KIt z7^8TVl)H|33$ity}Hjx}-Ded<3G~&K4Rb2_<1LJ1qJ*qOd zln_vS(^E94&Q63dR*x80DoJfZOjYz~kp=9mbr4xaN?k&-%MQo8z!^FGs zJ1-S=^7rVxk^nQ;hR}lQHyOKp(|RJ!HBmNJxzM1qT(4q@hudsYfxQB6C37oNwEwLc zuZpR0>QRXG-te;v{DmtrVBvH#`?P=Q7Wpn*zNuvjMV6w|e~zPaT9&1fI>gw<1trS{ zv@JKxMb&fkQb<*sO@Pky6`)zUaolN}8ErB(oUYu|@i|>N?<$b39!wZKXDj_4BeY8= zc8dFzEGIZOKz5B#e=b~XoY#XX5(6(B?ba{>CZ`lVj!q!7>~KChmOP{ce!KQg^R|<^ zhPwMF@3!ddG@le>%M-J?gQ!bj9A63d)D-4#Syz|=4H zZ#NV7XW0FysWWQyUcTrSs4EYMIpQ~?WMJ4f46II{IYf5 zO3et3_jO{L8{Q0{?71g1C(6Qnc`xeMr=OQ&IWhmXcQsPcS*fUR0EZY%k5zg- zM53j%UksPHAy*HklUa zeKmeyjtiOJlZ|~i6a9C=!?^)b?*s$zz7GGNR~@t0>T9id**;Y~I@(BAgjgQZ*DY%v ztl0qO8WgO@u+-g6{eRx+@SidP>r>Wj2uwR1ONjo6-o~V!?m~rO!t{2UQ?m9;L*zo{j^gpVBSQSj6w8xW&fQFZUNd=h0zUNu%S7AS>Ild}BqD(*` zlN!0SmF35LLxDc9Ti~wiwZF<;)putg#l~sJ0)HJqo?CBk4GdhYR;0o@U-xx)hjiQ4 zP1f_5mBGI_4vd{nFkF-qth{Ss1sU)o7sS~2UI7R!fob8GN2lSQi8+|meFC)^pq(Ac>l}Fpbf_yKZC|+%>nW33QO>z29w5R35!l9* zf>j=ZBXS|6g((T<6(&;CAkCf=u`a8&!^Nm28Ia|%l_&|o@^(s->_}fx^-0w8e}nn7j8l-0~D;rJPsnt-@wxy*Jx4U_gc&A(|r`ES>A1Q>R~A5x~m_76cY} zB!tced;CWvwn`mh$N%R!x$F^o47tXn>}lsbcs0l{GWJH0=Sm=I9z!Yvgm7sb=!Q-3 z+d79LZ}s`6#_Sm9DYe2@A!983N+C$e{uqSkPuXh;p_|c~yjC`P{Q}^_63&APX1rtH z2=<$~}MWe3i@2ggmr2wDJAln>Dne zF>a9m==r5=sAbc32fD2P{>2oDKQBrZK^ybBcaQ0Da@l#%iqJdwzr9L!1{>K%ucPZ_E(Hl|qGUzJq zo&h+9U30>F*@Q4_6NgJ~7!b7$or01;O@+FZt7)lUQ}Ohp4HHjpoEMDF^@H}L zhsKr;PY0>9UQpV_kcB`0z3`4J;5}n6^6GQ-a1lRDyDoTs){0=DoOwl<)R{b#SQ0f+ zX|IzEIE}t!Z}*sSQ9&5AnnP)yfNR*n|9cY`QbEOMs!M%Z4PHR+>=&R4!3abSs%;?6 zkL2ctg&Sp@nyI5alrk)FQhj}!Tq%i|o>Z)ne zb6s^7;6z}eG5#@rHg0(CFJKC72gCG=_x;rm2rt0DA4l!AEJ)Mi0yn}ief6SEjbF(s z7}G>*b9|i5R}gm2;4Rj@R+xMhiseqEo?w4@T`dDEJv$y8Bvb6RuIX03QX8*695s*GU`Jn-Slx(t9T@Eo+>Rp=G9gb{wNvl5_`Y8R6Z z*)JGx7z3)9BY-1y)+uvJn|W`Y$8*wulU$<>UcFTt)q_1LukCp(?r~7*;AOy`QsJb~ zzybRKQ8v;-U!^C7f6B?y{NJ_)TvPz-EAm@Gq9%5W-i z?8X*y8&2n#nE4Lc4u1;6hk6lfZt%6$TwRcV|=p@5SO-Y}U&6a;fDbO!uyrFcCQ8GTo4l${t3QKk6u&U3PCnBX=@WO|gS+B5b%n!EkMn6z6v+c#3MN>ICN z%2MvX$8vL1Qb{csr^98piw00j_o!A7k%zBAR!X1gzP#{gVD*S6eMO}ZmzdS}o9n!v zB9|xi^RUvQK!q#7D6_yr*EQjH=xn+I(J?H!>1t3Nj5RSO2_-;?9~yI<{+BS1z{uqY z5MU*YC#n&4uv#E*34t4JM(fIBXyDDwHFg`?JFRhmJa)lDPl#G}%m^Wk@uS?7d~zYi z$)xP|bAA$BB&5|!72F<-D+-Y5l2r8z)k2c!qj2v47uQw*$hHfJmy3rDukRthdPT>!Dy0dNf>`H3}({FbHG6YTY;) zpX;|8*IX>Rwv`wV(EKnJEh!}Vb#o02Z~y&0@$#Abi&9MAR;58Yr5(DuOs3D&_&cF1 z(Un+hjOMM2lUGLwX)#2})Uh3|QvEPR0 z@FSa04GT~Gsvp6J8@x54-CXawFAFDv1@iQv(m!fd;dblb0V8yhp=kTH-gjs)ztEQ? zxU~2<3G0ALV$1|9r=n*a;usW>b?XCp7TBPXECVQ@6D=x8Z2Mqsc5ccKQWL46Z$-Nz zd9CjWU5U}%*10^_HZ!$Af84Jr<$5a6QM23)O3wdP9vz|f41H1U%{|++5BY=&LvE_w z8icf2TfpzTZ|er3*eD2`IPAKh;mrHxOddPbbe0 zA*IP8Ex&2ILg0W_Ts%tu$dK1^ChMGtex z<}2+ELqC3W_z@%WWzF(OvTw2ZnH{zTsU%eHNr<^J!{uH{X_o_GAnRSkj@7^)Wx48N z>fc-nc3=vFLoVyh`uB%4*dCuYv?z!u0|%Eq72Z4Gw|Fh_0*%H^<-Z6WZL9V8iD$t* z1G~mdTwvV@2WwxYil_d~ONe@fLI~DOTyouSgiqLjWJZ;vdh{Vu9JIB_9#kko#f~U; zkP)cdcIK4`JbHNp1YeLx1^#{XH9X2wz6EehFutsC zN230FBm^?X$9mNfd-F#<1u4ozRu>zW>xaxv$BR1(?bi9ZvfZrh{w&+kfnP^!+iyDF z%|ZUQBkZ?4Nrq%$e#2e%>%ab%Ox{+AdA?YWm|OLTx0m(lx1?-yo<{XU^F-t6RmRvw zaQD>yRoN9+hy>E%zpaqAc{ydj8AijQ50DbF#OWMJbk_a8FF_*@pRVUo-|t})7?$70 z0>B6_i`%^z?4VZ?WQYbKW}um^Kk@e|2VIhu6yB#Lfn5Mpm8{vTe`#C6qS-aoUqvE* zwqO6HlJd(NxDQ7VyW0EqfB$FI%<(z)c;hX^gtu%C|^pX3`8(v+L;B!MP_? zM!E7j3&5HY>zIKNBAVg2}0_&$Q@{7Q{h_j{j~m#+9)FKYQ)R0qjWNz z3|})s8S+c&>Fo<@LP@~xvup+*KK;oSOdd$GL?ZzHW(u`t;&~+eU;vIjR9P5rdDL18 zR}~g=Ve~q4C$hbsJ+c3ufxtJ}8?regJDl!^k{|-C7$?()O2gV6J*0GEv=in;D z!Aa$Og%6~2Pz8^2X20)NCkM$tksmNrGpIO?bh)C4yjQf|C$0Y9%Olj`w^evw7`VsW zCJTE$xR4f5p4LaL{UpG=02DP1l8rKN5zj4lBb<<}8=;VI#gG-^ZWdsra*=b{{mhlX zY($jFD*SWq|38u|e()QgHvg8gS(qFc3M&g`$1x}vgysG_fFB*OfOfJ6$uiUF*I5r{ z9*{N+3BiCK9R2^O-k}aZ>0$R3xe_eW^M%5_fz{ThVYZJw)4c5C) z%I36KLFv&EHtga(a*svNp1JY@18ou1&bq?k{X_;Lfy{~5fAq8hCVeA}02v-x?@tJ) zq0&)ZF@9SQuIZ^6d>kD!1CBw!8_L{~VvI+R=H;1Ui2hp_Sp3h0Smp5P(ygqDn-gYh z5=b}COCzP(j(7d9D%RJ^;jR zPA*(PE!>LRg63Y2nMLfy17;v3kbT)-$pH^$wE}DZJi^Rg9Eh*z^$xjEH}w!ms1X8b z8*C2%pp3_;l=gY{5*HA5NseE+bd(ye1z;5*UPNFxs0T`SDgf}FAS4Xht7dT7fmzXt zm)Qv%yvm*tOzGgR2O+#GmEB;Ntz0x5TDSmFxOJ$8~ya$T()ObB?tk z4sx!K$bcbyfUv5@7KG3B_JQ0ngt5@|TV{Lhkk>s11RlKx?8JvSWgP|*Yoc%=mO#l) zA9dW_Rj*7pMe;^fd|86YL^{{Z)^L zO8^`QZX+Tby)C7-;8o9SvU!y9D`)t-FEa~pjh(G>*}@0`+uRW=pzF=p>F^{bMUs(Go3nw!Cn5cS`FrfDEo+SUOnT#ZtCR& z2ogiIBt%~s43^8bK-!ep!bBiQF=_9b?~-0m`JrJF?LDx@-^p88rL!#sc0|T!P+cT! z3Q$TwYwtTWhqKiJi>C-NqQj>2HTKSC*-QGCJx)>!@?!_5G`zsnBpZ+v0q>?#gG~c) z8he<^Ae%_T;mlv-H`D^z%9|qcXi5LA0ZTN&=DA2u@i0uU1dX5}iM%uPLdb>lIsuM^ z`upYKpc{MH0!zWXVIrGu0S%wz3js{Y9_?@)Nq&0!MoQvUcY>h;N0|?h6Fw+5i0&F! zlFMF0>PO6K5vQ(1(+H4;!efv`gg-ML+yI@rc=Eey?okbq5GLh%Jo{Bv+$Rp3-ezNl zWqEf20Qu7a&yyW2Z9r+Jv6+#|-n9m(c|n+bQ-1@}-;iAa8VSZw+TT&y!4_y$!Y~=y zEI5ySh!k$R)?(vK{rcXj2>|)*zl8Yuc6wi?p5sgey^^b8C~R= zpkUbmUr45Yqal~gI}V^gXuZ}7xkIlO@VXv@huHp638G&{&%!GmnKc=Dhu`~?+396~ zBtyPKsYpKHSin2&Q|Kx&;uRz#s|IiS&Ng9V<3Is&W0Fu)hsti>C~L85k`!eVCpH%e z*M##y+sAVWE<9D`!-Okrm&paO+?qaq>3BavPs-Fg{HBl`4>46Z%*+@@@m=)ceR_L@1jJ+Iwm^6fs z+2o~koPZ~}t0>Jk-&S&ueXkWr&9gMJ3A}*Vn6_bTJL24#D|^wN*oE7Eyd{!7L2&AC z*k+s=?6MA;#A2nSsqOqVs5n%$bKoxv#D0X~>Tm=ZpqmUOw3TTxA1pj!kI+^f_Bauj zyDZUP`Wp*C`^ZPsfxzX0Q1gR$w+|Iv-?f=laHWv6O~)BT1*F}-pBAppS{;u=al>s2 z2gDc9xGfoiYaCBWjLO1#>{RsOmHd13c!( zWQ2H+KNufA(TGY$QjRpbF?pI+n7c$X3MhjVP9s^7)JQ9|AkR$*+^G2`4tGdnH*&2E zw7`Hl%j6JUO`16!D#H5qG3NomqhTMEUyv6TBsI+V6wkyjWT|iYgxNE_N}Mtp*zdW& z>c#Nz0C*K`{~)UO$6K&FWyp8Om(PVc_oKcDNscs_Ap8dZd=Y1DG6il|KB=(1Ler~b zMW6@qFft(f{Ul7OQyQ0}c_vLQJ|>O%q^7s8SVK2!8bV?ctg|o|LyfLUKWy-8!U2;M z(Dx5fnH9v;PxnO}0w9qlvT8w-g_6N~ayIl>t+l5c!U@QmMwdY5#|azuVe7`w)2!O> zI&@F63Zz+#n1wKp3|YZ7_M`7%!<(3wp>lnRbL?3|Ak%^_0i3kD0pETYj!!^etS7$t zhPFT=c7P)eW3@|%Ap+4n_6r36Lp>cvYgO}wl)y^} zar2WcuLgAui!&7oR?4ey6m8(%!wNK-k#jo@&r9=E@etLDg5BS3hBD@CxUB`eU%c{j z{a$haxVvS1<>#;i!HN+Hl^Ja2N1pER$(+BQD(fu}TzHW2S98%KhM9)_)#izn#>Az8 zTdVu9FsBbf9YIVNx}iX~cjvWo9->4*mAvTxzHWtl-59Q3pfPhRf$ND2sX=P>yBNlZ zE3#u{_K%M_Tcgua5LCa`eDjSKYU*v*_kL><*4)Yn>CVaC!2jdw&Eu(DyZ`Y$7*Zh- znNpFGBpE|gLOY~XWQa8(dQ^UzZ-RVvKE8wu8e{gWXGTF4Ca?0!B2ETZ0N!4u@9!@D%dcw)@W1O|?RT2O}6VGpyH2oOyEY zFX@x&(K%YtLP-QJ$jEa53ua%`Ytq2wJJJew^<>kBXfba_Hto$g>@A1Xz*YY^p7^LLvRhmc-1TYV z-G_}jEu;Rs)Y=-9hvD8Updcx;&;9a?=zS@ZnjC9XCD0sq@cgV-n@Q=P^=V(4@IdLM zl>c4gRtgM!ZDqfujIM;9Kg<3wd?_E5tkAv_Ha9`X7cUonDfnHfb@`Q_*n(q}$AM22 zp>`nn-{>!cq@+@{`7>|neV@)}HTT=?3{*l08P8~@H-{BDM2)izWYi<@AC4*A zRB)-&ApSCZj?XQhB;8s4WhFF-pR{51{zoP#VnqxeCP<%(C zL`b)3y^>6YXexb_CmBnmQW};>#p~tmj9@ytEmuk16KF1K`i43I(jfOn&iPu?(7@U3 zMeO$GjFwTs;l=3da|#>qhnO)HuR3B#xhtMV@0-R?;$6yc&U$eRpMQx2L$P-DTjXhf zYL#Y)UkwlSYPlpFGJDuRzvUj~F0kZO$+7Azblh}_R&I!1M`I$*xA0~{NUY!W992gA zMQD#0_i#l|PcYa*QJe`Jx_TtxE^twdf@{}vcGjyS1GWp}KKx!=dfx%3DoH{DrzMV? zzA+S-#){2wZZ3ogh0umq;k`?Vo5FIUs6JkoZf6)u3@4$L+AkUY9M^PJRB6oHS zHl%O^g`)4rhMeaqabn42%-s7v+47Kq`jFk`Me<`mzK){==J3kC#r*AUYk^jB?nS9 z{2z@YMhe3|_FIgo0jQIl3=gdmj~-0_NPe{(Y)u3a_DQo|W$`*WO&G9wx|O5kVSacO zrBgnUBk{N+%0{=#yt>sSWX?;N^{SQQOSi=(TooYj0RJo>UIewfn zJSw+|=6h%hu0Z`F%4Sq(1^R(p@{I)Na@fivmrYfV;5NQf=TL2^RlI_!n|krP0Jl!U zX(1k6zYfx~0#oJ9{9|Ya_$nWQmn39G!o6T6KW#Yqac3EV<@$ktqxY%x9YjAHjS=~D zD7pv=-boIj&Q&!%-C)jL0!-MPb6^Jf|Lx-`$&bOIk!y@uI22dSWpYR}JNSvl?GJc(ktNp7Sw}6^B#Y&{|Io19cnbz@w_%2&;VI&Ra zm6}bvtLy4WP{w%#=wNBDSQHm^ZWRe9k_~+6q~?2L`CRpDM~Mbd@mfB)AQ0`VpDuuw zEycIif5M5-IW=u53eO|-|DV4zzG5(kf`e^Rn=FO*cBQ4xdWBXGM6|-Gv&(|)=`4g} zg~N-xkpn9s-+IOT$7^W)$p@8FvUM>S7m=9h`em19C|)-2pTgfc`552H$FwuTW8-QK zgFfe~crC)=&StLyd-|0Yg+<9xf7I;@O8~tDos|AeW}&@_DRy&-B|{!1B`Rr` zX1!9KT$nAjFg-VNX@8HdW!3)$S(h>}1j8tiVM{?&^?}ru7sDK5>;%Rd>>s#9#C>g` z0T@(&TYSl(kfK;}RRF=c;a1<+#~&bDzP8W*!@%!9P*_xO%l$zmqFz5&vI)QlIQ&@5lsRX+X9Gx}VB_S6{;h z2#27#ZTQDs{88$i1_p+!cK)h~-UoCOHzAfH78dF$MT^z88{BL9b^|nJ6&u6`Oeqi9 zz6<})A9XVBcTJ%eFow6_ihGS>FF<%i6@L&^fItjyZgxDXzR;fVn-z( zHk^D*0qU%el#u5=U&z^?sr-0y!bN>03I%_KhRdRn&I_))AkN^8DFu zA=bsVd1?)NSQnR`{4VPdxjEW5{`&>HaN77v@=LATU9_U(HJgYkOg%sl?)o(JEz=^AID30H9p}>_Yt}&5LW)SXBWT9##+*d+PXHBF6joHfzdgg~e zH4=CIllLq9kE30dlCVkLr^7}6x>bB@6Ezme|5xsu3?bAWe<2y|v|Sioe28*>TSL$p z`}NNTUh=d#nGr`TU%vxoSeL(>->90O{j=d6% z?pJ8+IYJ2Sz(D>GNVQQevf;!ZdQEot{96YqY&Gb=l*-#u&UUK}R6X(43%WnQ(ED#V zK~Eev-KT>Tu;;I>yj!?p+>>W5gmbpu1=kn*9=Hu9MXZ^t?6SlKU(#O+iDibmf3Qxe zGhH2o5qMl{x6^04e>QW^1WyA+{;_}&k#3R^NQR%LA*_dWT_>7N#fyp!uOuvQRaa}! z=J+!HpqEv)A}5g(lem0k2)q7J#vmMbjxuL|hO=tzQ7jBNI2QA%du=sk)VV9j6+5=> znSTn`+Eg@^&?vQ4h6GH+L-f@eLNR$4BKKRQudypmq~C^5#^rHO79IBII8{krhuBT3 zxpfQnl&YvTWTPSg!;J2%`z7??+}Z94t7rZVT^F8U2Omr+Us~$E#)W|*4$}ot`Dq&) zttmsEpfl&~cnC%~2(X?NGRws=K`iOc?Z=GtKi+3rI zcLf%ccfnS9eZWnb-W)srZS_&w&}GxPM>w&^`}!wDO7>Rvd{E8LckZguU>&$ic&$2b zgwkmtx-i>T(^5qh+CB}sWtd5u*>7>CdD6t=d}Ni2X_nCO==Tkis0nwsE1b5@>2nM0 z)D>)V;SAPAALdu9@Kr9l^L>_oICYMv$+^=tac?*kFOoeNsiHyZ(d#o<&;0%P9|LD~ zdQnS26KKU&_9_>h| z++dd#AS@;*mKnZzLrYud1KDA{v4cO2n!Ahv-JHr3uULYxW6@ zn0;WP(6dJ$RJM4%pioD6<9S3i*Vl@gs0E6#hnf@Y%Vrs5JnflpxLXU3_=-Lj{|9-i zZr@|qVm}Lbq+X@?|7F;yE_3>9g%=zo`=yHgnxepf>}&%)@W$nd_dVitH=my)9f-V= z?;v#x?<(PJcN|ZjZS9gI%BfM^V|b?N;jhw5`@6#T4Lt5TfBv^@K@u=_wG+Nh`?A#G zFL~+Vsh7@nt4FvovzN)b&mU-y51-DK+qhuQ$a$`Hv8WG%IdX+WZS1m!1RjWaE2S=9 zswZHQeztpU*y3`SnXbb|`LsB0_><1UKbkvwU5mBP)YP0+i9Kd&38{i_!gAVfmt~~7 zXJjXTIp1d0LIW?YR@uN6L=m(@pI^#|M23R`fwYF#wl-b(>ibLP5!$J7t(9ge-rj~w zT@?{Us(?gp&kS67dZ_f$^$d3v*5+@A_~*g4js~1v^bddS2P1TMwWP}nE{v_OxTDc;!3oEUc84;qF_w0X_JFTf8vdg1VJ4U!_N~XDW38Sl@Ti3LU~0yGE+3 zt;PLLTplVkmg3!Z%KgKayR(1z;k$ssqxR?)6Uvk$%zBZ0)hT`oDc%(k3 zwR?izUCK{=!d_Znncot$9o9w*K^a$8L8_=U-9mU>vI+iPJXIt_s>GSSA?1K@h?ZJ| z?Vk{H)&W9Wck*RjoFjm~xmr8LGA8)HPrmLsGXA#bNF4LKNC>S&_wL?BO9c+`d-1ko zBPCV^|6F5)8a6}=iQ($-ECen=E9UdytZ5>5iBq=&CkW$38! zxVSMMTIwrG4WCATG2!ixc*Kb%SHyFm#g+u{ z&Zv*A0@L)KCUc_s(;xwov*JnqqNis9vFHVp3un7AV#VTW)3?z={7$x6df1Y0^pNFu zP_IvX6~4!$7n?07*&Z*paX&hF&Gj-=*%Lgw_L0`X*>jkw5aS2``^^6HXT8KyrCYTG z+unQ{gjw5!doCL|!Y>MCzg(Qu5dN~t5?hf^7MzS|{X9b#>Drio?&Hnna6alk$+^`0 zE`4bA=qbJ7C zWqCq0t&R`)StT@1b=;(AJMp_B*;SpB2WJnOT*W4hYu!8bEHAB2WAg`L-cA#TP4&A7 z$WjgGq=jiJtQYNbak-^_(AfK~6L$fFh_F3Jm>;j5IVf|PxkSGFym*)kYa+Q=T_|5} zSedOg);VSSyPhLA<$tvQrNUA^H|teqgr;S{qQ(GhsToquq@0c9Prg7%;)|{nzfZND!WatHDg(R57ZDqIvqz``$c1x z=H7Cx%dhU+F`=3tE`@%!%YR1+!y&}koASHS+;HDfK5-QgLtz_)h%R3PO6jWl-Ppx> zylw+ki}extP=Y+*c8P@itmB~hDDm4FS13y=rtsR8DyMjPnJC*8m*FWcLu7aS$$%3+ z5+dwh{4b6yIm&t&;=}~m+x)A}wn!TolJL;x)N=UkFTWl(Dh5`PJe_sXWC|)@K!PlO zGt~fo&V3k68);%OT#V^`{x0R6s(ZeuZ6cT`Oo1Ig3N68YT!mUq+{rHLxX6>P(lmHA#* z$kFcC8TM#ceQUek)d_1W_{BR7)bPswNMLCQgIMmpvqP3VGcc43+(Z^Y&;zHG&@Q+5 zD@TGzGb)4=Zj3NV#Vcp}{4=)p?I?(rGmpC5ZqvvgAzFzPv$)hji|;SS_oSL!r(rw z?KvWciM@(WIu0LZ9ZQf#Io%IXHQHT892;d15DsH!b;DfP{w{(ZyJ_ zI{Bh(uJvYqD|WV2Tx|T!`ubE7mA~HIMEb3KXI&imIu-G-6!u@7*8(;H918-LxPMaw z9;>Y59{_7;l}sT%$$@Kbwdx6drwB``&sri(EiCuuY=Ce!A>fy@g>X&{bVBT2EfE=B z32c_AGTk44@A~r%^Bk}ZRXYL=mzJ8D`K?GZIa8PhPhE;M1(t3-*%tO6>AE-(Lc`mD zPtItMB&>oj7=!&>6T- z>k&m~O{m_kYzc=ygJH|{fjBVIPEt|sqCUJ<7Jm1uzj_y|-n;y}zp*!ZR$_U!aPH;$ zzITb`6<5%z$S3XB6u66Osej+aj+^?ioJbMHBtn-uENl$1-G(tZczn<2bm&2)|8~2W z;VK9A+R;6BSqQthM<_K|x%!|ng}<2BK?DTj1nk!q?{$4iGm(I%zHxtcGk8ME#S7Bx z&K6P@;Ef7Ulf*o15h-_4vB`pjD}uSNn0!Yl5ZFy}XPI&zn! zNXc{aQGc}NM3qqD zY7Jkf?wG)f6Y(y|N9uXH4VVS@-#f^Mun#6SnP^%9P1yoFJS$MOuMP&gkrs~|ai3TM z01svKAq1#B3aMwiv&aGo5TcV}Xt>Jn5XP8e8#Y94`mvWE3A_1e{fPUAcw$V?GBcSz zmTrswhYQfSK7}TXP@F0Ut@pl05WM(Iaytg(T*61;9YXHRsj96wzxh#r(2jO&4WTJXdTH*s4%hm%Jk@pj zpZ4@5EFW8d&g(I+yB3c)xUpi8#<fg3q<1kREfu9E!2Jdyi8RpKK^&6p_L_T1LzA8tv&j)3g2{qM+KDPtv1 z_qV&$ZxpS3Buonz{<a#&j2Q8E zhy1D^DV=Fh+Vo8dZk=iyrU~u4e?MXfnBqQR>hYs9NDKGWAT@HtjYa6u|tk6lBm7E1z}`RIT;RI9-^N zuzdTP3A4ZJ-@+=)&0Tq(z|?Qm)EZWH#YgYUmVt8=*EJ%F#DvCPi3NM!UYS_L@Y?>p87|Yh^91-vM#yE=J@N41+3a&V z0pk09zJ2K6hs?tv4ArU|uvLj`8HxxOG7&4!1_&?{^qJ%`__H)iMlbE|)R$hF`OF%K ze1*vO+SyjXmIiER<^{LLkN4k<>OM3QU%73tbVf0HRWX=1j??+i(Pcs7J92h22?TQGBYCMJBJ&o%(< zeYg2x8Gh?3ebBp>3c8Ah028`#BCak_cKV5^+Hj$^$cQrGt1cp`<`d6Gw3EvpEXgtJ zKYOywO(-kXPGrsG{?a+Stw?$`Hom zDBG%khhyD{K~aw~od0qWLGP#Hif}Iz1oB4gMPr_=rhgv^ix1G67&89aJ2LOzUq6|T zlcR=ogT`!eDLxeakQZm!S;6+`j_p67cgm;kfIY1RM_$%7qo{%JxD{P-#FmJ@ls#t^ z;XqIS^>>s?Y}7;DoIlKkwWiy3MSU1;g5|(zbx`;(4yR1QU~1shJ`O+iH-l3VPl5DtGtzmPY(>1*ncb@h{W+*ozFV-46UgTA?E7(+^ zuYy-GP^y^Ti|%8)mMt+!9xpKPaewN9#!7R?I%#flikUx7pY;+#N>sF2#lZ85kI;rp z)1_&xpNf=d`y;s4`9eV9YPXRyZvEeF-D;O5%tXKXEg+Vj$-$Hx2bwL$CoAP`rn-fq7|WUNOqUG%GTs`$UF8I7MBk}rYI`&;hI1j8|ikRHO4Xld~q)FXV2nNx3np-Y% zwcql*+f=*H?P6PxP3M;oemB171Jq^x==2R5-&x@<##2gcz3b$#%k#(770C^15+2%n z3L>(w&lg3nn=?{v!?%t4Mm?#Mb;&)t3E%qcyN&Cg-cvfCi7(s(f!^MoZs#(mb@}IC z*yEHsiD*PhX}l`V_Q=hZPi=VnImOU>&Y1{7dys=IYfzFF7y7mE`x`g)E;rAS1D6FJ zbbAF>I{ElH?Wpx#c55<@dAF5!!R4jiW zoZ18@X#3y!nQF@dxsPMIO(%k9rp+?6)~^qL@S!E8{0P@=Ex-mLDL8EE!iY}MQw@=bog#Qd%20>dlW>#zXQu*R!I$bsu)8}9Oz=FIHo z7k$Yu=1!!xrf^a`M-lbc%jOdxS-ZYM!sZ5oSCQ1|sH3uazMW=#{b|p%3^P>-Fq%kU zsL8FL&8qnoNY}}>haDNfngW>Emfi$?jV(?5&h6c)05E)@W@1u<|-1R4M)Sg%6e}8 z*;gSNXn9E07V3CHDaZy|A)JI;3rce=WbzNAofg8}^P^mB*xP=KNunK?y3qdONJ#*g zSzb9uAT{Z1w@KYRNt9dlgMC1`ZN9!&!v(XY+ckJr$>pxHiWzl)8zcaLDiX&-64>#8 z_`h(s_F`)oeFykA>og>H$n#UV))QK4n|+gJiwT=oCn^1Nma;bKs`)6z!E+$ zazv-EopmudvFaaEL$wtFS2V>B9;rC&ge0akhnBma|3F zsVe{vb&lXEB=nQcdfHP%UkEDGiC!iUnfuEP*JfgemXD-+w5tJF@B{JY56R$if61LX znNI(SXZ;G`T|}(-zWn#SnZwA0S5_9;xE?h+r$W4>jpb7flnr;i*e>)bEYSpTw-X~( zz}VQp{Eo9wDq%(tDumr1C^muN*|nk@B)$rUsH$yFk6dXPDSm4lc}n+3oeS49$Y+|> zej3c*u6X?%St6S@l;2WsEbAr+_6f8l*#Hk38f~V?QYF9tK^9ztkFX@J>e}yVf055lJ|(C zX<1yjMeu9Wr=q4u8!p0mWX8c52fv}`>m{mq?W5v04aqWr?7gja{7+o#(00FXVN>8O zZR|mv6_T&HilebxQI7>TNe;uUjzS5BFq`i@-EYe#&pS_F$b1gYLR%aF*?H85K5ig$ zPjo!RnXa=H>pY-lX4$5BwT9Jw8XUwQP|GXai{}+R?MY(PFnr>^dx4&7s{I39$fo{q z;nP7PK}lKE?TnwllMvmWfdZahu3c)@|EmN4sHj+Xs1sSH!KJ`78s`wbZ;mT&$(aQ9 z53OWxNo>;e{`q$2VWN2j``)71^hqd3hL8ccXADJ3kb>_x;6CDz?lW7leiypHZtS^) z)@8XXiHs>@o%aT8J?~3ylTFoL-$^TjmsZy`<5;jPI~!0#^>e6Qs%}T)0oPhwP>k$n zOUn4rhh((AELw{7_>izs?jpo&|Id+a=m?q6m1d3(+TIj|I7>0p0E!}N;ak;edn)6p z;&l*?gC+kyfQ^EW@EMQ#ueBNz7zR$})RO_!Q3mHQxj1|%!1^vX`tK$J*2@(@i74&+ z8JxVqeczEPdI~U?uDI&xeWV9}0w5)UcPMV3c2@z-3NvD%o#|)m6!+!jBe{b=;|LM=&hq_4;ikjIJh?PeJ%tT zBQ36Ohy@mob~$r%x0B7gl3YISp4e0)d_)k1NiwO0CJzL^wtN~~9qDPl{(AY0iuUB) zRlChU=L+I!4f_F+DeG*R02G+ebwYYXwGVSTi(Ve)6+>MW#rU#8W4r=)Lq8}~Wla58 znn=jXyL&JB2$+Z(r;cA3u5MN+vLQ)AOAFM$A7EgPBd&+sO~?q-SQkiAu_=3p|JoLv zpiu3;CtYGiFOyQrA7~+_C?f%^)77Uv`>|fw*FW^3%M(xeZbF`UH-*cmG$S>b4bvl< zo|vN>C{%!JC*7(I%|%sR9RFevQsZrR>B8CE32)!tLU06L3M1Ywimw`7z{=AvIp5LS zmHx|+(R}D{w{d%Z*?^Kom?0aj)m|?kA+Bx2B@l{cMh%uKw*QTG0t~1=qrOaR^R>w2 zauaPdt3$vhP?B0V?&$n&(0NA{z<)sV`;tUSRPU7ZkTaynH)35J*JhjUkQu4j?lS1^ zxz6o-{($YgaZJ8rA4zO-5bN$lQNWC<$6i0ZN4FFsZ~8&Ej*c=RnppI8sI3v?uo(*I zUT;5KfX+2zaaYwf2(-dD058W$9%qi*vA{ko<(01 z5IYI($qj)cNZ3&`-JQY_bqJPBCoPm>_93iKY^sPB^Gf7e2Qb1SdSz_OX7R*qT-~J6 zS1FXLHJpO~C7Nm!$bu*MR>1%RT$GCh4A2~aXbBY& zRcnhEHFn3HL=jok3@bP%O%Hh%@DJ{Jg8Y_!4@K6SBRlUZp*!N46$omoGnAdWwxg}@ z&=sQmDYm4JOO(0rqQ_zb`PppmaTiS+HlPF8!LYu@U^}e$obdG-Gx6@h4RJ-l^K4V5RD&i&^&6~j+ z5yZ$zGv%Q^u5}`j@MV1|@U-6jChV2mR&rw!j(7gR3X6O}kVI!L6;}U|xhBk`atCO} zOARv)Kut;vH+6}{zJsX3x5BUV(4idA&|LA8VjFWl52RNNw8MRQ>&4dnbw6S|XS=Xz zThjQQ^7C~Qhj+hT?OWI42hKbmn&w^uN#d*&8mf{&~NxUSaaws@ee999x1bNB9arzUn|Wl$m`~) z)P2BeY=cEp`C>d0%xXLUQ7e7cE2D^Zy4&Rmg_}8A2lb9JlxRz9qQ5AE^1IA%-9EHu z{2e+frxVo5Y(v0c-VZykiON_VlaS-^Wb0=DuaITqkc-w#vJd8Y4MW*XH5Lq1D>%x2 zIWo-XbILb6H-g*A85g-^gMIyCu_FeKGVWL={9t+~LmaN&#!zP9+Qg=|8}q$hQoQrR zRfy#2Rcpu64=Tv2yDJV z^yfW1eCQp`xCMQyD0;Grh6{QC=iPP&0Q+9n;)Y&WoS3fJYNsna z_s_~-xjp9LtL%KJh}!bIPkY=5R&ENjsKT079183alZNRD(o5B^eJ1p5fM|0|JtdY1 zrU|=%M3{-yU|fmQlhp@X+r&aZgPiv3FkcalLuDcXd+Yx}CHi4!IOI+jAd12d#LMN- zf5r1wtLX3{`z`4&qMx}{=o}!-t;$gJbcZT;j>x8mpY*8+4cy|h96F`DaBc# zBn(_BZ#Z$t{e8R)@#V+>c4~_QBtzJEA1UI#*ZcDM8?*@#qXQeI$eEyvo%HdF5XGn} zC2aP`uGwA^SBD>57`I<&xWfguicV^6tKU=rG|DAUsqsw(r%T!=i13fjILb*nZW>!T z*13T6AzE(9XrC-&@H#X6Ua9(1o^pTxF8&KJmeGnr7 zaDFTv0c-rgkfcHXdqPEay)~HdPK&^&?gsZm1*`Zr9Wl%~-_rdvhkI{%{A@odxc6r% z9lbU9mjcu_; zzLK@pZHBj3MS3otLj(C}&(uo{;y+PYbc&zMJ$C)SN5tR}Qo{!9c7&@x6foCmidV$w zeJAapH3z2%IUJZHP_B$Ml+PjjpdPXYJ(9xU9xI!Vd;C$?%&x3_>c5%FsxORSfzd+M zi3TahVa|hha9%avZMv~y$-Gj}zglUdW{FL3WrNNAPjR1;FgT%*jVs!!!6R9v5wLO> zfxA^D;50QAH`t?YUVSjy!FrS$8t$lvXo~Dmx{L(>swAd3{9!-Bk)Zl8*Z%`nul-ON z6gz@O6=-L7z8R3QfG>!n(e?WO|B5NTF2ke(ZBhh?&HOblSlcYEU1{NZRRw&Z! zt?ZWuC1Qal>>Y_s<15VUsJRtfL6}g{K1@F=s$77pk4d_iZ>rXR8%749SoNdN989A9 z0`B#EFwQ`PQAQt_+`5$-MSqP)WqyD4Y4B)DxvPYt%4CztNAK0l^L|ERU_>(Fpi|>_ zBz2tvcoS{97Wf`P(-~P6Xs*sH#BmSVxCTU2RPEpBFtlLDkZOLs&(F7R*(ycHsr@1L zZp2~cV1_bREkFf%yT@mPj{pcqs=DK053}gmRYa;|9;X3=K~$9^#yGx~Ljoi80=LAb zc%1kL;N!^zDN^w=P>>R2yCNTks3aL>8wUi+RRI+qpp9B#E|R#3<)-Vy_d}*ZXb$st z@*Y|@kSN)`mP;{h}?BuH>edxb|%|&WTDIi zbJ)!LRk_O)1@U)EgpbmTa%`PAD*dBk6MZ8`OxQ%J^~y3+h{g~|DP)Pg!fEoY^Jw;r z7T~wfGt9V$!BsHkM}W<7Sh>I)oEGz_z2B*XQsIY(kxeGN+qF3pcm5g|7PVz=z==3K zT#2l{YtUjOR*XICCLU!Lud>c=z+f;hK*Wlig#?(l;=qETJ$DD+ML{aNRbN4}s)oP5 zahh;`vFe^u*#e~k)3L-;W%TY7hr%o;ni6_N!;Aq#?YA5#THv*t7)7e8uu)}CXz`Ez z9^1@kT&v~SePH}mDGneqrm0X&JLKE!<|sYAwF0wX|;UGPzkYr!sOhj%6_9 zV&xeOi@g?qO<8wGZOau7Z^?`D@GY4J%e8CjTPv=8@A2D^9_453*)g*=C~f>#Xp+wS zF`pxcv-J%GQ9~KCCPde8Rr1d5Up$9$SBQNd5bBk66T_j(iJXm{SS%vstt|FsyCBxGB(;^zKmk+Fcz`aNSngkuE_J39% zlpdSf1skdT^<*7=WZF>%+P0zbj^2AC`0<^7wb`|O0v|s=YGUpubzROS zB`q)yMk=RE`q*q5kjL6jTZ8UN=N!*>6Y5-Nr#>8_1eGrFCE(7qzQpf${_WXt)nF*o zWas6M6*&#^-Y9OWjtGydxhWa7@C|$?RTB5A#I}Lalbqw1lU|{sR{67wcA!>__Z@RW z6-f7$Wu)$byMoeca`zdFGL?0-lzx?NR%?u?qrc6$pULFfG?l@ju3p}EqY!N z+_n6dzh20-_UfB(ianZrc=mM?Zx`7vx~4I%Zn#Qv=p@{agtycT4X^1Vttb?YML_h* zkZ%f&BwK9j&(VW+$y-+btFcGZv+Ckj*Ktw{#MPthwp{un;G6bULuGIB$=_p0RLBt7 zXB?rQ|5|^JYGun>#8Xr)23M;);Er~LE3zrO6vZm-B>gj(g{%~M8TH3AN%xo7R#7rf z0c{7UYPI^n`^SPq>ivJaRHTgg!i;^FQoOtZT~~_MoJ-mtArAh~SCg%uKT|~y`>1MD zt`^SAkE02%k898Hg&Gy$#SucseO$nx;puF2)~W2U;BTkia)#2u!}mo?&yI#hUq(Nr~UM3@Xk6i=KdqR-F@?oZ-kRbK zw5QtgTv8LmHx?*>;-=46&2GWBpVZEDT*8$Y0FMa=;hcC_;gL)Y?7wFUJoag96+&^d z=#b-wQr||=H|qZ$D0?%+vBh?*zR48B0TjWykM9L@z5@jc`z|fkbYM<^F?A;B=((h= z1mihCRetF><};VZ#MPGH&uXt;ie%e>r#*TRA@s?)yO^T{D6B3lx<)$*m86qjlha-u zCSI-rAn_1mu*fqZ8I8BTy&t}Af9>ZX#lAJ@xFW65EXOzB>UxumCCL3Y`Li4C)p5dY zC@)-*%Q5@Y>b)JYWCefSt2qvEC#T_Te*@_c*!!>z|M-S{mkl*DiaXm^V8f}nT8lh- zT3fG25**snt=DtXeXn)+ZQRllDm9FvxQ+vYlVEe!F>=m!oG|?|5rZki;DYLP^8Ia(x5ZZLUku(a=L`Mpy=svCcf0ilMYI9iK$Ex~7pjoO&H{qpHtx*A)wV7y0TJ)6~Y>!0VVcs%yn> z;yroP*ZCtj%u^IN3@1qu`bXBP+;c(17#E8=xGe*BQj6Ten|Lv`Tj^*x67 zA3i4+>%=TxBz6d+1QYb~8sv@V3|sg|>2;5f`TS~tGc1KCF;F>L+a=w4?G8scC|tD!4%W+X9%3wVi9?rh0EQ{JsrkmU5&P3heOLiqwFQmtB#&{+eWa=m}iPGDr$Zo+Y0jQEY$6Xg7uz~p8w>P1^p!kq%6y6W=ea_GHF?#~VnnQ-(K4l?bJqwe0SMvLXsO zXMuUCexKx*&I0u|Cq8enW`!iuOZA0BITzX6ai4RT5i(5MU56Yl#=Ujo_wXcm0oTi2 zWZq@&xYWi!Jp3++HL_yxLLe|Y?(d!fp=>(F5!VVSw)A?~Lf2N#Q>$M{b7P*jC_W*x zHRv}9922rGw)d?|a9XHV|1DvDsPf<}&vx3Ow??XK#yWqH9`9q^brVa~>RW{L)ize7 z+$X&p<79tm^Ebtvw7Z^nLaf$;VCk_|=aSlKX_jO3)lY&>xN8R$6)(qPa@s1n z?8Tb#LSh+VuBEEId$ziUk@izuM`E1!l|wAoM-QB9H2ZKgLdU>srjM|KSZcad_j4SC zu_1WUy&hFGaY0bmF0PpnQfTh=Z~)`fsW2S`$;g|Gmw?|Y^PWA|q}MQBuPuIY!NET0 zcOBUhk7G61a9wP;6(=$xVA-W?iO!EnJb6z3$f+l98oEWl3n&P`(?_&+L%{W2ug3)D ze0b?VOzrp~B-=SM%@POd2kXOPMGvU)lIW(>4Z@{+Sq)|_;;VJ`(q zI&clf=pwcHqiAS-8(U)cB{3S{XW_dAJbK*8dViuMiJkSoj!sV6SD!uqn3LWchPDq< zWfBJeVlDyqDPgbZu7`|ZZ*^;h=g77;tP*F0otNs~39lq3uI>}m?qFk0=Ze|Gq3jLv zm!^Eh24xct?lj>i9rr|#l)Vgz6EWtDd@8i)ImF+I{ni3J%XR#OmZjXvb`1|;;c%FY+U-bNSRqb`RDCS;5`-c0&Rw8md zpj$o?E?XctICxS0dU?6l-Sz!vq`Jj;bv%+(JgD0DX|bkeEEKVqJwf#T5p7@gJDhj) zN04$qD$Nb~nI_H$@8T*gK#P5GT8luZ&MOCw1HNh&G(u&5gM9hvkw?<|jxQW6djn#u zjh;g4FQH#@VfTOMZ~ijxU}zK5f&RI#=W1hdaO%pC?eB*otCyE=`gDnBYJr`0;6!3k z1dir95_2>4oK*K~kS99L@h_7&W~1|t{=&=47)lHja@EguplS97+{q_5ITbfqad2Y1 zIL=2Ri4lOq(yg0kgKsn8F@N{JXLm|W=q(sjgIAXCr!YGOx6qSe$v_o%;R_|sBToFE z-rHnSJA`6q!u)EEd&D17;N1}MZa>FkbGClqls*%WKhO9*5z3q)eC{jMQ>fx|L&Pu| zEh^9xw{nHyd?!0@xZtShV1N9O=(-Xq1G>SSVUKf3*BNp;khG<|a0cqpy-q4^4Bzqd zFECFMwh)Oqwk~?$N~1&5JJjPna}hI!Xr)_3?frSY>GF|?aQcyHFE4V>;l>6)pnWsk zRh~du#?v=Mf4^{WKc^MiIHT+I6xJCZR_K1-Lms3uvRR-)Fpgp3`1$jMdDV++?=$D5 ziH;f-xU)BGZk5wt!@+*Df$0vEwV(DQbT> zx7BrygyI#0OKm&UV2Ymf^%RywkDPrHj_oGpE6GBCV`eU&ZXb8g{c|$sfVKV18iwxkW5HKO)hps%rHP8{K*{ zp9Te;OA;%|Xpn!$3|zsUQgDF%a?K6q15pJL1zbuK;q~=-a%uG@!p$p7_XsK0^?Kx= zio5VPcb$^iN`Y2&jADAp5EFjTaX~u>cbl0eQa-E1(!2Wc_SIv(ZP~C0lAz@!=#i>) z9SPWVx#3k+SOY1pcyU2K zq6`=5bKSg;kRKCXh24as;ejv#g)iFD?keV`vVAUJHfIK$%#$sfIy|Fqe6i*P)pDVO zbmrALg11Uzf=1OTqrzv;Z7nQw9FJ!Q&aqgzw1cPU9z!dcGdzdQV6Ul2xuo$Rd(5v0?h%!E32)AWvUxr^XV_0kaosmc{C%G>8ovu9%q#}?D zbd_(_`uv(M4y~eO8FlI{yEbT6pXR9vrk;(zBztyWZ``U|FnH%jR>Wv#DK5-!VweiV z2|lp<{P`-PeibhPqF3CZj9NJj9Gz10@Q(F6DxhfN#5R?Q+Uod-dW(5$jRyDc*X9qc z`s`)KI)k&Y=UwEjBqmt`XYs7-#3rj~|NW>o^38CT!=TFcAoD%iD(1nSeBS#WE#8q^ z=HZ3WBX>`_N94mN+JlboEIBQ5#r}muqd4dn^DEk?F3*q|c)}O;1s`nP+gxR5FZ;(leTcS+r3Y*2i# zfxZC&>06PpHqb1{oM%WhFk2=%v9nOT}X?<~Pqr;^%X~pI1 zS!dc(MvlJOj?d^?&liCS(=l9I4EN@0qeDZlUyOrriE;t6KU@h7TV{Sy@6i+zYHWI) zKGlU^GZXzJsM4BsP#da<;T4k;9dM!#iAk@7Ke{CI!SP-ep>7|;rgdY};GI0=o#g4& zX^0*XW$!qbl)W};Z`g6A(RUFeXQYh8DtwqXvc@?)jf$HBO9huAOwKyJ16@uG5W;cK zz;$rt+2*FFXLXdF90`h^pqkl~91e~=5TUd=y}9l~NJ)D&;6E*VmI=*3q*<@@s^Cq* zIS!vc#}isig3bz1ec+x#el;R8+1B2PdwAK$Yg}PruibNWMnf0O$BO_w zn0`q-8F$j}js|;|9ao%~V)TR{7=p!THa{Q8fbWoy7#v9zubDWs`TSg7>_fE!hxKZ| z1>AX6H!pK}h{p#O?+6@(JEDDg@7qn$T%ejp+PQ1MJb}IXQF!ZHq>FveB~8c>&sGJh z$dc(Md^g(1>x>`A66&@wwa+@*e<6Q5KMv11BEp`4u!5D2r3C)2MEi|R$D8(q$xT>$ z-O-3pPMklOeg%D*@WTMkLK?VLg^!U7$nv&+$LKwf59O3Zg!X?e8`LSy&n3sn(T2uwtdyi&yxSNUU3IuITPif|EDi$V85&`0=XT6c-9)4u zfjUBK*(k(Kf-fJ6KeqX2AKw-6>?E;q zrD6I;NJ0cI@9XDtk8NX0@j`KDf)I^wV%Knug$(8z?y_hV55(v+Tvdxlw$W$`zeKHG zm}Uw*aP7BEpFanY4bf%6<(XM`Lxrj0Qt)W* zLsXw46^%9zWD>acE70OYGGNiPh67F2?_CT zcS#>y!R}nF=^6G3bdG)6M7LDG0+KD&v5E)BgBt{R!-``o>ITh{7jcyFXJfkSJCSCI zb-q6i%NEFO(;Y39EBVV*Nvwvx6k6-BU4XTK%r9yNrb-er3J7gOhc-AB1q=F+jm6#4ASo)ZrN2;e zT=E$Q2{!yE;Va4Ae1eJo&%afW8vOVD9UYKKm3ti0i9%?>~UB{^u`JK6I~b^`=G;aBbKdz3&2#B-*i8yl<1 zYV8_Y(Y8gtD1a0wB}fzRu2AiPT4u@^06ScO9ff7IeC^`2U?mB(sI#gJ1X{Mu%A(QwkmN`xq zAb*EhVB`O{oVzyv7xi=bTJ+CJrN%(mO{3mciE$L|fK>5pd3F^kh$57O|9Md*NSvX7 zPqA2`;fL8rsIde8{n7({ymjMz8*x}!KO=3w@kxii$yU(^PSw~pj!;{$`FH4gBX1>K z?F8;`5;h%pAq}#LLVHf43d`oR$de;r0g)yz{RH%QJ3G9&X#^er@#lqf2!L4F-c9HW ze~kK?k15NY+DU7J1g_||Sp+-woc@1aY5H}4D7IfEH+R(Jsvq3P$m!QZ_Q#eIt_Y`vncQwOO-Iy3$EL;WuR8#j;Xq14RIf)atr zz5RGOXE2W<7`^5Afl<0}{1i%5|F2i}B40o)RpS4@)Fuh9P#K`S2`UFT3#D3iQd2Ab z+n!VDb6)?qbwO)xDZWH9AG<$F9acv%w(e|C1jVWJVlEXz8lYB{{415B(?t3s0sL{= z*9PQhExq~k5WsQ#G*31x{bvk>tWl0X*}JKl>e;(_RN$6RN52oguHm=B6AzSDRa zNRWGA%ef?dn&;YpMelN9{D=d^N{*~qE8Jxt)QVvyb}{7ZJN{7`|9m(bXRq-c1ThnT^q3I#lfwvZBnEjSx4NH(Ye-g3P=9O;~Xrehg!_D{kEP> zx2RjxuVpMcbP?0#`_3WXfb<2<;{(~4jxQ;k>_(58B3?N4LJbTMFRGLHpiKSD$(Y>o zRD@rGq(PhN_Y^FgY8RB850|dWSuf)fFlyV$Ee#Zdto}AYfxBb?)zq(kK87pqs06e@ zE>D_^1#m3M5M;d_$)b#Yjnfjibu1<*;Aj)5>*9-7U(? zpFO7po|Q?Bc5K|hIuoWCxC@D=4=r0=O;AU^?=}I1o9XK!6r=J}CW2)Pf`^?B$5gnA zxQMw-cX`|EaeblNQq~;}wR%lj4SI|2a?AU9n>1y_=!cdi*rrCOsE?No@?4>)bj=ZC zO)n8Hs6mM7`0jvG52B$xz}27d@;T{@>|coNW1`PPk+n0$g^x`Ae!;?F^TZfBiPlSz z(Y{^}6XuUC?;C)Z+t_)%JOrr=DPSPpg2qzY#6WtS*1YQ82qf%j#Pi_KfzdIWiUSA4oV_WJj>v8hW^7>vF*d=+yG;`C;P3 zpf?y1Qu45)|6hA={z&!q{f{41D#h(8Qpv3j8WbgDh-RILN`?|nS80%$qzuPx(5#+r zC?ZY9&|u7P8g&vH3}r4S3L(mn>GRmnr~7){*ZVK{{_yp~>vemc=X3A1*IsMwwH|Bj zy}6^wZI?2id-yepIi8WPOQ-2eeP2=kth9t@gDcJUCh~AyAsoA}z=KLPfq9J{kV*}3 z-4JngqF(CDLIcLF&LKwr41D92$QsIT|63NI@>gUhW}JwfWVgX@+IJId{c#`fI;!Im zT%{?%X`B$7o0JYKWIN(GBy2cJdRb^hJ77!wiB7DYZY%dwqgmQue{@5j@{x^~Zf}g$ z%3Ka)=`-Krk#>kXxq$B|+{%rfXK^(8mYd!pc@otc%WiF4bbY2Y!h8}r?V^LY+4J7o z#HHxhXlAeN+9HBH8;PsdVOm>RGsfhMf3LJm`K39(DlpjR&&`x3!njUPF%M3qk zoWtC)62jEF-&}7eIEhYkq3JJt+@7KuaqCfSQ@hCK`OG@swrtq;%dpD|u1o z1_m~2hKSyBY-H0H&B-GPXUU5Y_`^lQUHo;$Fkk}`SV0t7ETizGcD`p`gYFX zIEU!i_r?{XQt(nEQFImqvd9_R;(_vic~mxv){jOw@C1>@{)C(B!&oV!YNb>picfVb z)!Ufc9`;HHWfO>_a1PO@smSRsl7q()ZYSjY*uOo^0`sTdv6$=QX>{g}m_92ftFB1T zX*Os2g~?y%#F;h?n&U|5!Z=e!xQ681%R|`xN-dQEpT%=f<{t3T>-?$x_f1?}|LE|* z8O4s{T&KD^piOTGfQC8pFk;=J=TU%_S|TD}um%fS4brMOdJcHnypFZ?a^wmIGk%P% zzeF0tcC_p{^hd5yO$N-Z+Zu#)80n@I8^{(0&>Kv4Z0^ zxBV`>HK#IIXHoBc9A6nV9c`L4;}O@{QHPR$9aFPuGQjjfS@T71L_@HxcBQL zH*X(3Al^}8ZW~I@1mf(UNwn|%M8jt@J8;I7oY#zwBxHYqsdpi*(6(w&uiWpbnZq-{ z?}&JQ5q96h^hnN-)C=p5jx?Bd$P9*=q(j+Ed4)7|DU^Sg-*Da9;gx0JQN7D?nuv>g z#Pi181htKxe*m*Ly0QAECIGE*snS2YdXOTxrvE10T`XmKpa)MK+00qjw{?Y0{u)(U zGBLoy^`-9}(Y!G^2#eH#f5SH-XO-SO1!gX2)>4z<#sfpd)5dr*u{7!>n;?a-?q;>`u#o z^l-GNpf3J4Sue;D!{6wYFAj0;7=1B4^<}#&{V-El#!&~YrKwj8mLdC+dtd za2lZcQ;6zcnGcl@Y?88jcbBpH4)7GKl-ACn>-H#1j4o0VcB=Z{rKV#8xQtGX$TjBR}a5KqQ=Ir|`9~%^? z+r-V5rWHx6+QMhO4#%T%Z84xdlrEOF5uk#3PTwd;06zjH_bRA1&Yboe0Z7S4Sk_Y~0k z=75yus{Ztt(mu83t$Y5cP6!+5mw5AaVz+o+kb>IYgf3oC&%?_lZtq^n*;Wh%KdF#; zq@B^I1MKrCkQN=Cbsi86`M4l#Fwzy#75&=La=vsp@6H&Dnoo|;qSrm~;Mr~U>FYmL zfb9zV8j0C`jBwBp`Mlus&imqBL;@PVj!H9+)p`Lq_9{+{*=!&tiI}woLWyjlr*_BA z`nERs81ELpPNe-wi)0fnH#lz4A*=y)xBBEWrBn zXNc+BRgm6W{II=E)4T7truu93uRxKW z@HB$2B&8Sm>t*t#yBgOH?TK9a_kJ-&!6{U zbaR0ST!o5bm+FJLdqnyH2%W>@KM}t!chw`elPt#Z57%B6cG0UZw7?SQ7)?Xjn0jCV zt1!NfA2kI>H3L|8$MDX;*%;M3>ins9^(lc`fcMTo35rVtYE8Pr$GRS=zX>}9CkHH# zze>Wm{iq!X6Ac!(717gNwr7XGXpUU3^QEws>-IM{Lvw>z(WupVkrabMk0xSBFa+;< zcD*z9&OZ3-*OLwOwi|fy#2qE207pavq-IR0Mq79NrF>^DyNATx+Jf~BuaS-&T|6fJ zob#LYS4H%$)fJUP!aXic-Zv(4OzY&D-*Gm@8#rJDeg$pxF0(rj>4SU;-cg?T)ACnU zQn+b21#Y{a=h>x;NJi`@=h`+undS#a{E%t{I(Fp@#v)QTdge4-*2b>qz}Y@c+zg7@ zB^kfOSM#+QstKjUH6re5qHZH1FpZodGW|8lsnww@1>Bp@e57kW{ zQ!I86_5N0V3WrcG)z@lCQuoMxlcP)boqUpzGXOybc{fprgL;;;s7Vm7mUkF8XWZuV;F@4Zk2T>s_ic%n{xV8(lm>{}>X z>V`(WWi+aYWQ(utd(t%b+l1;qnG{_SYmo>s>k0X_0~Hlwimqh~Z53TdyJE7nOnUSG zD&2dv_K(s2qpKHXua$OFN{x=4T(*=TO*rsCzUJ);yX4N!%XD-@UAeQb9CXfHFovd-n{VzhpjWse6Rc?)A8F*5 zZF&EOR4Zyg9FY~^VenEr#vYKadCP4Q>p%4FFT$9K+sLV_)Xn&xV}OBf7Vr4AMnh2O zYFzzy4X=WZ?Kt}vkt1W+`-D2VD_8kl>L|xGsBSY;y@4#^66XVSg6L0f0lY=4ah~wV z4H#m&2*!(QkdE1C_``A@DfH%dxf(|%E)1-o;VKS_&;h#O+#JLM>-?TwbEt|z)sPc- zLe4zidwI`9Q!n()c^gfHpYt|u`J_yg4?kX>3G z(eUllEZ2y~O$rqa!imneeRSM*+R_m;JKl#Wx7~LbCZUFBheLxF`%kRC16@JxJ00Gt zLH&a-=R>zk?1H9X4;#@GZ5oV$vZA(o^TE;Zd1EgBi2TBnu|6Fz3?8!Y(8n!vZu}?( zq*N?{BDj#5ljUE#tFAv?I{h4ZW00=xqt=nU@3{8{*{jdp&!MX}V?K}-ly}6?`$4rW zKW}9AiKRwZNum7tV!GJO-_W7E0rx&C#9e97j?F2ek4e6{*=M^aZ(0i^imtetN66ftQ!Tq`g_b8(sz6E z|IWg_wRq#E1A*FcodYnF#y=fl8Yf*jOiwhmbPWCf+mi-KJ-F?W1UHXOGwxiXVF>C9 z*&mGyue<>Dr9Ib&XyGe5SjUYUOp~8#fHK_qcrA{6H*!}sNh|_c!4*FqpVcR8IRD>o zWy7q6BRA%H+z`9{>fHa5gWmeyXG0Q{ zbXJ*tgCNcGSpC1_tOmq)2ke;^+x5Nj-DVvW$6_2?)QMApQ|QxAVjnY5(C2U!%lJMx znDEp5`mhn%85#3kdOOg{%?&uH>xP>~M~;mAQ{L zD^IrOjr$%f=8!Bhjg2GISdHV^%YibpXH0>X7@Q^$Ayulv%p^JK@D9L9&KHq@ljrx| zHKlQD4jq6%OrD!V6y>91;_f0g(P`eixyu{nw?MHF3H;|J>}F_e>4Z{Dz!tUefOAX- zjBVJCOQy?wcf4zN0A%+1Rj)$*r!OZ%`|Ro;jxdl><})9$VJWELyb^d!7hr8~9K>oz zBY6LqneAuCcNFa@!iG?#Z*?6GI0D(@Uq*&l(&>w-p-E&NB$~8pvxnOh zeHXL4wPSFU(;GF^L(mugvE%y~A+Tx^TX17e=^+9bA^TU93rVSr2A0u#T^R=fmiah*$W0B}a}(y(ip-cK zKPic&&)jgwI3(24@yamW-%)3Ofrao=9A`@CWGlW<<*g11P#^-#9Pdru6T>PJch?{A z7-sTeOcRdN&~gn~Z%3}_0_Dsw1}W-D?q`}{zdXq3rd;K^+r z@}!~>FH$mel{)9fr?l8gxRV-yOe@4pM-?L&zOO1~n$-C=L`c6!SEzGtxMOp{w6E1j z_rW!)M2{(BW=3Y!|A0c=8+ZM1GC|#cQx)g#J6(3YP6J| zY^G-Ro?}CDhxYx~`_W?T?pu`a@5jxQY3nY9MT-MRlc~A4UaWqfxosZGoV@5r8mGB4 ztHlo=zT;2N`)7FA*n6`Nh^8f9grCoHn%+>(Y9HO5(D`<;9jJf%g1IdFttV`9v{)3X zo!9jS`D-1q^E~!o6Owel_p0FdgHY|>SsnN0tM)TvxJ};!Sq!k{_e|y2A_vDD9QF2R zp0nxTzM--w6$#b@KNaFq>a!0GT7qZBo%v^Oekb6KI7~o{s}}3wkB8fU6f9hajQnN; z>+fpZlKMz%4@F#8lb=&dZm4{lNeqayIZ!NCxA@Ss_j`IP#jG@M*L5zbFa6jux&AEJ zJN;d|;=Z#qAfw04z)lIBd#HoJi9F{}{%90fusPUUD)^2FYBA^5&oQ^vsYWQq!O1~u zIlr?2Mo8+htn__rl+#b9tx)J42iG4+mtvtz}E1y&>8!~WN==%H5lZUYJL+k9v9%2D+ zo`cc2DTjdR_h!dz$y+m}GbT*j9$v=x27YN5-|24d8hq0lzFqBDaz@6iYyeSZ02rwg zme<=v^ui4$o;~ua3l&9HB9ZF8IMf3g;j%6qTYr$ABCe`BV8E+9S(fUb*-?%MN8_NP z0)QT~b=JL&#**d~D8ZA*c?FyIuzG-%qyfEnK&qa*$E05$`mN$lZnIulcH`2rV6K;Dt==Sip__BD3*n27n(FbAos%{R4+@6CF5L z4kLOUpEGXRC@Yyr>2Fr`s8=7d^E|n<5He9`hSZa%wK(y2_t0e@pz;k(C44MNpqseS zT)b&1&cjmXW%Qk0J8vE0=ihs^Qw=@OJa1M9kh-2W-VmAP5Sc5YP=+bJV{PYUE)HPT zisaxDJyFqN(Pkz*(vnHK72AwyWrt9ERM$ov%?_B*ml*J0S)^k%< zULrM{GemH%6fpnKn6-x5(e=`tOHIZ-#)M@uE~7rW&_`nBf09S)luA0W9QyZGR-9+#!Mbs#h^q zgn>8bH3}wh_FqJ3DiL|!{!^UZgk`$(-o_%>x_`Z{$b_Yj1E?fC%y)#vypT0u)E!rvzB70ZGU~;PpsGTABGv!ExUB{1iV7^`sKL6%-Vr3 z%R`|#R{oPqzhQE65eeSG=`nwViS#qIh0MGTV6llu#$jWiJy*?6Bua zsK<*q{KE1f_NG4oiF6?lJ_`AGDV8dQp&FXfAvQx=`PyT}TRY)ekCTiD*y;+2~nqCBW=O6d=N z8y?=EpL#dVXO-93r0is;p=AOW3-45W)5S`nEEfOp;<=(K*UsH3vJZ*8B#e4CucbMY z-Cq5^QZG+uR5@Q&u`jWCtYl@pP1V3YuTd-(OU-V~THfgUXmE#;{im8UX5}>wl=p!H zPPK_Tqb#;nXjUlpyou127GMJUPJ%wA5QW>*rDY2jU)~XL zIHUPDtKBwLzDj~qoD*dWeXsT?`W#z42_KY)Nuwt&dXnMPM%=Wld93BRlM)Z^zhP<_ z#Gl_X@q~A=u(GM)v|0Ee7s~LUQ`fWR-|*eF^Z4$WX1b=-#?I$crDbdGa?=n6T?7m0f&dYHee;0elcjE%WW0IZpqXcoiSf*(`Igbp;htF!<(j*{sy&!$&_Bh2-c9>=UiapBhm)agGr! z39Hc&@7c~xqvm41vo78&6z2M>#2Qh)J(&i-c9H3? %fZ^x^;w$ap%)!$?n!1c8@}jVTDByU+2rj6T^!H!|UC5c@>`S^Q06&

l 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%0Aq)z;%1ve1#T@*fG zo2DQfh8~$gOZ=G^7SJ!m;Drd`#>+Y4p=DjxoTw@?H?u%Xsx#)6rIHJc8D{Tc_oX+> zI5fXv8&swh-C|xaktE(EFBbuP?5@t_<+ylHcb=fGd(0DEI;Q07AliV}SPF$L5l(xx z$2>#LyMgWWPt3{J0ngw~gRSc*EoGneUJ|>LH+Ci^JNakOJhiyGl6+61Ba_ZONI{f7$V8KU>);YV)y1@qa+JSXO)SZ6?;0hqAG$ zz5Y4^muXYTm)Z1}#GLe#A7x@w_5Ae(M(4mXmfG?$YgsIrEiP($N+FBC7eAY)65XV% z&3F?Q$H|zEzr&b}-PcjN<{7CEY~N3x5O9}vHY@@ic`)O1t1Qij{3+!rv8mJi0lpZ} zE(&jV<1vi)Ok>t!r6tQ^pyk_zR@o|{qzKbP*X-WLoWh+VyPShwZ4?r z^Y9lxYBU7Xj~tE39|pPnMZFRbzR#G3#hjtpg3V)zJ^^96*J7nD?fM-5bh=F$T9SPFO*w7wf2&Ns zfptJCAiZlFGaieu!XscKFR=Gmdh;s|nNmSsPWKtVN`_|LtF;(DTd*KOw|<>3a2{st z*RfEs)Km>31-dQVNrMh}XQa1_WR5R`PD3T1eO}_e(uRtC&uFLBY7LQ%#*dddLtb8^ zs*ml#a(J5|5f}qLYKFDk(D}Goa@klzw$Do16H}Q+#Qc7D4m+Z3lIw+`)i5Du%rC!_ zU(_K@F44k03A$WyNu$mMbiA9oo`~qHw^(Oy>4+ZuQgGzx#~Ox@o3U81!cSqyPMoN% zH6jmP*Hd;Q>>x2O*COho;OE8Ev;H@=rbca|1BNqv#AWSz8ERE6!qC=<&XY>F?c?(@2phiD&_RN{A{ttr)jaEAxWOlcEsyXYEI%D zu89dGpr7{lxlv>WTg$`%$DPkxF0f%{Z{+D9o)+&oG9C)NoeVkE5wyK#_uOgYY4-;< zqhVIKGTpLU3ER-zkRMqSOH^q8mtzm*oAKynHmiUPynvP}{* zE7CL>Im^oDKQEB~U|B@bL}w=Juw)4REZ(I(WOB3?C4*?9vn=jsrsK_CEES&P!*p#% zZ|~D;s0CKUlDvWy@FRlPT^lPfpdlPSiT*Gs%cxZ&SPaA18nwB9(H&{f7NG!($!q~m zN!;`btbxce^Jp^fUK?RKD+%!|_~3=!i4z0&L57}+^1d>WO$V$Pd7`x{Lm!aE|4hxo zqqAFDjW|GU&=Bvx6aAs!KcnbkJ{_7TP%N9Y38n*YvchHQKJWSI6wX^)4#WXpr_t1^ zPB@)JyEiOHj1*$+8>hn>?>kGN%qW&EP1|wl(@8gayosp?!K_9`10utOFPq1Pt5;kl zqp+ag++Lw+si>U@l^q#9t#FomEX4Vdx%vOrD!Iwql$(%Va-(h0D@0RpkbbS9Of8{+ z2WX&=pF>YnNV1b8+sE2V{FOkC5egSFHMbw7#U>ryN#!#uJ8d!4Cbk>9J9&+I^}f9O z)DDnpwSc_Z4Hs5bQ9CwU%%Qc2ZekNHw-3+{f5JH`hXF$v3l*xx&dSyibr6;iXHyl8 zIMQ}ttEZFth9z+@Xl^z0$WsI%EdJ7~5PfyE4V@LVf^MQ&v-IjEp;_4^wcRA(Nni{m zZ6fw(r+-`%Z05OmW$Vl+JN*yOak4=arF>iG}`?Ie)5P^myu~PMt-6KeoD4jcfAB~rhlzd zNdr46p!57ix#^A(z^2d^cM=iw@KfK+POB!g@oX|xMt~YFvmD;iQtaF0HLCS>A<{d( z%<4Lx(5n6}t!Rj?n$*UV@AaiD8S_4yUS%8uE(*oSl5AU=R#UvjW zP&p%R0lmWe^tP~@wi@y`9`XnI^yrEJNnkxfHqC=G$xg)^ zJ6|?S_Kxx2d8C&FUwJ?bp)QAa(!y172;68NS;PT!v$)PsSv`U2R&V}9Urm7r)7nM4 zwZvqn+KU8dd*5A}>@=cyYl)?}_Shq22Oz}CBVNd|!HA-xGsQ$Cs*w=lP|-qzhs<$A3^yPg3uOmvsd=9m)ySJSKIeE09 zDq3iW$y!gx0xA)HL*5sQt`#q9hWnt+Z1J zONkk`vOrFSmAVNIs~8n|mE=P$9zP864S?b^4(mO4;;v2d)yP^-rOWf$25ywB(G2#pjy>UMfj$3V2HSU~VHc91HBBht?7!eF)3RZM} zha@;5W8tEPyyI?UH?xo5a@$QAdOLL$(*ds46v8T*%I>&c#AaqSj~_oo(l0w5`aygh z3qUO(Dr5Qls8HdyvV|&1g;Zp9TG0{OpW>DgiMJYGb>mYz+sA>VT8ua*$gbv=&BDj2 zr->4&oI_Nwp0ZT#JJl>B^ISGW@491z2Sd8K{1#%k#o@LOUXI-4%Rv(#DR$i+l4#_8 zpgBUKyXbIX4>e<3&8kzu%3oppMgmM7qCG~5a2E^&7E~3YKTDU5o%Wc`?euK6@Grst zQMvOiaZ$c55a)%jic*w)&eD1I#sacfhuXre^P%cYJ9|G(c4+Eko3>RtFtJ_BbLNE# z%`oM@i)>Y-dzFSvDe>NJxbbd!ig}QK{gD(gLcenK}ck%(BhePb>{G8;bohu2{Z+~6na^9g7;sg z?6a0q-kQ;&x{f4TrDz*RJY3)9gny2);2$t$O7CX&?sEWUezEhB4_(XPCt7qf3!Uta z{)%JgUqpe0c1xpa$iV&z%@G_`3&1ayYq&{4iazd?ta4xar%3ajP_`-rL4lSN-cjO9 z@QC7oOJCU~M(%}p$HRfL1Bb+DVc{1OF|Hp2o-7Q}namtGFmXRj^}vE$%M{1Z-p?^WYrF_RdF_7-hdG_4>I!raC6C7l=Wad#$+{>e)&FLj$qea70%?eb!e1) zbNI14#l(FjCG~kh!^a>jc&NB=_@Mz|=1n2a4{tPqL5$t|eSh-N%bawB+K#NDI{8rH zTehsSoKwI+Wr=EgWg}m2ScS0e|Nr~{BnMtS$!i8-;jx(hHB=GX(8WN@$bBP~m|@`m z&ErYH@H4;}^IwqleJ&Axt|CmtoRI1{g72KRaDmmKCm%b0mAKq3Q1#kONjP^*$Zw2> zCOZtz%qQRQAJcyMR*3Da%M(r%)YWUx64->y*dBf`H&I?qg8ZHBvp?r_P%Dhk6hIS3n;z#?Bnsht0+{MxnMmu zmnRF3iazN|3w&%ddaKmu!Z|;$c;_$u5Mk`Y^bZMi-clxl3>p=j6M~C&t@l0PC86GP zf<6331Eb{+*VX2ZX|Z_SBR?!JDLZAuqvx7V_l?hOj&Pf@;M4}|%UfJFUR^)GQ0H>x zx~dIpN2eXUJ~cw=>E5#s(!}IcM{DfdZtobj{ahLQn3aZ^YP@FVj0GpnEoQN2|E}@k zo9nMX6#}J4OSb;h8*bXx(skL#A^KxknCuaU=&q{aG*%mm9$368`OFQzCI@G_9p2$I z(b3b3YLc|+3SN%V-w&af)YVH=dw7xfV*Ah^h4V z{gWD|gn?xX4NC?_N*sL^@CYC1;VqRLbUl3jMnkkq7=N45OaiZsPu@mxOhTA16w~vq+1f@h9EI zimKoMU4d?h9(u5fjn|4{Zgre?35IpuLW*edNm(zp`2Q zoxh(j+u`=Nf_}xXA$n=q$DbW?qz8G29z-~SGq~$2{c{4S9=6X0FNrfAD=GD}AdIDE zPz&cwP1?x-Daigmjc-2x%JI+oW|;qg7#MY86vG446_61aVw<8C=}lC$Q11o=m-Xrl zX|*tIuy+sT`-foOvw1*tm3(qHlR}wB0tBQ!tMu2?)V2R4C|l^NtZL$(%>4Gqu0w>C zUK&{Vv_e(GgWkJFY5~3j~Us z^GVKuN4^GA10An5hM9@Z^d|FUef?WOJE<3xN^lPB|I$N6>UkEOW0)M%h3J8|@O5{? zVovRJ``K0B45^%WaOypw%$meXsSsy96+wWp`zkL9UcCo5kWyEbnemr*iIRi&@lHvJIAa7KJf>>qFuyzTf0z;O|0}DEV-` zB$8glhUoc!xiXy*zlV(%;nYu$`&O`=Q%kY}-Cx)#@dVjnwb8S#KDdiAOPs@vmIW`S3;8!p>VCJMUD&yrGh|MO z=p8kLkD7&DlwOvO==jK*?uHw5q|0j;Ufdn!;mu-AqBv_-ZY4y4mkR6M_faQSaJOgH*$PdN3?9{M|4sTPf3ml3lKr$)=qbVjPoc z!^Knd0P&le(iST{uF+m3Fk)chuLEK-tQF7{L}#B6>ErUN;!B^>m|nJ$Udofc6+EGG zlC#CqpDyP3Gq_DCLAX-=4K50wHjjNjdk?fJmx-UZVp-&A?C*DTp*)ajD6BR>LWD+E z;)$fT{Oq9yxL%_U#Hd&LA7FksMgQPs;l(--KPM#T9?iGVy`}(g`CDMZPO^uAUZuak z!?}Xd#1k{jQ*F z@ScM3v1W(%Qf5s59Mb;+$ns83F)$xFA7>_MLBeM4&nQZ`6L8iXo2p>)~Ji4$E{6fF;yq_dHC2w zPfse}n#Nu{h`w1}MJXm%#Qy<AOJbb& z>uEe+V-=JiDZEHepV}TWePxFZ10FtE0KsMP#}n020(S=Qq3?}L4Q7W%jSNZ!|F%6JR8FzbdB2erj2N+zRc{FBioX4vF^PsDOPW^Dt zlWCRSM-(p@$mM7naORJvDeMYwW?5yn>#DU9mqwaokBkc%Ok!-2%fX)qy?zwiCyKFx zNv44pPndAK>vc2h4`l|5uO{s%!Ky~FrIOoNMDURKB3-^)rZ0F?Hfcqrm>8*+RhvYX z;-x#3A3H45%u@iDxLXL5_f1vfdi44ejAR_$`c6Kt==*ZArn1zOnKvfy^ccu$CKQEB z)2&Q6ovO`rb&T#xZSLbnB1A0yfB)U_!i;=yf$%Jh_ES{Ny;&JVa7KpOTDzIk4TLg- zVF~@|L+@Q)EZ5(H^~i8(f)2KyY-ZK}K?E0bMF^@Ku4Y2jciW)XQ zMdQp++vFB;yQ-OrLl5Goyk9PRI@O0%!-CEogl`8+u8ocO97^=k@P8jZYcTn5cUZaJ zt7I_zj-=!M|tVQ0u${=T(^$2u;E5kEo#cR=#r&0_T0gi|cFS^t^DfB$6A(T8 zxx#aM)1A_Xs)-sI6DzD1C?>l(I=+p?G)Xc|e9sA|H??~(L~4qz1Gm87d1X3<5;S+LU!P;Oo{Hhj4aL}eLT?X zp4@yWfL2@{t)HNn{}&Nu7I!ou=G`w>n2}O1P9BqF@*uMjUTzptjekr0IQ5_Dr%@E8 zrJh9_Ig5}q9o?BpB-n~poFCYefK5C25)cP*T8$w)EkEzDhi@>Xza*sJ#lo<@^Egb& z1u03JhMHUWK6N%3d7102u`Pg<@qiUhs$GcJxpTSm#?F?1TfE*)R7Bz&u82OUs9=_b zVlsvWYMw>W>^@g7aTWeU#;&xH=ZOdySXR7YrZ9EH{(7^s?jU*6YQMSyb-&;Pi}~TA z*y@7*L|yLlTI4zLXG8}GcO(*E_vu+n9Yd4)YsK%uyN-SJ+yCVXQyt13N7DeB?r>@? zYDCmM{h6hS6hCl()^11o1&)C?lWo{Sq|oBPmn*7DS(!-p2>*(4bpH2}RdBpaL`}M% z%3-QVLTTS`W;>^|45_TZo(VSU%)HZacRBaVl?ZAF694M1BfSy`o9kB_xhnt*_}vo1 z7EBAkVe)(@o1fVfEHH#%9o>ORyhXRfC&ppLU9t9)N1UmM1Z%FC@51DRL~Cx4FEl}Kv}vbD znS829F*wvrdxZ6pr2C@pE+Ir^$LB5(RM9q=cl2AlB#Tuq>0~hUlbs*73z2`)hcwPi zZOy^*|bOg!lrTW-jBAJ)ebuJ3ojW!H{-n9F!hA9ab zMk{`>s}XhV5QlFx;)Rph7Mp0(^^jAX(#F#`)b?7Vf(d85={P3~`;+X^v@3XT~@V?V)6msan&m*e4DhV=_oHNZkux2F~$gwhQua<8tKt6%>$dIyVxm z>wiPdzT4^wUnVro>>;c0fy;=7FAJkl4>T)VU-0hiDNvi5OLW$n&_Lxt4ci{&u}fxT zH+C^&@uMl)vbq8pVKIN}9@=?2sk6W>cgvC7r=Kf-wLmBL^G);8v z1@AIgBuhn_)jayMCQ|qnuQ3I5;WQp$i&Pq9O{VEK+d$v5sGo`CzWM}#xvw4!W-4QI zR-{eMS9s zIJK9BnZN*=Ubg0_e>Y>;v7f9L4$0pNf|Pyis36M>wdo2QI$uG{x6lmv2W0?@!W6aV z37#SU^Vo+I^(UQz`Ai37zrl};68=Qg>b!G7&ELYapzhYcV35ZT1`n;H>`d-u0OfEq zr`|yo)-crh6Y56q@BcoIGvr7$BwD{elpi6KgKU}6-ItQo8*en!kYWd)?wRl2Q~S4Y z-19YLIi{;ev zUpUbp9QgXRY*mxaD{R9lO{xB{RWP6JObeO>tl%9*5VV@(uOYBcu(pcOQugVCh1x+A zcmUf&Sgg7j_+%kDDuNP4?d$0$rex0+V0s5km_cR{fvmoju22Omsqam*jFOi%g(S)z zz)3MQnECzy_`qu0Tor6;+?mZ*w#Z0zj9%{!rbp9Z2P^#v4fY(!18a44+qVt`aq_lW zKk@s~&oSBPPSMG@Of8}lt|{R5R;o$4?=o9TrTAl%-y%W2NoO(?E%7{A64Pl!wEyO} z0+iP435=-flx0Efo@=S-jh*M=5||g@B~}$(V33S~`*Cb93zb9kt}P1^zGNFj3$LT8 zc&4dn!W|Ae^rZr>0FIlvCG!57fD6Jh&LU{sZKm2N>yMqSXHUvPH8zfb zt%T_>F~ke(00Z5IPYn%C@7P%j1qC6#9sH&cw3b5eD-3;Q@E)2psnUNyf@4xtoY{Mm zZCEOEr>qQv&=vdi4B~1@7u7TF?DQtSuB<||&`n%Fc%%D{eWeeaIh_})-HtEITt#$N zlf+}Zb1))1IWt3b$2>1k^w~;1S@2NuO$LP`fIZZX!}To%LCJj%`=;Q1{wxw7rCy?e zIO+QyxxGg@Gks%CpJ_AS-}sneU^gS%!EPmL*;stCKY{higan@Z?x`>G?{CR4 zka|(vFBiPtU3hiK_i6O6_8{fHb(Eu&Z{9DPA>XDHeBF2=Z9s~cz>&WLe+^58bLGdM T-FK~oJmRc1S(Chq``7;iCg>^m literal 0 HcmV?d00001 diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/favicon.ico b/EgwCoreLib.BlazorTest/wwwroot/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4f0e0ad0a8300d86881040676f2c05f93ec4c1a3 GIT binary patch literal 31702 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 BZR`L5 literal 0 HcmV?d00001 diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/favicon.png b/EgwCoreLib.BlazorTest/wwwroot/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..0f58f8140e73f54123d5027fcafb5127dbca8349 GIT binary patch literal 87309 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�jum-t{U z_E2E%&qAq@JW(>S=Sw`pEmyBc$2oM%vQnB1>t@e6B4g_3)JOu0YvxWkKWagBufk6x zLiz6PN9Z$F|LuJI6S}hwv;E+CX%ZI?#+e`VuKJp}IpI#yXKF+)+!v)GuhD`4UZetN z#a1pkGJEy;m|#e+)CO1!sZj-n=knA6PgZsatGQp^u~w{GSJ@X`AEjvp?#0mhV506Z z7i6ZBZ+t7kl(iv!ljs}Nar#qp&3^s5y-QC+M6d!}30-v5l^$1RZj(P7y($X4tSHJ` zamuV>U3m{5fvp&%1Pin7Sn4S1?pkK37}vQ2KdUaKZ7OaroH+>h(*%tIb215t((ULx zy1ZzOneU!&l8ndZ%)r}4M}O!y-U0Z6i!b zts3%|$dEnX;uyE0=6=zMeqqj!g5idA(V?t6Z6l$kt9xmnY9USjxvefmGdqagSsEVS z{_Lv7&6e31mMpq9sDyy22CYL3xQdb!J>IB;v2O%B&U3QKZ=o8+PrZ6ZMl*2O(LU!` z`T>10vdL9^W`6MKA-&eZi}J*ZYit8%<|mJ9qv<>>Q|U~MOn?x9T^PP%PbV=qA|WXM zMuOsaUYWevvC82tm0xnb4zvMYS(7vwAK-F3x~efK8de?UlibK+o#q!IG&z~KKwfMr zx9A>nTh|yV3+Ei{i9uTr>;&Ki>sQgnHHBs+mER#mznG!JEG#j26`#Y1lI2Qeh z3U7{ED@t)p7__b@t$nd_ z9oDhz5>=iYw^Eeinb)H!MTdzHAZu?IN&L9Np$q zGi)RAKlEPVk4a#gGP=8-)EsiCM2@canhR&7(C;}U1RkyL z`x*Pbc_qK16U$$sj0HIMrQX&6p>czh( z42nhBPc}*bk$?Lu!&*{iB96K~C%pdY{VH8s`$e@CK^Ya^$ukah@}-H4niE#yQnlr+ z1NxX3&-rB9u7JChBPBxNaZ2J++3&F86*+b0;Z37>NpsEMY7&4L&QS~c|7ILJwNc}c zWcH|+Ta*q3F_OSNk)G;oAo>4xUao)abK-6t*ov_}NX-5C#f4}uW-fCk{u-lW)sHC* zKF2qDCfwhXW{?1!nL;`9BwPY4m3jVePO$N+cG4ZDQSEGJ2t`$S+so172K=J3-|1znV9v zxZgowN>oU7ySj7a=c?wA$TwNB2{XIyS=jOw$g<&n1>oG6_X-@drl39=QBe1(C1} zCQayT#sPgr`ku5iJTZx77Lc_Q@VPl<<@~FrlJ~MYBBvozGn}`rFlYc(8rRLHggdrp z8FpZuENb&!wk_L=;$FUTtdtmVj(_3UKJqVJg=zp~lAbruM(WQW3#|CkC(Wp%*)*e6H|^a-rZ-d z)SkDG#{1u$3U@>dIcEzdGCH#5xEl%>OW=?vtj5qhag{&4X}dd<4%+A&MJ1M*WZ0w= z?J(2-r6(RdF*d;ySM4SpL1isz9c)X2lGzVJoa)D%{!35WK-N?JJe3aUlIrkI2aa0I z5vT#K&TnGI|99unEXBasOjDxRh49XK7vxr_q*#?3fE&;MTT!vK`0XThtFFlgOemm6 zT>>FHm^a7P#I>43edqv&!4hbxt7wUNz(xAakUa+zBTp<=ojuP#n0>WUf^u}#s_q?$ z#6|YVhfB$mDh)Z)!IZM+=iyYR|5<>a5RlyT#RFXu{m0a22h%Z2dN3#Zw+ypxm7b#y zxsJdcmlwSNO6?d2f#?_^O8dfrt;?36?t37)y0IfyE)K2MIOp=mcvN0mGCuyz870}S zEb(7m(%wQ_iiv-f^SIXKXC0dVu(T!?xaa*w7m{Gq%ZP!miUW|!9jdYtHC)rGtlPE_ zObbF6_V4YAZZ)$0M#lGfp3+F?l>h}U{I6=e7Ln6q5UwCkx(L*Yqtw3LDvXPoiFH={ zuZ~o~m4kT&D5J}s!7_fv16X#ah1%4bx#b#*!!{eO755Gfd)g#E2VibdkYXDU^&0AT zPO!h+RWJmyFsD!Gl2JiMRE}(bvNEj!wi{S2F3EW-Ox)wuUX z`0*hi#|D|saq#GwrbWQnA684B0EZT;GH`P+CX+~9+og8a$Bk_7>rQUo`kRAU65h$G z7Fk#QifUy7x(fWCG%kbPQF2fNwcFk8&xIt@IRVKMW{Z*!{3C+gVoW_DI{gSi`oX3StwK~O z?ffw|6|A+uaTnYaZb6b+1JK-@Diaol#<&3x3%Ba}c?ACx6;3Odjb$qMSO7@g<0sZG z2$Bza9gN;iHKsx;Efb2t>KmEn#IyrIoeDFaZuNm6!6`wQ5OUbz=fd{B zU+t{tYBf#@NWqN)BbFZ^!vi?x6S|erT73=*4^srMWxPM4g=Wnr4Px@oaa+Eq=Ghk7 zK3WS^4_{$%;RhOA8ag2|u;pX&(|OXt%%h^kTY)Z#c z?`fgi6r+(O4K&b6)4jK;Aqa#Vz5&N`YjN z@3SlLtpIAB4GSrsmbQu_} z>nXa+)}ybq{g-{>^LB_>%gmPxY=8J@@%>k!+eaYEul%jRAA)Je+QKV8yYpJZS3@j( zSynW1`tRQ_#{?6Xlb+JeDBXgL8OB~@FVYOrM^sFKb)v5OSVeTu_NYshEb0dd4@sergpyghC%lvVW5F<*IN z)Y#&APhIsm)Sdk19GaGNeS+SGvbX4ZUi=KMd`;X1Bg}^r+f)|`ufWR3`ueH4L;{#@Q=D+jI73gnjoJ*hKj2DSiDo|t==qf zovogbm?}Y15VXAU7Y)lS)GnAUqtVskovgN}`r+-`4=5X$Rq)`JO7rChU%jhdGIM?; z$V{dRk%aDJyP&6lLQKR#sN@$J%GAv!65kZy`b^lt}1P|{CrX+CSl9sgv9m}N zBR4nnf(l`gXO3u-KeEtU%p$Hp_I2}>YMp$P~FTwO~ z`Cx+Ky7aW3FHk72HjYnzeVHgF#+6{cXEEvFjh8hmUcC;gsu;*Y8GM0x;WZC9t(! zfJ%!e)ZpZ$0(J}(IB#xv~gd&hsGz!$1bmZg?FF@R39zt@NqBE3CFnDao*L<~?% z>2+b3+vfi@;O-lw7H!(>!6^7P$@qr4h6wcvNONFQJnj0tx^Q6|6v+y+7;fCbsqGMH$8b ztuRtj#P8jnfE%7aa*EzusZVrYjcSo z9hM84CB^}7 zmPuX*QJ&P}oYg-GkAfXsS!OK7wBz1)`3cWdCxDP&Ya6RWIR#1FwJv>*4!AE$0BRzZ! z`d+gFUTa=T@!NA1T1l~ex_eL08#oiT61#dp!Dkpo=D{Zw4`Wu-dswNd*dD4w{<6L< zUX$DTZSos;mZqFsWUJg4a53_;D0GIPVnMIiML+sIt3UZDFXfG;RovUvS%CHSbmD9# zgUEVL8&GcX2<62cPR>S4j{DKa63cEx`hs7}WmH7{d_*UfZP3nB+McPj1u`;T?nQZuTwu`-L4TV)~iQRRhoynEe)QAF8%v$AP<12h)NHL~e@_S!$wU;2-#MZ;k z43Z!EM_^7o!^JH4T$Id$yMAY%r>abJ*+^avsKUYt4XUC;wxP-I;z+Co|%@aus zg4wr6x8p0>DM4sY-x#=jV3HRwRj73j1Khd7mGSDUTroeKxfaM5U0h-wuBDiPsr?Wl7-R3w-16Q6(w7qru(jO&lSXwjLi?E(~=TuNmDyNYE;-U+~o| zWRGv#4}k=!k=ZNHC&U>yS$TqmK3gSVMbD>{h_{MXaO#2)=DRJu=O z;q&x#(=UVDn{>*RO07}ofqqq28xV~k?92*~P*9kX@Z;tV_nB_!A`;SR^=w5inV-SI zK>u(U&;=o`MW61q5cW?&5|;)s+q|5ZXa+eV0cW(*f+>jIQ}pX);mmsEAJ>-XX|*$X zytod3i!?8^l|NDS`m~lSfI}aviwDjiE%&fR$G52#%~uOlVzkdM{wmFD^_J)~ikBm? zg9F7^a`h`zn`RsKshxFSaU4zpGwD}qPi5l6wmjVZHd+m94eFdXw*Cw>wWfLAU3W-` z3e~85>Xm*NYcvXz3bnuM!|Rnw3!lG}A-?4T>s*sA1vt-jwqR(&9a;$hftF*b*X<@< zu+!0AS6&ZqMP5N1yTsEOIdUje7}7L0sfEx5#KV9@3#f+lVFhBTXYm*&@OcImotFW%`8xKDcNE2CYdI(+ z=(rtjaNS?4t$X72$e|h)rW|5{9B_^8&sl$6o$`Ew$T+{ly<8U(v^;y8{CdI^L}t`gRLX}512+;MHKO11I!Q3pomSq=5}1vNqa3s0iw{&9`!&$0S#gqR@1KoHtB z?^Y=2W*;*RzO%i3LijO?%CodN4ce11<{`xymik8j8vWZmmiZI7AIEdUG^F>vC}k5< z!u5K8+9hTtW1ecw3RsurEF&QPW5e`-UEc=6I|r0d?T5fz^yOXF8kpS}rgdNk%qmXa zJtw05_L#>40DU)}2sWAHD%Q2%Ffk&$=Sm+d6_O{BV3cFS+!5#rjm$uKAGPB7s!tpZ zVEh5w-9p~>D#5$6=Z`rO5`SsMwu@f z7Mbu=-S?lM6J(BYHE17OIzJjPB@nyVp%0VQ{>@-H9_i{DpbqIZmKRsIelX|K%xUCG zUaO&~q{h1McON@BKk~tdA*6r>&7T5QIHo<)6w)gc()%Z~M(#}7@YUBN|J^H`<%~75 zFwWSyRy~!TKI%LSjCcgR*!rSy<`N@;W`}XWkG9@5!W#01DM3rYtjWTrNk@w0RJWNW zbo(X~t{4ntHr~w>?8rxkT5hN&-(fa2g474r)Jh%@Qv)3!4t)Nl;7e0{m;^$2vfU)8 z_@DxmCc4evEWUnUy_JH;0Y{jVna0jzmxKm$tZGEGOO#5rK!3OBdZdAN2f{3YCwa@a zOPvPQac8J~Y(~)8eg$>W_{Q@e_k4Z3a~Zv-7u~4b&F5W*{q>UZfD!jZXFQ`AJHOL? zCbM%>w`%d*D2x&2eY8>7*Xlu9F*t_3&W}hiBNO;yM0nkqB(qi)bU(wL<}A-|sp>)A$3{6B}wadvZ4qt}fGV(ikE_fo#!bo&%$E87w@V zB+0L*Sk#&PW>&uYL^v>cdAh^Oj`^M43lf*sT9Qh`76(FH5QPbecw}AXysu0D|67&lZo7>P>!Qo#TcI zIv8Kag%0BFw9Kr*d44(+nr@f1H*L2a^auRItXcJaS$x6YC%(2G!k8#*6t149y_0+o z`<`b4Hrbq};UFogISHzVIJ2%wxeKi9pqP~)8QD zqLq>+Uf2XW9_=eFpn_PBp^HP+V0cDMzpTqJg5<(@yBxt&ur2CTo8BswWwzCxLJL_spPxyWSe@{)c_-YE66k|` z%@be^juLTZ5K@gmHf)J>G8TcJ2Pm?+yHuh0tq$^-@xip>PU&Hc3*-#eX#3qH%sb=t zO2?XH;PG8F<|Z5(&-g);6-{^UAvE@`&V9raG@Q2Il#Oa`OIW9lrS5rIa1!&niKXPD8aNDM8$k(q? ze)4$wIshDVAkWHi3y6gTg)K~`+L-^#aU>g}w+(tTtx6fm-T`fqfRFaW7og)R_mw=C#km#27k)ma?UwJBj9L z7OeQ}7=-CJ{~Lvu;l_ziQcFkAI_u%{?)yrT*~p9b#XqR)(lq9cPo$=>wCo2X3Bu;1 z3~(6e6b(wCA%5-@j8;vpbWRel|ErYc&kUaWF$ zrQdx!={cneDc%7{d{w?ko7{q!^nk$$N^{B%#|uic0M)AfJ#?U|{y5WfTU-3>Y;4Bn zN!F0t+cktn&Lq3Z*YAQ(II?+lAQwMYH+;Ot=!G!I!+E$8oX;~T5Mo7hZ~v<;+z&bH zX^0G@2asWIMtpMgG!LVrf2FHwlLo<*6w_v;^-aRH4-shNfs&n+1Jjzk%!o0bxV8@3 z;Jj&vOI;FbkR;g@XvT=e{T@{a7ilty>qDVZw8?9K51K5(gvO(Oi7Tl8&2oL+U0p9~ z*C^)5Y9_sh__PFR&~8*qx(Kvj6Z4aw4r8Tb<6lL>q&C5;1>xgu5!HYH@$UZsy4znU zTi;d!*5GJ9!~Xn&qXe#ud`N0wi+^nLD{!jpLE!EzZb2u<+|0c7As`PJ0D2!0$eX=G ztQP)w_f|zdsibg3bd3LIg#0*fAYIv?#Omv6I`YJHCBG~T(qS4g3_<5YiosR=LIo-U znG+YqKOoA?V@F9a8cSg(GZ(&wU;bR5a|OSV@G|3AX%2I^a{6#xFssYM&xL6fG5^rJ|E*D$$Dd_ z29n<-pk|N_*wNMq{{3lQ^&B%$J}BoHE3kkcTN*#LhGUd#U@yK;vL0l$xSj=hn!;4< zK37j9;dRL5!`C0wX80Vn)J25UoJNaJFD}a9>ygmi(92O>%-qv}ssY$vFk3j*OMFn~ z%u`Xulf}tHsq0V$^0{xR(^s(~bhbQdyB zuKslt=7O^4HnAzLt?TyVD%rGo=RVpO<4^w88KyuhmLKv+UQ9>q)Rmpx5Ess&Rl5*4 zx64n|m|ntzIi@-|?fzpY(XvEhZcXX0Sg*~v4lsMv6@X$KgBaP)71{82bm`AV*Qi%_ z{;j$2q-4$*31##_;-I*bRE-`2{dulA(Fnaew~6SaJpoGnE_mVK&jw@;`riHAj5_Fh zKN^UI>uDg;R6DZ@_TN$mpr=v1d`u%qS_`qJMr{*WKh5W$slmOgv5Pz9B6F)>n^YTtaQ>4)|c~0v0sL)c#H}B;l2)4O|9a z!M-S5c^aU{7Efx!8~{!_o-&N_I|=azqt1O3;}g1jOrbnN46Va2QSI?U=Z9;f_$)S3i*gKds+ z-a()2C3a+xVm15gD27LhJ5m@0_2fv4mxGJv35b%miDQg1bqVvHH>|v%u;oIiZW}E} z^Isd)Vyv^|;3k!Wr^d(2P;p2<{&(>dQcB4ZKWi?Hy45ehuVO8dELB% z!U)v0oP)iz*y^zFHdUM2{n&}(REtDTazpT9EBnMZtVWO=AGOQq{^G;_8N z%nVQa4dKmQMfM9OwszOengagCnUb36jv3q%e1n@T8G;Ozo7I0z!O7n*e!u6u-doyJ zm0SmQhI-k+fwSdv%&Ns z#>c;prJfWwAz0X#H9>skf5?WcH6_}f(G*z}t28281;lEzQED5WHGWn3>BAi+5q0V7 z*J+w3+WnU!?W8+;XZZcLLxdU1zNsQ4Pb6YjlAq4D5skj>JM0wq+RBaig(8Gb$u9Q4 zBK?mGlwCU2NOyrcv|RF%O4lf^Gp(8Y^e@z=9<_nfT2z2L_E#xW332!ae%7>u<}Djl zEe_{B^T!`qUhppqf>(n$B(xIxwvV1o+hUm=k&B~q4scic1IVD#dvY7}-9^X;16m|> z1+^K+hKAs%LYkXzsy3%MX6e1d*t8hhz@dLh^m`*W@?8SqLjKj>Kk?9jYR&e+s!AUS zw~L*T0K#QP9*WHkfd3Yi*Z@fB^I-p0V?%6h!8 zqz;F!`+Ji$7Emy6qbg2!T#O7N6rabReL}Pk4#pd<3o{sb=n~Mn_eSBD0?jrX)!AGF zaf`GaqgXx7z(68M(sGYacD*>0BP+)HhHoZbYP%TMl8B^6+}U-1o7eyoP|saV3Yzb3 zVX>vha(GjZ1JwYg)cGU_UHK}M#)nZc<=Z-uLM%g*{?wJqFQ&qH9DpL(W zv1eJnSindB#91-2i1YBRKo>$re@`!jLxnRQn{Rhr4q*?^?eq$@Xm0!wDc6?V>8hP$ zVEZk4EJf7Ukolt1b_MrDPM{Q_QSf=XB9 zIejd+<{Jzi6ov8xWJexu8Trl*u`EXT3g-3@UDbza-A z26#(K3uqiqCDe~&DM~+gA{n_)n5|=1M9CsZJVyB|^V>`l`0zAYrR$Tl4$L&6d`Tt()c9KH#O`ttYDik-1&XBa-0ma@>SkfYxKf z=dMjl4Q{%>kr0#k`T5ChwZ}C@U_^Rtty=Zw{@;x5lTnw@QhB!;ebB?)H)GIY%!f6D zPJg+tN@7K(1HVMx@;FgxK;WxUBHAx4IaY z%kVbeqmp1*MHH~`>3;!mr;A?kdvkFnWWa%(dgqrNn+x1QLh_+1IG(}JyAJ+%(e#*J zwG-?=SX0E1uW|>|3VDjqiGOsMT&^Ic2Z0ZbAJ3>D|XE(N27 zH%gSq0nH=P$t{tc>U~YX;Dbun+o+ErOTf%RKZ>pj^wz_t15?hiC^U!N7U!^MiH%}J z_CXGVuHAx9!V^pXY|scC3_wN|J!dNhyhvbQl^o*0K;4di26y@uzc1!dj>6Z6_DWv! zd&8d^^El}?r(SMBp#!ujZG^#C2XN<0)AvLN# z6~;4gpL&i|5%ZpRuJDzjHn%pPHs@T-sLXRQBeQT0G!Z>rwFEl4hoye62j}c3qkQ|! z?_b7O`qn~fRsQ8BaXO*>A9J@Z_JayZ=Vc3e!dib z+I84{ueP+d~?0cyU3w=yqGp{ALwB;J3+FOR3eC^g%i$2>0!mk8(Qq)(+f-UW9l3Q?8 zE-#29ag+P?{&}aQfqE&+8pt}H1c?{-z&vQ|^&DJ4gtsvI-Ua>izN&>CB^WP>K^dn8 zt1{z82Qv1O>PNiP*euv$UkM-cWpYc* zy%IDyB?$|!>>0k4E)`w`3VDID=G9A@NG z#Z4<92h<}^%W&ARraM8Z z@J@`=ddaN7&!fO=(!X@aa`r{}YGZr08jO!)yj~EnWj|!l*y|?27Ltf5ylXDhvC7A; zW*x46b=^Jon>zMZP3V2m`~NWUFj)0_hAsF`!I@&E>zAaIM*iP?Q7KJsiKEV%2V1at zvn_PXO|v8|3|E&#P!YxkZ(`1mt+}7%0_iqzgJy@Th>yQ=L0@U)JA*iQ169?qM-N$& zi3RuHhslS@jazdeXd!5(biD@CkuY`T0{Gf5mP7F@E^jpb{&g2j*N$Y}oma)Rvs(UX zhaj#}bIEv_GXx3sOM2g9iQ@_cr9>A3h)#_VGZ>7ztYz?VdABu;;a;&3H+i<`J)GFx*8E|jDuH>_Oo85;4&v^oGf~!VyKVNGIfb&Of89JSOSj2$k zo=Q)I1q~^K9VnG^Gw-Y{zQw(up}S`-GY(~iMi}xl*)}fH()M15VG-3P?aZidIAb_D)f2X7AXkT`Tq zuFH``p={U$$V0qNz!oMA&;ro!PeJ)zpS;-he@DK53EFYaJM?bI(6Cb?eZ-%gnL8G( z+`bc*RPH4XT?jLctxb z0tghmxoNOTcURi(0XE*pb-}3pWIF6RFI7imwT{l!^AXDJl_OXw<)O7cx9VE~l zcUBd-1OQ?cwG_>Bu(MpWeN8?@HOC zjcPt76cnN5Q=_GmB)m6s?W$juI$7M+;jNva)35U1bD828VXW}IkswuOcV1C={m{2W zO*cp%`>@5)Q>lFUY)d}CK=_>iG?`*M=Q>~bu3Y?sDtmj~^T|Ho(om{Bco0<^)hLWK zI4_TPI*cGoC#Uc>m;P-V&AR^lUJrTG&DR*|OYyHh-F7U;POX_(JF#Yb{vWdZ)R=p*u@;ot(zZk!v@5h#Z?k8( z<)>Djq?Dmo*uXJS!&Y~O9hC#A>~tNAg%WvfqTf;Og_Ixyme}(3zNM4FXqpcy;;YF3 zI^w{JIYS+7?aa;1PksZRchb(vC^3ji5v~p~{J~2iTyE;*5h;G;9wFCO^M22g5TkwstaD95{t_S_?73ZJQZ%K0JtZ^%#tu>79jVm}z^qvRH6Mg<(A^KG4L zKA61YuQh$gupWFZwKim)@(9xVOeT%AE33Tv8(|ihm zir}I@cmg2)#Hx2|=5~;iprNtHu&1YYQzu{bF(`*<=C648X5Ds%N6zt(HOXFRO%Q*T zt_oL^UMqp~5*pOth{tB=igBsI9FIFBcFv5CWdk>Z+I}-`QY!$5G=h^f+N>9{Q^bH6G(`1KzUu@84GALXBb7Tq~{=3ZnB#QS<2 zMs<%gkK{3`7~^oQ_ys##J3H|qJ!qBeZyvEKD?CLf&GNejca(n3OK#c8@Tcap-6V|O zOKv$?VSLWk)(+;}uF}z5_4O|N%q8zHsXu5qU@vFqrqa7m^QkjEkOD^J6P?&VG4dGH zwdgxk^rMM>1vG2Or2IcyGc41pt3Nesd94?bB^hW2{&GV6QL)y(Ja&AR?ijScs+N0B zhbi;fGj+|RX-hpWJlXH}$>xz6_-P{n4^0vH%_H7gqw3qn;n<1EZN9&M3jNW;y4)U= zJoYy75~c!I*W)l|v;#d=^apheL*hBJcEYz8jc0k?U%{f}b=S?o815qAbiU0a@@2yN zGKurX4YhAE+Uw`Sn@60Kt{)v7Ka^P12N8*#qA^+CXU9HjGLI!!fG0Z}@Z#RM%Fk*1 z0&j_DK+A?RYid!D*$z;PgP?cBZq<>8Yat#aKQ8_wjp{9^&3QJLct}K%lDr~SczG1O zy9+`n8xhjkzvO)*D<8WVuKgDs4$gDrm=KZN)TRUqdzoS!KrPD%=UzA+aB<_v!*k6eN03-X z5ui5ZJD9r>Wu@x^pzeI&XU}&T-q2U6cIWuZN9lqC+u^cXbv=aOltKU`8%XsX-V%eQ zTrk4}N5uYq0C4YERJx2@2?6SU(&eLT+gVp=o6~U8C#@Xj%IPJ9ok-+h}ss zcyFS>6IzbI*CM;cSh!gAxyYG!+e!Adj|vLWpl_#iT@T)_BA8XQQkTr(q)h;~3mgL_ z1guTkN^iZcJiO1)j&tUG=MAWnwB&YzGiOgHpYntm!xwBM2u0^DML{3#8To`(Z+W<< ztLwHS%=*EgqdlRX;QgkjcRJVjGX!BlrT}uk_499&&P7fN5lu;9mgpitOM>L{@B>2z zsE4a4JD;!w$YJe9T@NWxfCQ|e&>-K~O~yI1h-`C=MPdN%c~jhiH1a^!CcOh($1XC! zuo_<<&Mk*$;@MB@r$@heeJK2 z3+xm;xdoCYp{PsBZnYz$gj~G~lianz`q9_rhnqWAQNAyVdgY* z207Qs_X9F#TZA1^2h1DsX7t&rR=_WR&>UCogy#_WZpqEl;XlY+8J2S84v zASX9+_dD>R6&&%ogMa+rOLFNOL0$vDY8RAmQ|sJ3qJX62ceR4A=7b+oi7FF1O|97( z_{*qs(+^1FB$*+u31cZbKO7L6rPDbr6za(Vk7U3+iPV)9dpkY8Aie0xxCC#8jH0Td zJojM7Ylx0}YYLm8f2(_foB0ZeyMY>2H2_Cuhtlyk5mCF_4t^(F97uI>M`*q2ceg`q-{Y>|DbC?SNT?4?4o#9+!cb2_CGI+G{{ zg%Yw9!VuF@90}Ql$z)%mkwV%2*E8PE`Taki-p}WK-|;-peP8!=U+ed}uKy*b;&8g$ z<%m)?Mq(>234uCN!~jCHtQ5rMJ;6^?mmS%QGThAA?(+64iIGgx1xervt~n-Lv`3eA zuGs}62?9nQBKtXwbz}ednuZxR7todIC+MQx<-R6Mf5hf}THUX=Umw4y7Vt!ILnRW# z7uUWzKljupi~(e46 z1E?3Mx{RF;DWyePe^L4#iZl(#@%RPq$m*9-CK#Xg{!bY5$8LSAdQy-Kn}fLOCg{zU zH!kXutwe5#clgVkq9Fz{>J@RkCTEuH4V&4`EE|xGmdR^EQyw`@uBt7YV%DwKQpnaM(td zAGDc_6C~jgE_s%dr^4*ganwn|#QRN7F2If0hJ-#FTJer0Vc^#x0j~#w8Q3QsDXm!~zx48c#CUHUKi!J9o2;X+ zve*BoQ<^y=PzKRCaJqY$&*>Eq4)o?P>GQwv0Fg0-=a}aAO@TUZ=IAbBrtok&aPklzv7|-du+9=z(`5pOKJ@hT0NJ zB_7%L-_EDYG@P(&;IUA$a3B#olnRa|jK2R&he*AKx-uFrZf7V+;REl^@gweGa(UA2 zmNyBq-jkpWozM%nXYQj5z9q==YR2I15ca{BFYo0&c z%kU&ia%^2$Y~fJ)8aGw1S`hw=C)N`Zi$Bd*qH^y3M{8iwYYItNQXx8R;4yrQ?vp7q z`hGi6v{k=Hinwq3Wd~?FMebX7iw!=2H<#?Dkd*SFnkT~FU1)W$c0caq!0eux-D9o>A9Y6nBoyf<_qt*S0Ad@)h)HujuGdiM6?xdm;kLC9jvLlrI{x z<30B>h zpM&7eaj>8rhFX;F4!fUdd$CnI|G6G3pjVv%Qe9HKbmkZRRehN!Ch3WDH7-0de2J{M z#q&BiX?~ZkWn`UrcP^|~y2=kSD$SSWS%k$8rhaU29QtbuDa^dKJd0f&<|tZtf|)v7^TJ$zO7BONkPQqu|M72zVwm7BzJR~2X5;t?~zC1X;Z0YisB#Hg{E=Uh_DJ02|2HMip7d1vb?h`HZ zyb6ONFpKBjjVLK3xm-;tnUO?UFaiq{MdVy8?Hrg(vthI`yY zrb9y|zG7aMGZTD0@Q42fnW=t$3Zg~r=c*o0xV6uOeB0K0I(hYs5A!E|&Q95l6CfKP z24c<>6ATc}jX^%(1hy2~n#&cAVsofrfKl|#OGu>dj;yxE$P2dmi&4FWyRVk^6LKsN z20l^&%5wX31(}qejoQXYu8wg*}O>}B6L)TzFq08@$4Kg^i zMHV57iB(8S{UeMJ44nf(HjL>WOCY>Trd?5Ct$9UTCcCWR`hn(lnZ|Fn1J3?7z!u=0 z9Ng}AN7A#iO5r9a1^yIc*3;F=N`Krv|M~)RmJVjgSE~x}3S^NCkDM4*3^Y0cq|`6v z0MFh>ch5JzrQ3P690jA}eHGZ#9QvA2Nb=nO-H0e6-19RB&=632zX77^1?Q_uCw#oz zSSvy$#;TTGhfBJTtZI#X>p~3213}I3e*BnbaA_SmBP)2Xl%_%AJhx)m{!~FD&KZ!Z zVaYT{K%t{%xR;@DPj}=Y66)(hLVdSGo<3~=yNcJ#jhGyGdH3|T*?aWZt9M6V@1z%# z)a{g`fw6AklI=j+&TPSeBT&*@H?|vUPb8*Q&D*C=_9|J`h~YExE>+sOw7-U2D|_iO z(e8JL(jRM#!4cak$3sDf%i>@=j~2%Dh~CNYEAQU=Oep$rI75jdFDVEt|EwRXQU@6i zLUui#_$JS6phLtKvI3bkM=JV7h)7+GrxsKB|9f-2t#T#S4ZF9f!(YZl z4YMt_$;JvvoeD`~*a7s66eH88f}6FH&}d<&ECIP?-ZF!Gw9oP=iNjz%xeh(*IQVYF zh@6CN$uyulGQL>=hEg6c8`2vIyzy+stHu1U0=svQg}&%kPw!vaJz2^C9P-J=>2Rhe zeS&Tc$e$s;HI*aDg4rhA?{B!N8fG7ETZX-gFKYEZx<~WzU<%SR?UbViKp|#aJx>K& zN5YDebyUhs_-xv7&Vg(N|; z0XYm^IhVBkOw=FJ=LM&Q7uxH~zGCIkMswE`C&A0v?pqd@q*$F08g5h>2~=fS4Z7}m(oi875cqDy+tTHgk?#3A zsuX_PO=*Z}DU^@oWSvV4{KyLhVGHz~&-bZMC(%#SZTyPWB5akV-NVVQG+Z|5?Ib8Q zE(BB#>1ush>KPx=X&-tky&g_Jf^a)a8*EWOdVGf7lb&b@+PntNPPBe^Zr`-#gBEB5 z`+}&&`T{|Uo45y@psL75C?u&D^raS}tOAgO&cBn;I8UGRY5|rYHRxc8!mRC4CsSP& zlGMpgheMyXcYR39Bt{Z$?DPrWIq2c#@O`ZYiucR!hXl77fq{|_MMsdtk7&8>8Wj(k z4hmk|z5)CF84?{0KDO7X2tndm2&O^M48HG=359&bXip3%Yf1O3GHjpiwUa>^dFTfUUB12IKEBvr|OixnQ9%y#{$f@~a| zoo3(3$;~BK-zK5Qxa2KU>`2krFrYV*Bs|3J-4JpU_n{-;alHWSM|hMf30DNrg|GSCz{> zL_y%40jVvL2UacYSf)sZ#nT&uOR75&+@(YBBk5toApQ&X`sUY`$&%3~jt+(=o}7Gl z4or7payozms*MBM%xUs09cE3$y_XtVt6|~ogUdk#QdWb+n!w^Aq>t3*GF}$sCCg%4 znmc~Ydh#hWeJJ_FYP+`H3xs}Gx#Kv? zYu1qSxB=`2o_QQ}Sgt%&Mxcu`4d@ndD^+w4w|xTxY5{E(H*&eFCRFHiTH~kuPU)!O-&UR|D%kQqb0e~!6 z9?S=e>I=OW1(y}!9=|O<`}pIJGjuV*{vsj0qY3BhiTgVL0+>gs0hhMs$O{|7KO)~G z4=L1*L9h^f5)FHREOO1Dzwm$I{_>XK@^l5u+RS`2n}6wCUARSsGYWjFM>)@fAS3}L z2*IGb&BM65?4TvZKiB9+2s09HWHkUbZ9qtWJ1w(T865&q9i-=wBW+f7cDh9G_>t}r zJLvlh&V%k*M+hWvg9oy`>A@U1zkrt83koqu^OKdIG-M;B0O}SZ5c?~}f}D=Y#tvlQ zw?)?HD-j;g=530=JbGJhVdszy1rgIo5X6wHUkx%0uY`yvz@EE}vw1fAwrAQqs-W-M zd=*ux;8Ne6kS!6f?fu5EMwu@7@atj|v`1wdoGd(kV*x%4kmo%ILEaELj3CoC1{qse z^g^Kw$@5T|*KSE6eQ>yAGL4^rgZG5wS!AI&B@C&F$y|T1BD_Z-5taFBv1H28FGZ;~ zdRcJ#11q^KT~EK`hgrpU(rH5UlXuk+6#|LVofxQdCuG~pLxjczz0E`d5Hk+f`fiI` z_^Zv+F}3sPkn9y5znr`Um2AAS>yK+L1A+f+$%J@~42v=j@fzu#%Nkqaz@%1cT3q`0 znWVDe!c98Ut z8p7|C;_FWexpOlALv%II;_m5y*+uY;N)Aeg&Va|7f?eb6H>5rGz(JbVZ()yR#cb(y zt+q4?MWwDW5+o{vy$MIUA3M7WAT7L;W$Z!XR!vHPex-=Wj!?WDhK@{4`on%8O71u` zx5)^jzk_y;3ygn=iY^?E_S#$57d{}Q%|YB!WOi{Q3c5D&XaiC@2+(^jpxcF6zP(Bp zIsM`5D&QKF5EPOe(1p;4^|;=P9K{w!6&joXuh8^6CCgSmle=B!VkJxxAU#jd-&jgC zJghH-QaK|7a{nf0Z>dbO(lw}U!gzS{p1eW<01z27*wWA#6{47l-xINi+$_sO| zFT)|E*FsL7r_Npum4t4~JZ2V2ftLjU@-cN$;UlfEd9K<)7Pk2-w=JLXwk;*5~fg)t>lukw>3H8@+fQ&`%0t z>53{>L4fZK@FJKNacL7FnF!s`5FlMB%5VeY(SzBzghmLJ*fH<6qT8t2r+xjuBXxL} zG@(~$$EAl`z+zEn1vBFiRIoQ)ZAeMI^O8am!&bQ-WyH0b7IIR{avmd!pi^;#w}ZoQ zBNnj!@iRPu%1D%w2o*_LkAbtjYux&G(GICYVcP8M%QTu_TCuWHjZs^gL6i~*QL|e? zrwF7caeZ$%!BfC4%NGR!!ug6uKtf&}4IJRh??zO6i^(z z*Y?YSTiGDmVhA5t0Mcf|VyJsIR9dB_VCu7-{Y3F?rw2Hj0ZDbf-wa$tZ{Hf#Y3py0 zWIkW5>k>2Ku@fSQ7QO1i_?>k+TeSD+9&|_wJO#Q#d-}4b%GqBhWIx>rLl0P1RLPAD zHe-bMLaq!83R;x$;-K;q#^`rN@cDKQsxqsgYwD>=lyp#NT&d6G1;GN_gv7qq?jQW@ z?F|JSLB6&B-8tc2rF8qjY8Yk;1g;e>g{6$hEJ#{7SFLg@h#y!Ypn;-E@1)DK8w=iz_WK+Ld& zFyvdPUIgt9M&E_i>m3~54T4{C5qdytWEL!3Q~y6CJkR;q`2zDJ#0&E}>1qHwhIm-R zV$~ZlR66?QjTzqg<4g{fZbW&@X@H-r`K07{A`s{e&Q(ve{dCAN#-)C z1wCSmC*F-f)}$CfylGZ?$Mtv8&KYcW2jGmG5x|;E>W?JfPG~eBA@C+Y{Cy}G(9Q5k zrd=T2g^cmmpsRgXAd@Mpa0HT?sG6G~a&+``-K9V|pjYuddufNX#tmVJgv@!DcjugX z`8Bys%LpHu=~}kRbA-g<7a+05;HF(ARRYdr;aTPYR)qu6p!G18B$+zPf8kTS$`hMs zp|Md??VYb=0Bf;btj+IZ)GM~^oPzGPma%grK+BB2`CKCQVjtcWLgxO2H_rei#v3jH zokuOAebM2%Bi}L-V#KKOXJM0=FGBho77qk82Upymf5vcv@0WqGWCZ;SAP$MGJY?!M z^MkbTGpMdqQiux8kDG3Ifcfz{wS)apfIxS3PFT8BMD*?jIVVCqPly(U(0y076O?o( zCo~q6D87M$!v~l=n90x*k9z<)G9<;gtREoH+`trjZRX&Jm9(tfG0O=*h~QF&cZmDY|_1~}Fi@%3BB$DZOtnz$GwSW*YdpB|(V3aA) z`|$xFsKMTQpA51J-2LSZMT(H$;-{ZOD|n*)xo5N?eWoQYP`Q_xpaB_mL2@QZFw-e3 zkLZNNi*Ll~@C8JpyuBk)%Pq93Oi-beGdi+uv~SN}EW7e9aztD)FdPYthh7q@)i-|G zxF-RMzJw1ksluQO0~})%{O2p2+yXar^}jymV`NV-bSgcd<+Vi<74egJ;n z8v+IL0XwSyIY;>fG2?awcr- zmTAcQs{q{BaoO$C{c`ZgQc(W4WSn^7`VIQ-<-_kQ;Fy-WVv4*d8)H8UuN} zlCihG&}%L86I@S#-^ot=dh9&I(E%s~T^c_NQe6dJplMit03Y01-m>`5nW(!63l6S` z1(-n?tBE|g7g9YuRl6Woe@2G+6ZHJ>K05RjSHEb?ygKwcUpA-GRRX_FsZF9@uYd>Q zvuBagLvQmcT29`fbo|VI8wlq^sEH$71|o0!Fp(SZYMD~lFOv92=jO5ichS1h1$-I< z))xSf0U~(>9QCYHi;6FT`r42=&T_(7gYLL5hDCsH_|V;~*&javB_n4x$>s2Hf=2D= zxMzK1=f&_(|5!j4=b0aezPxS*piS~fq3FC!r_ncaVBH{L+x&ZZ!u#?;XU+0Gfd_CI%$uBed&tdvsLk9|=e+Se{ zpcbI4v#T9P-=>@4;VOv4*n&G0=$EFJQUHkutriDRk(;4gIE+AoT-ohFpNBt-bfD0~ zMC>ty`6ZQh#hJHLJ5gp=?RT^ z(C(v32sqKUUXnZ9PazZnc9g7{#beO?yT1O-H*Fr)nbqZTpLgfV#&0N_K}xSmmF5x0 z;3c{PtMHO);&FF&zOldM0GEW5?gM%Urz5RRP{C%uP z`vcIw%Ij@~`Rt?=_eE*E+L-I;?n7p`AYQ?6Vffjq*$}$L zAhImKONWvRzRx}>&_5FSZJr|}KJLSQF#_~wqz&9UK$o}Bi9dL!% z@PoTFbp*E^+>(-k6`8Sw>#z~8cGb_U($;d$yJno^HT1dDI79Edrvx@W4$@XSKZsSz zxgWp(GfpaiQ2X9q^*1VUet(_lDI=9xf5WZRDVW*TYan={;#NH0To4p~+}OHr0sB~| z%=F#4sqq``@fc0O>vfi&IZinNv66kPKY{uW^Z`6zLon%vM`f6gK?v~CM2H9N9E1%{ zu(!+j{%ag{P3K}bv1(@vIb%i`zv2C7`-Ogkk-#bNGm_Pp1`9SPyJ)>lzg*bZM=FFP zR2&wxblG>e+K#=!V?afe709w%dJ>DkRHrlyjQ}1zI96$S6QAXN z)m+smzVUQn@XLvt92;=EY(!q4!Y&>jd3VA_Lz`@Kvl^#u`rtTK?m*_v`@5RyWPY4V z#*Svv(`_lI4ry=O@hR{2!S>oE)6IWawns$g{<819Z0OT@;lzm(1KHD!8I{$g3qNH6 z8_bg0`Es(Zd_sngBJ-YjiJ*LJ<+igFNYB5MU&OtFSG(82{9cWUw7%O)I>(2k;yC9Pc}?QGFjueAB-}x zM}|yYKjfIi#q%XZ@@N&(ag((LP2IERZQCw0a(d6S%mfXWipypDjO$wmYtjx){^dbl z_^}j&%ni|4#yttbKdEcCbzhswmhCjc-J;n`)QCxK#y>2*LV)&zv6Z=gnlQQSLVQi; zHR-IB_?bBo^`bpAsP4d25jK2Pgvxb_#<00nH@Xm-?F@t$4HIk#Z?y9!&l@whLqm6Q zUrCX^MIWhst5RmRYX+i7AA61c@v*oqA#&MvWCu9p7?!+y?l56xTlIaU>sjXKlg#09 zo*(`GfHm@2keSEqY#{%EP#wL)) zMck-}94wXCmukUwM}>u*Z?xA8lo-c7_T9iR4vH&0s8 z$?8#svN=&N0Riv_ae6|ZkbY>vda-<~V4**%MNvm7c5x5~!YuYarQMQHFj%fkJ2dxl z6Vaw&BD8h8Qu~wHBSGy?zTVVaaWqY>aiDYngIrMLetUVhPAZqa;9?LVrsS4Crec^7 zbe!F>PUh+GcSYtohz6AzTUg1PnwH%0Z}YMD{gvj`UKrf*Gfd8GW$5A4m%R$Q?jrZ7 zk$n1_7Xf$D@xzz-kzverS`s0U4P#89S`A<_^IMq@nb%+TLe-yfw&j3u-0{rX0Y$S( zY3@U%oh!iWZb0STIxCXIy{eFH?*gkfbND-SltnJdVYnnRbZ#h2I^l+$k0H9hB!$G9 zCZ}i$YDKQa$7x2mnYYo82dndHKYiK+6yIVmmt8z@`<8=g+0)WUlz!$g!GplVz9qO% zeBqk92SX?8>8^6w=YTS!Yx9nsO08(@@WR@-SNpuKa@j#7d9(v( z_S1++fn~dfiRs-t7w}DUtb^&B*rR zckAxw8+}-QL@s-792Uft{nWq;o8}rQo?9csUJ#c#jB9Gi4BGt1^;$Xlj9m7|@eMzB zzM6RmMDqPr8mEh#y3xzqaOyg{=Jz*DV4!GqbE}egm?_p;NykM3{{ki+K-*=L1(E(4 zK+!n8Q6amSTP2xB^RO(hFl@k*u@kaINbm-4_vVylKZqKx9MFK*g%~^9RUD(3P!6f=U%#(l>77S|$ zenC+;GWK3q&J0p|8y)>KE)33cweFhI@Le`=HdYd_S-Us zOG<{nbGh>s?svKEMC!)cAq=-A-(^8)qWV;!Q|WBj=c;j3e&hiN`)Gqcbp9~W)tN`YpKOM1M zTYO}eQ!9LnY;L8MM8$DPnT^@(7Wa3?hKcBgPIey)4EuTdgd$XTXcVAxQG0u7yj!bD+nW!2IL>Uf+ zORk9aNDxmnOf0-sia@6f4M0AI1{`hh zmRwufZC3j?G_JxKsp_3Ix2oB#GtH&X%L>VAC8)C^nUCbM<6nNBg$cn>W)y2~C6+*S zr=(b3nJuz{|?tcxno+$koPqN66`K~2-SuUqWA0Ro) zYP$RL90Gqyu}s_@nBSR_O-<&^VtS%nc3Ft@^EN&Uq*%6XJZEzBHJzUvLCXIlXmoOc zK1ObVVy1_pxs#(|bm0s=k-;Bw*|nK68TP?Js;q)>96HtWnSO`jOSzn=T-s$+z-6!> zI6^?AY3m;Jf&0FRnGPI;hejY*%kwVoz}@mK`J-9=bf?b71*_$N3Dw1C&@b#q>iTKNk!EC0R>L>6 zND8{OgD;=kPr~+QfY_PFJANh|fiVN>_Kas1V|Iix-0d|~zt4WRRY#_zpTq`hMIDC5 z!@~THHl0ld6VwxoZL~w!;6Si^F}XAyE}|8|w2{H1pEXQC8r8)Xg9({6cfdGjT2oP{ z336|dw6D*72Xxx=LmppknL~8w<51kHR{I9|^tIf{^H?Co zPKNZ?!(&4A-TB{WA73APb*!^Voh%G$LbV&aprpgtfZuyGm-bUUb*$Knm57M~(-Hy1 z^*+o^X(yY4K}$YwZUym%r&_tR3KiBFcQ^MKCiT*s3)6^Hs7o(QYe5G4Juhg(LX@WOK550yb_PLB?h)`KuvpfBaoexg_=u)-jc zpmFWtZb4wM_ro9V8Z2GgMrU!* zn@b)9(v?C)H4-i~OdO)Gkh(Er9GI!{owV)9h6kki=abMzF(zb*e zVXb20wwx*COuLnSUMdUhyXxmkW>P? zaB@LQ4n#!M443RF_moBK1=*Znur!Vb&vClLDAXUFVd3+Wsfs!)wA_?hFe05C2M;o9 zA#&6K0|GBp0&-1b3!`RfxoSzbBsV3j?I-H<45J&1ncLyaA!+JqqF+2*vZLH{c>UG+ zIPB`ylbi4v)!Jg(;9_x9r8n1b3&rBR$t#sDf{C(%iB~gvn|)NBa>D{=PcnOQ{Sr}q z0e$6*9PU@?Rjy9FRBr00h!s>hUFiONqJJ7>_;N~ttHp_agy>&`*W~2W@9A*cGrsVJ ztJ6H*M?6{zmoRH1fyuws_2<)&Fk-_*5{y|@26td{4=0hM$YtS&>S52b%h&+%GQk^0 zi1n4Cu?j*3YAZFvRB*S3#=GgQts65lh6#c8THK#IvsVIfEM&mnh38wD;>?-W?Y5+I z#F3m6V3J}30v9;<+iOi>qgs5iL-~bGGUAm5SwU^fdzrS(qq^9^$7zO=`Y>V&*4+u~ zmb!my=9u*>P~Z>1jj-)((xoR|a{pRtgwac+MoIuM)fZ$y87cb^RH!y9=>Q;2+!stB z%tgU|i5`Lb&W-U?h2QM@F?(EU<7>l=9)hE4T6a!~}I zk+#SiaGdbwse(@a)5%dex+op@e4odVsJnH&iJ3TG_UDIBL%#jI=?I$S2f>P~z<%LW ztVH|eC!cNIE980WqYc^3s2&;ws7LQcu$+kZ!ExV_S!iTsMVZE|9;Le(C@wDH!j%(>heLHuAYa+ z1NLqSj9{Y>xU)fyW9RjlZSc+^xaM$qX-z)kR6@I#j_6__;mwvSihy2y!&AYBXklx} zD`s_m>$NLwGGmN=G_$ov9091kkjpkgg<%z;lbW+szFX>ZAp=><~hfS>U-)9L#A z%5i=5+3S!yY)igJ^{W$hx)9%vh}w;mI%pRNXH#-(#y(!<@7c5W@!a8ibTcf?t+KIt z7^8TVl)H|33$ity}Hjx}-Ded<3G~&K4Rb2_<1LJ1qJ*qOd zln_vS(^E94&Q63dR*x80DoJfZOjYz~kp=9mbr4xaN?k&-%MQo8z!^FGs zJ1-S=^7rVxk^nQ;hR}lQHyOKp(|RJ!HBmNJxzM1qT(4q@hudsYfxQB6C37oNwEwLc zuZpR0>QRXG-te;v{DmtrVBvH#`?P=Q7Wpn*zNuvjMV6w|e~zPaT9&1fI>gw<1trS{ zv@JKxMb&fkQb<*sO@Pky6`)zUaolN}8ErB(oUYu|@i|>N?<$b39!wZKXDj_4BeY8= zc8dFzEGIZOKz5B#e=b~XoY#XX5(6(B?ba{>CZ`lVj!q!7>~KChmOP{ce!KQg^R|<^ zhPwMF@3!ddG@le>%M-J?gQ!bj9A63d)D-4#Syz|=4H zZ#NV7XW0FysWWQyUcTrSs4EYMIpQ~?WMJ4f46II{IYf5 zO3et3_jO{L8{Q0{?71g1C(6Qnc`xeMr=OQ&IWhmXcQsPcS*fUR0EZY%k5zg- zM53j%UksPHAy*HklUa zeKmeyjtiOJlZ|~i6a9C=!?^)b?*s$zz7GGNR~@t0>T9id**;Y~I@(BAgjgQZ*DY%v ztl0qO8WgO@u+-g6{eRx+@SidP>r>Wj2uwR1ONjo6-o~V!?m~rO!t{2UQ?m9;L*zo{j^gpVBSQSj6w8xW&fQFZUNd=h0zUNu%S7AS>Ild}BqD(*` zlN!0SmF35LLxDc9Ti~wiwZF<;)putg#l~sJ0)HJqo?CBk4GdhYR;0o@U-xx)hjiQ4 zP1f_5mBGI_4vd{nFkF-qth{Ss1sU)o7sS~2UI7R!fob8GN2lSQi8+|meFC)^pq(Ac>l}Fpbf_yKZC|+%>nW33QO>z29w5R35!l9* zf>j=ZBXS|6g((T<6(&;CAkCf=u`a8&!^Nm28Ia|%l_&|o@^(s->_}fx^-0w8e}nn7j8l-0~D;rJPsnt-@wxy*Jx4U_gc&A(|r`ES>A1Q>R~A5x~m_76cY} zB!tced;CWvwn`mh$N%R!x$F^o47tXn>}lsbcs0l{GWJH0=Sm=I9z!Yvgm7sb=!Q-3 z+d79LZ}s`6#_Sm9DYe2@A!983N+C$e{uqSkPuXh;p_|c~yjC`P{Q}^_63&APX1rtH z2=<$~}MWe3i@2ggmr2wDJAln>Dne zF>a9m==r5=sAbc32fD2P{>2oDKQBrZK^ybBcaQ0Da@l#%iqJdwzr9L!1{>K%ucPZ_E(Hl|qGUzJq zo&h+9U30>F*@Q4_6NgJ~7!b7$or01;O@+FZt7)lUQ}Ohp4HHjpoEMDF^@H}L zhsKr;PY0>9UQpV_kcB`0z3`4J;5}n6^6GQ-a1lRDyDoTs){0=DoOwl<)R{b#SQ0f+ zX|IzEIE}t!Z}*sSQ9&5AnnP)yfNR*n|9cY`QbEOMs!M%Z4PHR+>=&R4!3abSs%;?6 zkL2ctg&Sp@nyI5alrk)FQhj}!Tq%i|o>Z)ne zb6s^7;6z}eG5#@rHg0(CFJKC72gCG=_x;rm2rt0DA4l!AEJ)Mi0yn}ief6SEjbF(s z7}G>*b9|i5R}gm2;4Rj@R+xMhiseqEo?w4@T`dDEJv$y8Bvb6RuIX03QX8*695s*GU`Jn-Slx(t9T@Eo+>Rp=G9gb{wNvl5_`Y8R6Z z*)JGx7z3)9BY-1y)+uvJn|W`Y$8*wulU$<>UcFTt)q_1LukCp(?r~7*;AOy`QsJb~ zzybRKQ8v;-U!^C7f6B?y{NJ_)TvPz-EAm@Gq9%5W-i z?8X*y8&2n#nE4Lc4u1;6hk6lfZt%6$TwRcV|=p@5SO-Y}U&6a;fDbO!uyrFcCQ8GTo4l${t3QKk6u&U3PCnBX=@WO|gS+B5b%n!EkMn6z6v+c#3MN>ICN z%2MvX$8vL1Qb{csr^98piw00j_o!A7k%zBAR!X1gzP#{gVD*S6eMO}ZmzdS}o9n!v zB9|xi^RUvQK!q#7D6_yr*EQjH=xn+I(J?H!>1t3Nj5RSO2_-;?9~yI<{+BS1z{uqY z5MU*YC#n&4uv#E*34t4JM(fIBXyDDwHFg`?JFRhmJa)lDPl#G}%m^Wk@uS?7d~zYi z$)xP|bAA$BB&5|!72F<-D+-Y5l2r8z)k2c!qj2v47uQw*$hHfJmy3rDukRthdPT>!Dy0dNf>`H3}({FbHG6YTY;) zpX;|8*IX>Rwv`wV(EKnJEh!}Vb#o02Z~y&0@$#Abi&9MAR;58Yr5(DuOs3D&_&cF1 z(Un+hjOMM2lUGLwX)#2})Uh3|QvEPR0 z@FSa04GT~Gsvp6J8@x54-CXawFAFDv1@iQv(m!fd;dblb0V8yhp=kTH-gjs)ztEQ? zxU~2<3G0ALV$1|9r=n*a;usW>b?XCp7TBPXECVQ@6D=x8Z2Mqsc5ccKQWL46Z$-Nz zd9CjWU5U}%*10^_HZ!$Af84Jr<$5a6QM23)O3wdP9vz|f41H1U%{|++5BY=&LvE_w z8icf2TfpzTZ|er3*eD2`IPAKh;mrHxOddPbbe0 zA*IP8Ex&2ILg0W_Ts%tu$dK1^ChMGtex z<}2+ELqC3W_z@%WWzF(OvTw2ZnH{zTsU%eHNr<^J!{uH{X_o_GAnRSkj@7^)Wx48N z>fc-nc3=vFLoVyh`uB%4*dCuYv?z!u0|%Eq72Z4Gw|Fh_0*%H^<-Z6WZL9V8iD$t* z1G~mdTwvV@2WwxYil_d~ONe@fLI~DOTyouSgiqLjWJZ;vdh{Vu9JIB_9#kko#f~U; zkP)cdcIK4`JbHNp1YeLx1^#{XH9X2wz6EehFutsC zN230FBm^?X$9mNfd-F#<1u4ozRu>zW>xaxv$BR1(?bi9ZvfZrh{w&+kfnP^!+iyDF z%|ZUQBkZ?4Nrq%$e#2e%>%ab%Ox{+AdA?YWm|OLTx0m(lx1?-yo<{XU^F-t6RmRvw zaQD>yRoN9+hy>E%zpaqAc{ydj8AijQ50DbF#OWMJbk_a8FF_*@pRVUo-|t})7?$70 z0>B6_i`%^z?4VZ?WQYbKW}um^Kk@e|2VIhu6yB#Lfn5Mpm8{vTe`#C6qS-aoUqvE* zwqO6HlJd(NxDQ7VyW0EqfB$FI%<(z)c;hX^gtu%C|^pX3`8(v+L;B!MP_? zM!E7j3&5HY>zIKNBAVg2}0_&$Q@{7Q{h_j{j~m#+9)FKYQ)R0qjWNz z3|})s8S+c&>Fo<@LP@~xvup+*KK;oSOdd$GL?ZzHW(u`t;&~+eU;vIjR9P5rdDL18 zR}~g=Ve~q4C$hbsJ+c3ufxtJ}8?regJDl!^k{|-C7$?()O2gV6J*0GEv=in;D z!Aa$Og%6~2Pz8^2X20)NCkM$tksmNrGpIO?bh)C4yjQf|C$0Y9%Olj`w^evw7`VsW zCJTE$xR4f5p4LaL{UpG=02DP1l8rKN5zj4lBb<<}8=;VI#gG-^ZWdsra*=b{{mhlX zY($jFD*SWq|38u|e()QgHvg8gS(qFc3M&g`$1x}vgysG_fFB*OfOfJ6$uiUF*I5r{ z9*{N+3BiCK9R2^O-k}aZ>0$R3xe_eW^M%5_fz{ThVYZJw)4c5C) z%I36KLFv&EHtga(a*svNp1JY@18ou1&bq?k{X_;Lfy{~5fAq8hCVeA}02v-x?@tJ) zq0&)ZF@9SQuIZ^6d>kD!1CBw!8_L{~VvI+R=H;1Ui2hp_Sp3h0Smp5P(ygqDn-gYh z5=b}COCzP(j(7d9D%RJ^;jR zPA*(PE!>LRg63Y2nMLfy17;v3kbT)-$pH^$wE}DZJi^Rg9Eh*z^$xjEH}w!ms1X8b z8*C2%pp3_;l=gY{5*HA5NseE+bd(ye1z;5*UPNFxs0T`SDgf}FAS4Xht7dT7fmzXt zm)Qv%yvm*tOzGgR2O+#GmEB;Ntz0x5TDSmFxOJ$8~ya$T()ObB?tk z4sx!K$bcbyfUv5@7KG3B_JQ0ngt5@|TV{Lhkk>s11RlKx?8JvSWgP|*Yoc%=mO#l) zA9dW_Rj*7pMe;^fd|86YL^{{Z)^L zO8^`QZX+Tby)C7-;8o9SvU!y9D`)t-FEa~pjh(G>*}@0`+uRW=pzF=p>F^{bMUs(Go3nw!Cn5cS`FrfDEo+SUOnT#ZtCR& z2ogiIBt%~s43^8bK-!ep!bBiQF=_9b?~-0m`JrJF?LDx@-^p88rL!#sc0|T!P+cT! z3Q$TwYwtTWhqKiJi>C-NqQj>2HTKSC*-QGCJx)>!@?!_5G`zsnBpZ+v0q>?#gG~c) z8he<^Ae%_T;mlv-H`D^z%9|qcXi5LA0ZTN&=DA2u@i0uU1dX5}iM%uPLdb>lIsuM^ z`upYKpc{MH0!zWXVIrGu0S%wz3js{Y9_?@)Nq&0!MoQvUcY>h;N0|?h6Fw+5i0&F! zlFMF0>PO6K5vQ(1(+H4;!efv`gg-ML+yI@rc=Eey?okbq5GLh%Jo{Bv+$Rp3-ezNl zWqEf20Qu7a&yyW2Z9r+Jv6+#|-n9m(c|n+bQ-1@}-;iAa8VSZw+TT&y!4_y$!Y~=y zEI5ySh!k$R)?(vK{rcXj2>|)*zl8Yuc6wi?p5sgey^^b8C~R= zpkUbmUr45Yqal~gI}V^gXuZ}7xkIlO@VXv@huHp638G&{&%!GmnKc=Dhu`~?+396~ zBtyPKsYpKHSin2&Q|Kx&;uRz#s|IiS&Ng9V<3Is&W0Fu)hsti>C~L85k`!eVCpH%e z*M##y+sAVWE<9D`!-Okrm&paO+?qaq>3BavPs-Fg{HBl`4>46Z%*+@@@m=)ceR_L@1jJ+Iwm^6fs z+2o~koPZ~}t0>Jk-&S&ueXkWr&9gMJ3A}*Vn6_bTJL24#D|^wN*oE7Eyd{!7L2&AC z*k+s=?6MA;#A2nSsqOqVs5n%$bKoxv#D0X~>Tm=ZpqmUOw3TTxA1pj!kI+^f_Bauj zyDZUP`Wp*C`^ZPsfxzX0Q1gR$w+|Iv-?f=laHWv6O~)BT1*F}-pBAppS{;u=al>s2 z2gDc9xGfoiYaCBWjLO1#>{RsOmHd13c!( zWQ2H+KNufA(TGY$QjRpbF?pI+n7c$X3MhjVP9s^7)JQ9|AkR$*+^G2`4tGdnH*&2E zw7`Hl%j6JUO`16!D#H5qG3NomqhTMEUyv6TBsI+V6wkyjWT|iYgxNE_N}Mtp*zdW& z>c#Nz0C*K`{~)UO$6K&FWyp8Om(PVc_oKcDNscs_Ap8dZd=Y1DG6il|KB=(1Ler~b zMW6@qFft(f{Ul7OQyQ0}c_vLQJ|>O%q^7s8SVK2!8bV?ctg|o|LyfLUKWy-8!U2;M z(Dx5fnH9v;PxnO}0w9qlvT8w-g_6N~ayIl>t+l5c!U@QmMwdY5#|azuVe7`w)2!O> zI&@F63Zz+#n1wKp3|YZ7_M`7%!<(3wp>lnRbL?3|Ak%^_0i3kD0pETYj!!^etS7$t zhPFT=c7P)eW3@|%Ap+4n_6r36Lp>cvYgO}wl)y^} zar2WcuLgAui!&7oR?4ey6m8(%!wNK-k#jo@&r9=E@etLDg5BS3hBD@CxUB`eU%c{j z{a$haxVvS1<>#;i!HN+Hl^Ja2N1pER$(+BQD(fu}TzHW2S98%KhM9)_)#izn#>Az8 zTdVu9FsBbf9YIVNx}iX~cjvWo9->4*mAvTxzHWtl-59Q3pfPhRf$ND2sX=P>yBNlZ zE3#u{_K%M_Tcgua5LCa`eDjSKYU*v*_kL><*4)Yn>CVaC!2jdw&Eu(DyZ`Y$7*Zh- znNpFGBpE|gLOY~XWQa8(dQ^UzZ-RVvKE8wu8e{gWXGTF4Ca?0!B2ETZ0N!4u@9!@D%dcw)@W1O|?RT2O}6VGpyH2oOyEY zFX@x&(K%YtLP-QJ$jEa53ua%`Ytq2wJJJew^<>kBXfba_Hto$g>@A1Xz*YY^p7^LLvRhmc-1TYV z-G_}jEu;Rs)Y=-9hvD8Updcx;&;9a?=zS@ZnjC9XCD0sq@cgV-n@Q=P^=V(4@IdLM zl>c4gRtgM!ZDqfujIM;9Kg<3wd?_E5tkAv_Ha9`X7cUonDfnHfb@`Q_*n(q}$AM22 zp>`nn-{>!cq@+@{`7>|neV@)}HTT=?3{*l08P8~@H-{BDM2)izWYi<@AC4*A zRB)-&ApSCZj?XQhB;8s4WhFF-pR{51{zoP#VnqxeCP<%(C zL`b)3y^>6YXexb_CmBnmQW};>#p~tmj9@ytEmuk16KF1K`i43I(jfOn&iPu?(7@U3 zMeO$GjFwTs;l=3da|#>qhnO)HuR3B#xhtMV@0-R?;$6yc&U$eRpMQx2L$P-DTjXhf zYL#Y)UkwlSYPlpFGJDuRzvUj~F0kZO$+7Azblh}_R&I!1M`I$*xA0~{NUY!W992gA zMQD#0_i#l|PcYa*QJe`Jx_TtxE^twdf@{}vcGjyS1GWp}KKx!=dfx%3DoH{DrzMV? zzA+S-#){2wZZ3ogh0umq;k`?Vo5FIUs6JkoZf6)u3@4$L+AkUY9M^PJRB6oHS zHl%O^g`)4rhMeaqabn42%-s7v+47Kq`jFk`Me<`mzK){==J3kC#r*AUYk^jB?nS9 z{2z@YMhe3|_FIgo0jQIl3=gdmj~-0_NPe{(Y)u3a_DQo|W$`*WO&G9wx|O5kVSacO zrBgnUBk{N+%0{=#yt>sSWX?;N^{SQQOSi=(TooYj0RJo>UIewfn zJSw+|=6h%hu0Z`F%4Sq(1^R(p@{I)Na@fivmrYfV;5NQf=TL2^RlI_!n|krP0Jl!U zX(1k6zYfx~0#oJ9{9|Ya_$nWQmn39G!o6T6KW#Yqac3EV<@$ktqxY%x9YjAHjS=~D zD7pv=-boIj&Q&!%-C)jL0!-MPb6^Jf|Lx-`$&bOIk!y@uI22dSWpYR}JNSvl?GJc(ktNp7Sw}6^B#Y&{|Io19cnbz@w_%2&;VI&Ra zm6}bvtLy4WP{w%#=wNBDSQHm^ZWRe9k_~+6q~?2L`CRpDM~Mbd@mfB)AQ0`VpDuuw zEycIif5M5-IW=u53eO|-|DV4zzG5(kf`e^Rn=FO*cBQ4xdWBXGM6|-Gv&(|)=`4g} zg~N-xkpn9s-+IOT$7^W)$p@8FvUM>S7m=9h`em19C|)-2pTgfc`552H$FwuTW8-QK zgFfe~crC)=&StLyd-|0Yg+<9xf7I;@O8~tDos|AeW}&@_DRy&-B|{!1B`Rr` zX1!9KT$nAjFg-VNX@8HdW!3)$S(h>}1j8tiVM{?&^?}ru7sDK5>;%Rd>>s#9#C>g` z0T@(&TYSl(kfK;}RRF=c;a1<+#~&bDzP8W*!@%!9P*_xO%l$zmqFz5&vI)QlIQ&@5lsRX+X9Gx}VB_S6{;h z2#27#ZTQDs{88$i1_p+!cK)h~-UoCOHzAfH78dF$MT^z88{BL9b^|nJ6&u6`Oeqi9 zz6<})A9XVBcTJ%eFow6_ihGS>FF<%i6@L&^fItjyZgxDXzR;fVn-z( zHk^D*0qU%el#u5=U&z^?sr-0y!bN>03I%_KhRdRn&I_))AkN^8DFu zA=bsVd1?)NSQnR`{4VPdxjEW5{`&>HaN77v@=LATU9_U(HJgYkOg%sl?)o(JEz=^AID30H9p}>_Yt}&5LW)SXBWT9##+*d+PXHBF6joHfzdgg~e zH4=CIllLq9kE30dlCVkLr^7}6x>bB@6Ezme|5xsu3?bAWe<2y|v|Sioe28*>TSL$p z`}NNTUh=d#nGr`TU%vxoSeL(>->90O{j=d6% z?pJ8+IYJ2Sz(D>GNVQQevf;!ZdQEot{96YqY&Gb=l*-#u&UUK}R6X(43%WnQ(ED#V zK~Eev-KT>Tu;;I>yj!?p+>>W5gmbpu1=kn*9=Hu9MXZ^t?6SlKU(#O+iDibmf3Qxe zGhH2o5qMl{x6^04e>QW^1WyA+{;_}&k#3R^NQR%LA*_dWT_>7N#fyp!uOuvQRaa}! z=J+!HpqEv)A}5g(lem0k2)q7J#vmMbjxuL|hO=tzQ7jBNI2QA%du=sk)VV9j6+5=> znSTn`+Eg@^&?vQ4h6GH+L-f@eLNR$4BKKRQudypmq~C^5#^rHO79IBII8{krhuBT3 zxpfQnl&YvTWTPSg!;J2%`z7??+}Z94t7rZVT^F8U2Omr+Us~$E#)W|*4$}ot`Dq&) zttmsEpfl&~cnC%~2(X?NGRws=K`iOc?Z=GtKi+3rI zcLf%ccfnS9eZWnb-W)srZS_&w&}GxPM>w&^`}!wDO7>Rvd{E8LckZguU>&$ic&$2b zgwkmtx-i>T(^5qh+CB}sWtd5u*>7>CdD6t=d}Ni2X_nCO==Tkis0nwsE1b5@>2nM0 z)D>)V;SAPAALdu9@Kr9l^L>_oICYMv$+^=tac?*kFOoeNsiHyZ(d#o<&;0%P9|LD~ zdQnS26KKU&_9_>h| z++dd#AS@;*mKnZzLrYud1KDA{v4cO2n!Ahv-JHr3uULYxW6@ zn0;WP(6dJ$RJM4%pioD6<9S3i*Vl@gs0E6#hnf@Y%Vrs5JnflpxLXU3_=-Lj{|9-i zZr@|qVm}Lbq+X@?|7F;yE_3>9g%=zo`=yHgnxepf>}&%)@W$nd_dVitH=my)9f-V= z?;v#x?<(PJcN|ZjZS9gI%BfM^V|b?N;jhw5`@6#T4Lt5TfBv^@K@u=_wG+Nh`?A#G zFL~+Vsh7@nt4FvovzN)b&mU-y51-DK+qhuQ$a$`Hv8WG%IdX+WZS1m!1RjWaE2S=9 zswZHQeztpU*y3`SnXbb|`LsB0_><1UKbkvwU5mBP)YP0+i9Kd&38{i_!gAVfmt~~7 zXJjXTIp1d0LIW?YR@uN6L=m(@pI^#|M23R`fwYF#wl-b(>ibLP5!$J7t(9ge-rj~w zT@?{Us(?gp&kS67dZ_f$^$d3v*5+@A_~*g4js~1v^bddS2P1TMwWP}nE{v_OxTDc;!3oEUc84;qF_w0X_JFTf8vdg1VJ4U!_N~XDW38Sl@Ti3LU~0yGE+3 zt;PLLTplVkmg3!Z%KgKayR(1z;k$ssqxR?)6Uvk$%zBZ0)hT`oDc%(k3 zwR?izUCK{=!d_Znncot$9o9w*K^a$8L8_=U-9mU>vI+iPJXIt_s>GSSA?1K@h?ZJ| z?Vk{H)&W9Wck*RjoFjm~xmr8LGA8)HPrmLsGXA#bNF4LKNC>S&_wL?BO9c+`d-1ko zBPCV^|6F5)8a6}=iQ($-ECen=E9UdytZ5>5iBq=&CkW$38! zxVSMMTIwrG4WCATG2!ixc*Kb%SHyFm#g+u{ z&Zv*A0@L)KCUc_s(;xwov*JnqqNis9vFHVp3un7AV#VTW)3?z={7$x6df1Y0^pNFu zP_IvX6~4!$7n?07*&Z*paX&hF&Gj-=*%Lgw_L0`X*>jkw5aS2``^^6HXT8KyrCYTG z+unQ{gjw5!doCL|!Y>MCzg(Qu5dN~t5?hf^7MzS|{X9b#>Drio?&Hnna6alk$+^`0 zE`4bA=qbJ7C zWqCq0t&R`)StT@1b=;(AJMp_B*;SpB2WJnOT*W4hYu!8bEHAB2WAg`L-cA#TP4&A7 z$WjgGq=jiJtQYNbak-^_(AfK~6L$fFh_F3Jm>;j5IVf|PxkSGFym*)kYa+Q=T_|5} zSedOg);VSSyPhLA<$tvQrNUA^H|teqgr;S{qQ(GhsToquq@0c9Prg7%;)|{nzfZND!WatHDg(R57ZDqIvqz``$c1x z=H7Cx%dhU+F`=3tE`@%!%YR1+!y&}koASHS+;HDfK5-QgLtz_)h%R3PO6jWl-Ppx> zylw+ki}extP=Y+*c8P@itmB~hDDm4FS13y=rtsR8DyMjPnJC*8m*FWcLu7aS$$%3+ z5+dwh{4b6yIm&t&;=}~m+x)A}wn!TolJL;x)N=UkFTWl(Dh5`PJe_sXWC|)@K!PlO zGt~fo&V3k68);%OT#V^`{x0R6s(ZeuZ6cT`Oo1Ig3N68YT!mUq+{rHLxX6>P(lmHA#* z$kFcC8TM#ceQUek)d_1W_{BR7)bPswNMLCQgIMmpvqP3VGcc43+(Z^Y&;zHG&@Q+5 zD@TGzGb)4=Zj3NV#Vcp}{4=)p?I?(rGmpC5ZqvvgAzFzPv$)hji|;SS_oSL!r(rw z?KvWciM@(WIu0LZ9ZQf#Io%IXHQHT892;d15DsH!b;DfP{w{(ZyJ_ zI{Bh(uJvYqD|WV2Tx|T!`ubE7mA~HIMEb3KXI&imIu-G-6!u@7*8(;H918-LxPMaw z9;>Y59{_7;l}sT%$$@Kbwdx6drwB``&sri(EiCuuY=Ce!A>fy@g>X&{bVBT2EfE=B z32c_AGTk44@A~r%^Bk}ZRXYL=mzJ8D`K?GZIa8PhPhE;M1(t3-*%tO6>AE-(Lc`mD zPtItMB&>oj7=!&>6T- z>k&m~O{m_kYzc=ygJH|{fjBVIPEt|sqCUJ<7Jm1uzj_y|-n;y}zp*!ZR$_U!aPH;$ zzITb`6<5%z$S3XB6u66Osej+aj+^?ioJbMHBtn-uENl$1-G(tZczn<2bm&2)|8~2W z;VK9A+R;6BSqQthM<_K|x%!|ng}<2BK?DTj1nk!q?{$4iGm(I%zHxtcGk8ME#S7Bx z&K6P@;Ef7Ulf*o15h-_4vB`pjD}uSNn0!Yl5ZFy}XPI&zn! zNXc{aQGc}NM3qqD zY7Jkf?wG)f6Y(y|N9uXH4VVS@-#f^Mun#6SnP^%9P1yoFJS$MOuMP&gkrs~|ai3TM z01svKAq1#B3aMwiv&aGo5TcV}Xt>Jn5XP8e8#Y94`mvWE3A_1e{fPUAcw$V?GBcSz zmTrswhYQfSK7}TXP@F0Ut@pl05WM(Iaytg(T*61;9YXHRsj96wzxh#r(2jO&4WTJXdTH*s4%hm%Jk@pj zpZ4@5EFW8d&g(I+yB3c)xUpi8#<fg3q<1kREfu9E!2Jdyi8RpKK^&6p_L_T1LzA8tv&j)3g2{qM+KDPtv1 z_qV&$ZxpS3Buonz{<a#&j2Q8E zhy1D^DV=Fh+Vo8dZk=iyrU~u4e?MXfnBqQR>hYs9NDKGWAT@HtjYa6u|tk6lBm7E1z}`RIT;RI9-^N zuzdTP3A4ZJ-@+=)&0Tq(z|?Qm)EZWH#YgYUmVt8=*EJ%F#DvCPi3NM!UYS_L@Y?>p87|Yh^91-vM#yE=J@N41+3a&V z0pk09zJ2K6hs?tv4ArU|uvLj`8HxxOG7&4!1_&?{^qJ%`__H)iMlbE|)R$hF`OF%K ze1*vO+SyjXmIiER<^{LLkN4k<>OM3QU%73tbVf0HRWX=1j??+i(Pcs7J92h22?TQGBYCMJBJ&o%(< zeYg2x8Gh?3ebBp>3c8Ah028`#BCak_cKV5^+Hj$^$cQrGt1cp`<`d6Gw3EvpEXgtJ zKYOywO(-kXPGrsG{?a+Stw?$`Hom zDBG%khhyD{K~aw~od0qWLGP#Hif}Iz1oB4gMPr_=rhgv^ix1G67&89aJ2LOzUq6|T zlcR=ogT`!eDLxeakQZm!S;6+`j_p67cgm;kfIY1RM_$%7qo{%JxD{P-#FmJ@ls#t^ z;XqIS^>>s?Y}7;DoIlKkwWiy3MSU1;g5|(zbx`;(4yR1QU~1shJ`O+iH-l3VPl5DtGtzmPY(>1*ncb@h{W+*ozFV-46UgTA?E7(+^ zuYy-GP^y^Ti|%8)mMt+!9xpKPaewN9#!7R?I%#flikUx7pY;+#N>sF2#lZ85kI;rp z)1_&xpNf=d`y;s4`9eV9YPXRyZvEeF-D;O5%tXKXEg+Vj$-$Hx2bwL$CoAP`rn-fq7|WUNOqUG%GTs`$UF8I7MBk}rYI`&;hI1j8|ikRHO4Xld~q)FXV2nNx3np-Y% zwcql*+f=*H?P6PxP3M;oemB171Jq^x==2R5-&x@<##2gcz3b$#%k#(770C^15+2%n z3L>(w&lg3nn=?{v!?%t4Mm?#Mb;&)t3E%qcyN&Cg-cvfCi7(s(f!^MoZs#(mb@}IC z*yEHsiD*PhX}l`V_Q=hZPi=VnImOU>&Y1{7dys=IYfzFF7y7mE`x`g)E;rAS1D6FJ zbbAF>I{ElH?Wpx#c55<@dAF5!!R4jiW zoZ18@X#3y!nQF@dxsPMIO(%k9rp+?6)~^qL@S!E8{0P@=Ex-mLDL8EE!iY}MQw@=bog#Qd%20>dlW>#zXQu*R!I$bsu)8}9Oz=FIHo z7k$Yu=1!!xrf^a`M-lbc%jOdxS-ZYM!sZ5oSCQ1|sH3uazMW=#{b|p%3^P>-Fq%kU zsL8FL&8qnoNY}}>haDNfngW>Emfi$?jV(?5&h6c)05E)@W@1u<|-1R4M)Sg%6e}8 z*;gSNXn9E07V3CHDaZy|A)JI;3rce=WbzNAofg8}^P^mB*xP=KNunK?y3qdONJ#*g zSzb9uAT{Z1w@KYRNt9dlgMC1`ZN9!&!v(XY+ckJr$>pxHiWzl)8zcaLDiX&-64>#8 z_`h(s_F`)oeFykA>og>H$n#UV))QK4n|+gJiwT=oCn^1Nma;bKs`)6z!E+$ zazv-EopmudvFaaEL$wtFS2V>B9;rC&ge0akhnBma|3F zsVe{vb&lXEB=nQcdfHP%UkEDGiC!iUnfuEP*JfgemXD-+w5tJF@B{JY56R$if61LX znNI(SXZ;G`T|}(-zWn#SnZwA0S5_9;xE?h+r$W4>jpb7flnr;i*e>)bEYSpTw-X~( zz}VQp{Eo9wDq%(tDumr1C^muN*|nk@B)$rUsH$yFk6dXPDSm4lc}n+3oeS49$Y+|> zej3c*u6X?%St6S@l;2WsEbAr+_6f8l*#Hk38f~V?QYF9tK^9ztkFX@J>e}yVf055lJ|(C zX<1yjMeu9Wr=q4u8!p0mWX8c52fv}`>m{mq?W5v04aqWr?7gja{7+o#(00FXVN>8O zZR|mv6_T&HilebxQI7>TNe;uUjzS5BFq`i@-EYe#&pS_F$b1gYLR%aF*?H85K5ig$ zPjo!RnXa=H>pY-lX4$5BwT9Jw8XUwQP|GXai{}+R?MY(PFnr>^dx4&7s{I39$fo{q z;nP7PK}lKE?TnwllMvmWfdZahu3c)@|EmN4sHj+Xs1sSH!KJ`78s`wbZ;mT&$(aQ9 z53OWxNo>;e{`q$2VWN2j``)71^hqd3hL8ccXADJ3kb>_x;6CDz?lW7leiypHZtS^) z)@8XXiHs>@o%aT8J?~3ylTFoL-$^TjmsZy`<5;jPI~!0#^>e6Qs%}T)0oPhwP>k$n zOUn4rhh((AELw{7_>izs?jpo&|Id+a=m?q6m1d3(+TIj|I7>0p0E!}N;ak;edn)6p z;&l*?gC+kyfQ^EW@EMQ#ueBNz7zR$})RO_!Q3mHQxj1|%!1^vX`tK$J*2@(@i74&+ z8JxVqeczEPdI~U?uDI&xeWV9}0w5)UcPMV3c2@z-3NvD%o#|)m6!+!jBe{b=;|LM=&hq_4;ikjIJh?PeJ%tT zBQ36Ohy@mob~$r%x0B7gl3YISp4e0)d_)k1NiwO0CJzL^wtN~~9qDPl{(AY0iuUB) zRlChU=L+I!4f_F+DeG*R02G+ebwYYXwGVSTi(Ve)6+>MW#rU#8W4r=)Lq8}~Wla58 znn=jXyL&JB2$+Z(r;cA3u5MN+vLQ)AOAFM$A7EgPBd&+sO~?q-SQkiAu_=3p|JoLv zpiu3;CtYGiFOyQrA7~+_C?f%^)77Uv`>|fw*FW^3%M(xeZbF`UH-*cmG$S>b4bvl< zo|vN>C{%!JC*7(I%|%sR9RFevQsZrR>B8CE32)!tLU06L3M1Ywimw`7z{=AvIp5LS zmHx|+(R}D{w{d%Z*?^Kom?0aj)m|?kA+Bx2B@l{cMh%uKw*QTG0t~1=qrOaR^R>w2 zauaPdt3$vhP?B0V?&$n&(0NA{z<)sV`;tUSRPU7ZkTaynH)35J*JhjUkQu4j?lS1^ zxz6o-{($YgaZJ8rA4zO-5bN$lQNWC<$6i0ZN4FFsZ~8&Ej*c=RnppI8sI3v?uo(*I zUT;5KfX+2zaaYwf2(-dD058W$9%qi*vA{ko<(01 z5IYI($qj)cNZ3&`-JQY_bqJPBCoPm>_93iKY^sPB^Gf7e2Qb1SdSz_OX7R*qT-~J6 zS1FXLHJpO~C7Nm!$bu*MR>1%RT$GCh4A2~aXbBY& zRcnhEHFn3HL=jok3@bP%O%Hh%@DJ{Jg8Y_!4@K6SBRlUZp*!N46$omoGnAdWwxg}@ z&=sQmDYm4JOO(0rqQ_zb`PppmaTiS+HlPF8!LYu@U^}e$obdG-Gx6@h4RJ-l^K4V5RD&i&^&6~j+ z5yZ$zGv%Q^u5}`j@MV1|@U-6jChV2mR&rw!j(7gR3X6O}kVI!L6;}U|xhBk`atCO} zOARv)Kut;vH+6}{zJsX3x5BUV(4idA&|LA8VjFWl52RNNw8MRQ>&4dnbw6S|XS=Xz zThjQQ^7C~Qhj+hT?OWI42hKbmn&w^uN#d*&8mf{&~NxUSaaws@ee999x1bNB9arzUn|Wl$m`~) z)P2BeY=cEp`C>d0%xXLUQ7e7cE2D^Zy4&Rmg_}8A2lb9JlxRz9qQ5AE^1IA%-9EHu z{2e+frxVo5Y(v0c-VZykiON_VlaS-^Wb0=DuaITqkc-w#vJd8Y4MW*XH5Lq1D>%x2 zIWo-XbILb6H-g*A85g-^gMIyCu_FeKGVWL={9t+~LmaN&#!zP9+Qg=|8}q$hQoQrR zRfy#2Rcpu64=Tv2yDJV z^yfW1eCQp`xCMQyD0;Grh6{QC=iPP&0Q+9n;)Y&WoS3fJYNsna z_s_~-xjp9LtL%KJh}!bIPkY=5R&ENjsKT079183alZNRD(o5B^eJ1p5fM|0|JtdY1 zrU|=%M3{-yU|fmQlhp@X+r&aZgPiv3FkcalLuDcXd+Yx}CHi4!IOI+jAd12d#LMN- zf5r1wtLX3{`z`4&qMx}{=o}!-t;$gJbcZT;j>x8mpY*8+4cy|h96F`DaBc# zBn(_BZ#Z$t{e8R)@#V+>c4~_QBtzJEA1UI#*ZcDM8?*@#qXQeI$eEyvo%HdF5XGn} zC2aP`uGwA^SBD>57`I<&xWfguicV^6tKU=rG|DAUsqsw(r%T!=i13fjILb*nZW>!T z*13T6AzE(9XrC-&@H#X6Ua9(1o^pTxF8&KJmeGnr7 zaDFTv0c-rgkfcHXdqPEay)~HdPK&^&?gsZm1*`Zr9Wl%~-_rdvhkI{%{A@odxc6r% z9lbU9mjcu_; zzLK@pZHBj3MS3otLj(C}&(uo{;y+PYbc&zMJ$C)SN5tR}Qo{!9c7&@x6foCmidV$w zeJAapH3z2%IUJZHP_B$Ml+PjjpdPXYJ(9xU9xI!Vd;C$?%&x3_>c5%FsxORSfzd+M zi3TahVa|hha9%avZMv~y$-Gj}zglUdW{FL3WrNNAPjR1;FgT%*jVs!!!6R9v5wLO> zfxA^D;50QAH`t?YUVSjy!FrS$8t$lvXo~Dmx{L(>swAd3{9!-Bk)Zl8*Z%`nul-ON z6gz@O6=-L7z8R3QfG>!n(e?WO|B5NTF2ke(ZBhh?&HOblSlcYEU1{NZRRw&Z! zt?ZWuC1Qal>>Y_s<15VUsJRtfL6}g{K1@F=s$77pk4d_iZ>rXR8%749SoNdN989A9 z0`B#EFwQ`PQAQt_+`5$-MSqP)WqyD4Y4B)DxvPYt%4CztNAK0l^L|ERU_>(Fpi|>_ zBz2tvcoS{97Wf`P(-~P6Xs*sH#BmSVxCTU2RPEpBFtlLDkZOLs&(F7R*(ycHsr@1L zZp2~cV1_bREkFf%yT@mPj{pcqs=DK053}gmRYa;|9;X3=K~$9^#yGx~Ljoi80=LAb zc%1kL;N!^zDN^w=P>>R2yCNTks3aL>8wUi+RRI+qpp9B#E|R#3<)-Vy_d}*ZXb$st z@*Y|@kSN)`mP;{h}?BuH>edxb|%|&WTDIi zbJ)!LRk_O)1@U)EgpbmTa%`PAD*dBk6MZ8`OxQ%J^~y3+h{g~|DP)Pg!fEoY^Jw;r z7T~wfGt9V$!BsHkM}W<7Sh>I)oEGz_z2B*XQsIY(kxeGN+qF3pcm5g|7PVz=z==3K zT#2l{YtUjOR*XICCLU!Lud>c=z+f;hK*Wlig#?(l;=qETJ$DD+ML{aNRbN4}s)oP5 zahh;`vFe^u*#e~k)3L-;W%TY7hr%o;ni6_N!;Aq#?YA5#THv*t7)7e8uu)}CXz`Ez z9^1@kT&v~SePH}mDGneqrm0X&JLKE!<|sYAwF0wX|;UGPzkYr!sOhj%6_9 zV&xeOi@g?qO<8wGZOau7Z^?`D@GY4J%e8CjTPv=8@A2D^9_453*)g*=C~f>#Xp+wS zF`pxcv-J%GQ9~KCCPde8Rr1d5Up$9$SBQNd5bBk66T_j(iJXm{SS%vstt|FsyCBxGB(;^zKmk+Fcz`aNSngkuE_J39% zlpdSf1skdT^<*7=WZF>%+P0zbj^2AC`0<^7wb`|O0v|s=YGUpubzROS zB`q)yMk=RE`q*q5kjL6jTZ8UN=N!*>6Y5-Nr#>8_1eGrFCE(7qzQpf${_WXt)nF*o zWas6M6*&#^-Y9OWjtGydxhWa7@C|$?RTB5A#I}Lalbqw1lU|{sR{67wcA!>__Z@RW z6-f7$Wu)$byMoeca`zdFGL?0-lzx?NR%?u?qrc6$pULFfG?l@ju3p}EqY!N z+_n6dzh20-_UfB(ianZrc=mM?Zx`7vx~4I%Zn#Qv=p@{agtycT4X^1Vttb?YML_h* zkZ%f&BwK9j&(VW+$y-+btFcGZv+Ckj*Ktw{#MPthwp{un;G6bULuGIB$=_p0RLBt7 zXB?rQ|5|^JYGun>#8Xr)23M;);Er~LE3zrO6vZm-B>gj(g{%~M8TH3AN%xo7R#7rf z0c{7UYPI^n`^SPq>ivJaRHTgg!i;^FQoOtZT~~_MoJ-mtArAh~SCg%uKT|~y`>1MD zt`^SAkE02%k898Hg&Gy$#SucseO$nx;puF2)~W2U;BTkia)#2u!}mo?&yI#hUq(Nr~UM3@Xk6i=KdqR-F@?oZ-kRbK zw5QtgTv8LmHx?*>;-=46&2GWBpVZEDT*8$Y0FMa=;hcC_;gL)Y?7wFUJoag96+&^d z=#b-wQr||=H|qZ$D0?%+vBh?*zR48B0TjWykM9L@z5@jc`z|fkbYM<^F?A;B=((h= z1mihCRetF><};VZ#MPGH&uXt;ie%e>r#*TRA@s?)yO^T{D6B3lx<)$*m86qjlha-u zCSI-rAn_1mu*fqZ8I8BTy&t}Af9>ZX#lAJ@xFW65EXOzB>UxumCCL3Y`Li4C)p5dY zC@)-*%Q5@Y>b)JYWCefSt2qvEC#T_Te*@_c*!!>z|M-S{mkl*DiaXm^V8f}nT8lh- zT3fG25**snt=DtXeXn)+ZQRllDm9FvxQ+vYlVEe!F>=m!oG|?|5rZki;DYLP^8Ia(x5ZZLUku(a=L`Mpy=svCcf0ilMYI9iK$Ex~7pjoO&H{qpHtx*A)wV7y0TJ)6~Y>!0VVcs%yn> z;yroP*ZCtj%u^IN3@1qu`bXBP+;c(17#E8=xGe*BQj6Ten|Lv`Tj^*x67 zA3i4+>%=TxBz6d+1QYb~8sv@V3|sg|>2;5f`TS~tGc1KCF;F>L+a=w4?G8scC|tD!4%W+X9%3wVi9?rh0EQ{JsrkmU5&P3heOLiqwFQmtB#&{+eWa=m}iPGDr$Zo+Y0jQEY$6Xg7uz~p8w>P1^p!kq%6y6W=ea_GHF?#~VnnQ-(K4l?bJqwe0SMvLXsO zXMuUCexKx*&I0u|Cq8enW`!iuOZA0BITzX6ai4RT5i(5MU56Yl#=Ujo_wXcm0oTi2 zWZq@&xYWi!Jp3++HL_yxLLe|Y?(d!fp=>(F5!VVSw)A?~Lf2N#Q>$M{b7P*jC_W*x zHRv}9922rGw)d?|a9XHV|1DvDsPf<}&vx3Ow??XK#yWqH9`9q^brVa~>RW{L)ize7 z+$X&p<79tm^Ebtvw7Z^nLaf$;VCk_|=aSlKX_jO3)lY&>xN8R$6)(qPa@s1n z?8Tb#LSh+VuBEEId$ziUk@izuM`E1!l|wAoM-QB9H2ZKgLdU>srjM|KSZcad_j4SC zu_1WUy&hFGaY0bmF0PpnQfTh=Z~)`fsW2S`$;g|Gmw?|Y^PWA|q}MQBuPuIY!NET0 zcOBUhk7G61a9wP;6(=$xVA-W?iO!EnJb6z3$f+l98oEWl3n&P`(?_&+L%{W2ug3)D ze0b?VOzrp~B-=SM%@POd2kXOPMGvU)lIW(>4Z@{+Sq)|_;;VJ`(q zI&clf=pwcHqiAS-8(U)cB{3S{XW_dAJbK*8dViuMiJkSoj!sV6SD!uqn3LWchPDq< zWfBJeVlDyqDPgbZu7`|ZZ*^;h=g77;tP*F0otNs~39lq3uI>}m?qFk0=Ze|Gq3jLv zm!^Eh24xct?lj>i9rr|#l)Vgz6EWtDd@8i)ImF+I{ni3J%XR#OmZjXvb`1|;;c%FY+U-bNSRqb`RDCS;5`-c0&Rw8md zpj$o?E?XctICxS0dU?6l-Sz!vq`Jj;bv%+(JgD0DX|bkeEEKVqJwf#T5p7@gJDhj) zN04$qD$Nb~nI_H$@8T*gK#P5GT8luZ&MOCw1HNh&G(u&5gM9hvkw?<|jxQW6djn#u zjh;g4FQH#@VfTOMZ~ijxU}zK5f&RI#=W1hdaO%pC?eB*otCyE=`gDnBYJr`0;6!3k z1dir95_2>4oK*K~kS99L@h_7&W~1|t{=&=47)lHja@EguplS97+{q_5ITbfqad2Y1 zIL=2Ri4lOq(yg0kgKsn8F@N{JXLm|W=q(sjgIAXCr!YGOx6qSe$v_o%;R_|sBToFE z-rHnSJA`6q!u)EEd&D17;N1}MZa>FkbGClqls*%WKhO9*5z3q)eC{jMQ>fx|L&Pu| zEh^9xw{nHyd?!0@xZtShV1N9O=(-Xq1G>SSVUKf3*BNp;khG<|a0cqpy-q4^4Bzqd zFECFMwh)Oqwk~?$N~1&5JJjPna}hI!Xr)_3?frSY>GF|?aQcyHFE4V>;l>6)pnWsk zRh~du#?v=Mf4^{WKc^MiIHT+I6xJCZR_K1-Lms3uvRR-)Fpgp3`1$jMdDV++?=$D5 ziH;f-xU)BGZk5wt!@+*Df$0vEwV(DQbT> zx7BrygyI#0OKm&UV2Ymf^%RywkDPrHj_oGpE6GBCV`eU&ZXb8g{c|$sfVKV18iwxkW5HKO)hps%rHP8{K*{ zp9Te;OA;%|Xpn!$3|zsUQgDF%a?K6q15pJL1zbuK;q~=-a%uG@!p$p7_XsK0^?Kx= zio5VPcb$^iN`Y2&jADAp5EFjTaX~u>cbl0eQa-E1(!2Wc_SIv(ZP~C0lAz@!=#i>) z9SPWVx#3k+SOY1pcyU2K zq6`=5bKSg;kRKCXh24as;ejv#g)iFD?keV`vVAUJHfIK$%#$sfIy|Fqe6i*P)pDVO zbmrALg11Uzf=1OTqrzv;Z7nQw9FJ!Q&aqgzw1cPU9z!dcGdzdQV6Ul2xuo$Rd(5v0?h%!E32)AWvUxr^XV_0kaosmc{C%G>8ovu9%q#}?D zbd_(_`uv(M4y~eO8FlI{yEbT6pXR9vrk;(zBztyWZ``U|FnH%jR>Wv#DK5-!VweiV z2|lp<{P`-PeibhPqF3CZj9NJj9Gz10@Q(F6DxhfN#5R?Q+Uod-dW(5$jRyDc*X9qc z`s`)KI)k&Y=UwEjBqmt`XYs7-#3rj~|NW>o^38CT!=TFcAoD%iD(1nSeBS#WE#8q^ z=HZ3WBX>`_N94mN+JlboEIBQ5#r}muqd4dn^DEk?F3*q|c)}O;1s`nP+gxR5FZ;(leTcS+r3Y*2i# zfxZC&>06PpHqb1{oM%WhFk2=%v9nOT}X?<~Pqr;^%X~pI1 zS!dc(MvlJOj?d^?&liCS(=l9I4EN@0qeDZlUyOrriE;t6KU@h7TV{Sy@6i+zYHWI) zKGlU^GZXzJsM4BsP#da<;T4k;9dM!#iAk@7Ke{CI!SP-ep>7|;rgdY};GI0=o#g4& zX^0*XW$!qbl)W};Z`g6A(RUFeXQYh8DtwqXvc@?)jf$HBO9huAOwKyJ16@uG5W;cK zz;$rt+2*FFXLXdF90`h^pqkl~91e~=5TUd=y}9l~NJ)D&;6E*VmI=*3q*<@@s^Cq* zIS!vc#}isig3bz1ec+x#el;R8+1B2PdwAK$Yg}PruibNWMnf0O$BO_w zn0`q-8F$j}js|;|9ao%~V)TR{7=p!THa{Q8fbWoy7#v9zubDWs`TSg7>_fE!hxKZ| z1>AX6H!pK}h{p#O?+6@(JEDDg@7qn$T%ejp+PQ1MJb}IXQF!ZHq>FveB~8c>&sGJh z$dc(Md^g(1>x>`A66&@wwa+@*e<6Q5KMv11BEp`4u!5D2r3C)2MEi|R$D8(q$xT>$ z-O-3pPMklOeg%D*@WTMkLK?VLg^!U7$nv&+$LKwf59O3Zg!X?e8`LSy&n3sn(T2uwtdyi&yxSNUU3IuITPif|EDi$V85&`0=XT6c-9)4u zfjUBK*(k(Kf-fJ6KeqX2AKw-6>?E;q zrD6I;NJ0cI@9XDtk8NX0@j`KDf)I^wV%Knug$(8z?y_hV55(v+Tvdxlw$W$`zeKHG zm}Uw*aP7BEpFanY4bf%6<(XM`Lxrj0Qt)W* zLsXw46^%9zWD>acE70OYGGNiPh67F2?_CT zcS#>y!R}nF=^6G3bdG)6M7LDG0+KD&v5E)BgBt{R!-``o>ITh{7jcyFXJfkSJCSCI zb-q6i%NEFO(;Y39EBVV*Nvwvx6k6-BU4XTK%r9yNrb-er3J7gOhc-AB1q=F+jm6#4ASo)ZrN2;e zT=E$Q2{!yE;Va4Ae1eJo&%afW8vOVD9UYKKm3ti0i9%?>~UB{^u`JK6I~b^`=G;aBbKdz3&2#B-*i8yl<1 zYV8_Y(Y8gtD1a0wB}fzRu2AiPT4u@^06ScO9ff7IeC^`2U?mB(sI#gJ1X{Mu%A(QwkmN`xq zAb*EhVB`O{oVzyv7xi=bTJ+CJrN%(mO{3mciE$L|fK>5pd3F^kh$57O|9Md*NSvX7 zPqA2`;fL8rsIde8{n7({ymjMz8*x}!KO=3w@kxii$yU(^PSw~pj!;{$`FH4gBX1>K z?F8;`5;h%pAq}#LLVHf43d`oR$de;r0g)yz{RH%QJ3G9&X#^er@#lqf2!L4F-c9HW ze~kK?k15NY+DU7J1g_||Sp+-woc@1aY5H}4D7IfEH+R(Jsvq3P$m!QZ_Q#eIt_Y`vncQwOO-Iy3$EL;WuR8#j;Xq14RIf)atr zz5RGOXE2W<7`^5Afl<0}{1i%5|F2i}B40o)RpS4@)Fuh9P#K`S2`UFT3#D3iQd2Ab z+n!VDb6)?qbwO)xDZWH9AG<$F9acv%w(e|C1jVWJVlEXz8lYB{{415B(?t3s0sL{= z*9PQhExq~k5WsQ#G*31x{bvk>tWl0X*}JKl>e;(_RN$6RN52oguHm=B6AzSDRa zNRWGA%ef?dn&;YpMelN9{D=d^N{*~qE8Jxt)QVvyb}{7ZJN{7`|9m(bXRq-c1ThnT^q3I#lfwvZBnEjSx4NH(Ye-g3P=9O;~Xrehg!_D{kEP> zx2RjxuVpMcbP?0#`_3WXfb<2<;{(~4jxQ;k>_(58B3?N4LJbTMFRGLHpiKSD$(Y>o zRD@rGq(PhN_Y^FgY8RB850|dWSuf)fFlyV$Ee#Zdto}AYfxBb?)zq(kK87pqs06e@ zE>D_^1#m3M5M;d_$)b#Yjnfjibu1<*;Aj)5>*9-7U(? zpFO7po|Q?Bc5K|hIuoWCxC@D=4=r0=O;AU^?=}I1o9XK!6r=J}CW2)Pf`^?B$5gnA zxQMw-cX`|EaeblNQq~;}wR%lj4SI|2a?AU9n>1y_=!cdi*rrCOsE?No@?4>)bj=ZC zO)n8Hs6mM7`0jvG52B$xz}27d@;T{@>|coNW1`PPk+n0$g^x`Ae!;?F^TZfBiPlSz z(Y{^}6XuUC?;C)Z+t_)%JOrr=DPSPpg2qzY#6WtS*1YQ82qf%j#Pi_KfzdIWiUSA4oV_WJj>v8hW^7>vF*d=+yG;`C;P3 zpf?y1Qu45)|6hA={z&!q{f{41D#h(8Qpv3j8WbgDh-RILN`?|nS80%$qzuPx(5#+r zC?ZY9&|u7P8g&vH3}r4S3L(mn>GRmnr~7){*ZVK{{_yp~>vemc=X3A1*IsMwwH|Bj zy}6^wZI?2id-yepIi8WPOQ-2eeP2=kth9t@gDcJUCh~AyAsoA}z=KLPfq9J{kV*}3 z-4JngqF(CDLIcLF&LKwr41D92$QsIT|63NI@>gUhW}JwfWVgX@+IJId{c#`fI;!Im zT%{?%X`B$7o0JYKWIN(GBy2cJdRb^hJ77!wiB7DYZY%dwqgmQue{@5j@{x^~Zf}g$ z%3Ka)=`-Krk#>kXxq$B|+{%rfXK^(8mYd!pc@otc%WiF4bbY2Y!h8}r?V^LY+4J7o z#HHxhXlAeN+9HBH8;PsdVOm>RGsfhMf3LJm`K39(DlpjR&&`x3!njUPF%M3qk zoWtC)62jEF-&}7eIEhYkq3JJt+@7KuaqCfSQ@hCK`OG@swrtq;%dpD|u1o z1_m~2hKSyBY-H0H&B-GPXUU5Y_`^lQUHo;$Fkk}`SV0t7ETizGcD`p`gYFX zIEU!i_r?{XQt(nEQFImqvd9_R;(_vic~mxv){jOw@C1>@{)C(B!&oV!YNb>picfVb z)!Ufc9`;HHWfO>_a1PO@smSRsl7q()ZYSjY*uOo^0`sTdv6$=QX>{g}m_92ftFB1T zX*Os2g~?y%#F;h?n&U|5!Z=e!xQ681%R|`xN-dQEpT%=f<{t3T>-?$x_f1?}|LE|* z8O4s{T&KD^piOTGfQC8pFk;=J=TU%_S|TD}um%fS4brMOdJcHnypFZ?a^wmIGk%P% zzeF0tcC_p{^hd5yO$N-Z+Zu#)80n@I8^{(0&>Kv4Z0^ zxBV`>HK#IIXHoBc9A6nV9c`L4;}O@{QHPR$9aFPuGQjjfS@T71L_@HxcBQL zH*X(3Al^}8ZW~I@1mf(UNwn|%M8jt@J8;I7oY#zwBxHYqsdpi*(6(w&uiWpbnZq-{ z?}&JQ5q96h^hnN-)C=p5jx?Bd$P9*=q(j+Ed4)7|DU^Sg-*Da9;gx0JQN7D?nuv>g z#Pi181htKxe*m*Ly0QAECIGE*snS2YdXOTxrvE10T`XmKpa)MK+00qjw{?Y0{u)(U zGBLoy^`-9}(Y!G^2#eH#f5SH-XO-SO1!gX2)>4z<#sfpd)5dr*u{7!>n;?a-?q;>`u#o z^l-GNpf3J4Sue;D!{6wYFAj0;7=1B4^<}#&{V-El#!&~YrKwj8mLdC+dtd za2lZcQ;6zcnGcl@Y?88jcbBpH4)7GKl-ACn>-H#1j4o0VcB=Z{rKV#8xQtGX$TjBR}a5KqQ=Ir|`9~%^? z+r-V5rWHx6+QMhO4#%T%Z84xdlrEOF5uk#3PTwd;06zjH_bRA1&Yboe0Z7S4Sk_Y~0k z=75yus{Ztt(mu83t$Y5cP6!+5mw5AaVz+o+kb>IYgf3oC&%?_lZtq^n*;Wh%KdF#; zq@B^I1MKrCkQN=Cbsi86`M4l#Fwzy#75&=La=vsp@6H&Dnoo|;qSrm~;Mr~U>FYmL zfb9zV8j0C`jBwBp`Mlus&imqBL;@PVj!H9+)p`Lq_9{+{*=!&tiI}woLWyjlr*_BA z`nERs81ELpPNe-wi)0fnH#lz4A*=y)xBBEWrBn zXNc+BRgm6W{II=E)4T7truu93uRxKW z@HB$2B&8Sm>t*t#yBgOH?TK9a_kJ-&!6{U zbaR0ST!o5bm+FJLdqnyH2%W>@KM}t!chw`elPt#Z57%B6cG0UZw7?SQ7)?Xjn0jCV zt1!NfA2kI>H3L|8$MDX;*%;M3>ins9^(lc`fcMTo35rVtYE8Pr$GRS=zX>}9CkHH# zze>Wm{iq!X6Ac!(717gNwr7XGXpUU3^QEws>-IM{Lvw>z(WupVkrabMk0xSBFa+;< zcD*z9&OZ3-*OLwOwi|fy#2qE207pavq-IR0Mq79NrF>^DyNATx+Jf~BuaS-&T|6fJ zob#LYS4H%$)fJUP!aXic-Zv(4OzY&D-*Gm@8#rJDeg$pxF0(rj>4SU;-cg?T)ACnU zQn+b21#Y{a=h>x;NJi`@=h`+undS#a{E%t{I(Fp@#v)QTdge4-*2b>qz}Y@c+zg7@ zB^kfOSM#+QstKjUH6re5qHZH1FpZodGW|8lsnww@1>Bp@e57kW{ zQ!I86_5N0V3WrcG)z@lCQuoMxlcP)boqUpzGXOybc{fprgL;;;s7Vm7mUkF8XWZuV;F@4Zk2T>s_ic%n{xV8(lm>{}>X z>V`(WWi+aYWQ(utd(t%b+l1;qnG{_SYmo>s>k0X_0~Hlwimqh~Z53TdyJE7nOnUSG zD&2dv_K(s2qpKHXua$OFN{x=4T(*=TO*rsCzUJ);yX4N!%XD-@UAeQb9CXfHFovd-n{VzhpjWse6Rc?)A8F*5 zZF&EOR4Zyg9FY~^VenEr#vYKadCP4Q>p%4FFT$9K+sLV_)Xn&xV}OBf7Vr4AMnh2O zYFzzy4X=WZ?Kt}vkt1W+`-D2VD_8kl>L|xGsBSY;y@4#^66XVSg6L0f0lY=4ah~wV z4H#m&2*!(QkdE1C_``A@DfH%dxf(|%E)1-o;VKS_&;h#O+#JLM>-?TwbEt|z)sPc- zLe4zidwI`9Q!n()c^gfHpYt|u`J_yg4?kX>3G z(eUllEZ2y~O$rqa!imneeRSM*+R_m;JKl#Wx7~LbCZUFBheLxF`%kRC16@JxJ00Gt zLH&a-=R>zk?1H9X4;#@GZ5oV$vZA(o^TE;Zd1EgBi2TBnu|6Fz3?8!Y(8n!vZu}?( zq*N?{BDj#5ljUE#tFAv?I{h4ZW00=xqt=nU@3{8{*{jdp&!MX}V?K}-ly}6?`$4rW zKW}9AiKRwZNum7tV!GJO-_W7E0rx&C#9e97j?F2ek4e6{*=M^aZ(0i^imtetN66ftQ!Tq`g_b8(sz6E z|IWg_wRq#E1A*FcodYnF#y=fl8Yf*jOiwhmbPWCf+mi-KJ-F?W1UHXOGwxiXVF>C9 z*&mGyue<>Dr9Ib&XyGe5SjUYUOp~8#fHK_qcrA{6H*!}sNh|_c!4*FqpVcR8IRD>o zWy7q6BRA%H+z`9{>fHa5gWmeyXG0Q{ zbXJ*tgCNcGSpC1_tOmq)2ke;^+x5Nj-DVvW$6_2?)QMApQ|QxAVjnY5(C2U!%lJMx znDEp5`mhn%85#3kdOOg{%?&uH>xP>~M~;mAQ{L zD^IrOjr$%f=8!Bhjg2GISdHV^%YibpXH0>X7@Q^$Ayulv%p^JK@D9L9&KHq@ljrx| zHKlQD4jq6%OrD!V6y>91;_f0g(P`eixyu{nw?MHF3H;|J>}F_e>4Z{Dz!tUefOAX- zjBVJCOQy?wcf4zN0A%+1Rj)$*r!OZ%`|Ro;jxdl><})9$VJWELyb^d!7hr8~9K>oz zBY6LqneAuCcNFa@!iG?#Z*?6GI0D(@Uq*&l(&>w-p-E&NB$~8pvxnOh zeHXL4wPSFU(;GF^L(mugvE%y~A+Tx^TX17e=^+9bA^TU93rVSr2A0u#T^R=fmiah*$W0B}a}(y(ip-cK zKPic&&)jgwI3(24@yamW-%)3Ofrao=9A`@CWGlW<<*g11P#^-#9Pdru6T>PJch?{A z7-sTeOcRdN&~gn~Z%3}_0_Dsw1}W-D?q`}{zdXq3rd;K^+r z@}!~>FH$mel{)9fr?l8gxRV-yOe@4pM-?L&zOO1~n$-C=L`c6!SEzGtxMOp{w6E1j z_rW!)M2{(BW=3Y!|A0c=8+ZM1GC|#cQx)g#J6(3YP6J| zY^G-Ro?}CDhxYx~`_W?T?pu`a@5jxQY3nY9MT-MRlc~A4UaWqfxosZGoV@5r8mGB4 ztHlo=zT;2N`)7FA*n6`Nh^8f9grCoHn%+>(Y9HO5(D`<;9jJf%g1IdFttV`9v{)3X zo!9jS`D-1q^E~!o6Owel_p0FdgHY|>SsnN0tM)TvxJ};!Sq!k{_e|y2A_vDD9QF2R zp0nxTzM--w6$#b@KNaFq>a!0GT7qZBo%v^Oekb6KI7~o{s}}3wkB8fU6f9hajQnN; z>+fpZlKMz%4@F#8lb=&dZm4{lNeqayIZ!NCxA@Ss_j`IP#jG@M*L5zbFa6jux&AEJ zJN;d|;=Z#qAfw04z)lIBd#HoJi9F{}{%90fusPUUD)^2FYBA^5&oQ^vsYWQq!O1~u zIlr?2Mo8+htn__rl+#b9tx)J42iG4+mtvtz}E1y&>8!~WN==%H5lZUYJL+k9v9%2D+ zo`cc2DTjdR_h!dz$y+m}GbT*j9$v=x27YN5-|24d8hq0lzFqBDaz@6iYyeSZ02rwg zme<=v^ui4$o;~ua3l&9HB9ZF8IMf3g;j%6qTYr$ABCe`BV8E+9S(fUb*-?%MN8_NP z0)QT~b=JL&#**d~D8ZA*c?FyIuzG-%qyfEnK&qa*$E05$`mN$lZnIulcH`2rV6K;Dt==Sip__BD3*n27n(FbAos%{R4+@6CF5L z4kLOUpEGXRC@Yyr>2Fr`s8=7d^E|n<5He9`hSZa%wK(y2_t0e@pz;k(C44MNpqseS zT)b&1&cjmXW%Qk0J8vE0=ihs^Qw=@OJa1M9kh-2W-VmAP5Sc5YP=+bJV{PYUE)HPT zisaxDJyFqN(Pkz*(vnHK72AwyWrt9ERM$ov%?_B*ml*J0S)^k%< zULrM{GemH%6fpnKn6-x5(e=`tOHIZ-#)M@uE~7rW&_`nBf09S)luA0W9QyZGR-9+#!Mbs#h^q zgn>8bH3}wh_FqJ3DiL|!{!^UZgk`$(-o_%>x_`Z{$b_Yj1E?fC%y)#vypT0u)E!rvzB70ZGU~;PpsGTABGv!ExUB{1iV7^`sKL6%-Vr3 z%R`|#R{oPqzhQE65eeSG=`nwViS#qIh0MGTV6llu#$jWiJy*?6Bua zsK<*q{KE1f_NG4oiF6?lJ_`AGDV8dQp&FXfAvQx=`PyT}TRY)ekCTiD*y;+2~nqCBW=O6d=N z8y?=EpL#dVXO-93r0is;p=AOW3-45W)5S`nEEfOp;<=(K*UsH3vJZ*8B#e4CucbMY z-Cq5^QZG+uR5@Q&u`jWCtYl@pP1V3YuTd-(OU-V~THfgUXmE#;{im8UX5}>wl=p!H zPPK_Tqb#;nXjUlpyou127GMJUPJ%wA5QW>*rDY2jU)~XL zIHUPDtKBwLzDj~qoD*dWeXsT?`W#z42_KY)Nuwt&dXnMPM%=Wld93BRlM)Z^zhP<_ z#Gl_X@q~A=u(GM)v|0Ee7s~LUQ`fWR-|*eF^Z4$WX1b=-#?I$crDbdGa?=n6T?7m0f&dYHee;0elcjE%WW0IZpqXcoiSf*(`Igbp;htF!<(j*{sy&!$&_Bh2-c9>=UiapBhm)agGr! z39Hc&@7c~xqvm41vo78&6z2M>#2Qh)J(&i-c9H3? %fZ^x^;w$ap%)!$?n!1c8@}jVTDByU+2rj6T^!H!|UC5c@>`S^Q06&
l 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%0Aq)z;%1ve1#T@*fG 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 T-FK~oJmRc1S(Chq``7;iCg>^m literal 0 HcmV?d00001 diff --git a/EgwCoreLib.BlazorTest/wwwroot/images/linuxLogo.png b/EgwCoreLib.BlazorTest/wwwroot/images/linuxLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..2afbacf6f56a6ee184b7a42d387c8ad417479655 GIT binary patch literal 23552 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 Array.prototype.slice.call(args)); - let ticking = false; - let args = []; - return function(...rest) { - args = updateArgs(rest); - if (!ticking) { - ticking = true; - requestAnimFrame.call(window, () => { - ticking = false; - fn.apply(thisArg, args); - }); - } - }; -} -function debounce(fn, delay) { - let timeout; - return function(...args) { - if (delay) { - clearTimeout(timeout); - timeout = setTimeout(fn, delay, args); - } else { - fn.apply(this, args); - } - return delay; - }; -} -const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; -const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; -const _textX = (align, left, right, rtl) => { - const check = rtl ? 'left' : 'right'; - return align === check ? right : align === 'center' ? (left + right) / 2 : left; -}; +import { r as requestAnimFrame, a as resolve, e as effects, c as color, i as isObject, d as defaults, b as isArray, v as valueOrDefault, u as unlistenArrayEvents, l as listenArrayEvents, f as resolveObjectKey, g as isNumberFinite, h as defined, s as sign, j as createContext, k as isNullOrUndef, _ as _arrayUnique, t as toRadians, m as toPercentage, n as toDimension, T as TAU, o as formatNumber, p as _angleBetween, H as HALF_PI, P as PI, q as _getStartAndCountOfVisiblePoints, w as _scaleRangesChanged, x as isNumber, y as _parseObjectDataRadialScale, z as getRelativePosition, A as _rlookupByKey, B as _lookupByKey, C as _isPointInArea, D as getAngleFromPoint, E as toPadding, F as each, G as getMaximumSize, I as _getParentNode, J as readUsedSize, K as supportsEventListenerOptions, L as throttled, M as _isDomSupported, N as _factorize, O as finiteOrDefault, Q as callback, R as _addGrace, S as _limitValue, U as toDegrees, V as _measureText, W as _int16Range, X as _alignPixel, Y as clipArea, Z as renderText, $ as unclipArea, a0 as toFont, a1 as _toLeftRightCenter, a2 as _alignStartEnd, a3 as overrides, a4 as merge, a5 as _capitalize, a6 as descriptors, a7 as isFunction, a8 as _attachContext, a9 as _createResolver, aa as _descriptors, ab as mergeIf, ac as uid, ad as debounce, ae as retinaScale, af as clearCanvas, ag as setsEqual, ah as _elementsEqual, ai as _isClickEvent, aj as _isBetween, ak as _readValueToProps, al as _updateBezierControlPoints, am as _computeSegments, an as _boundSegments, ao as _steppedInterpolation, ap as _bezierInterpolation, aq as _pointInLine, ar as _steppedLineTo, as as _bezierCurveTo, at as drawPoint, au as addRoundedRectPath, av as toTRBL, aw as toTRBLCorners, ax as _boundSegment, ay as _normalizeAngle, az as getRtlAdapter, aA as overrideTextDirection, aB as _textX, aC as restoreTextDirection, aD as drawPointLegend, aE as distanceBetweenPoints, aF as noop, aG as _setMinAndMaxByKey, aH as niceNum, aI as almostWhole, aJ as almostEquals, aK as _decimalPlaces, aL as Ticks, aM as log10, aN as _longestText, aO as _filterBetween, aP as _lookup } from './chunks/helpers.segment.js'; +import '@kurkle/color'; class Animator { - constructor() { - this._request = null; - this._charts = new Map(); - this._running = false; - this._lastDate = undefined; - } - _notify(chart, anims, date, type) { - const callbacks = anims.listeners[type]; - const numSteps = anims.duration; - callbacks.forEach(fn => fn({ - chart, - initial: anims.initial, - numSteps, - currentStep: Math.min(date - anims.start, numSteps) - })); - } - _refresh() { - if (this._request) { - return; + constructor(){ + this._request = null; + this._charts = new Map(); + this._running = false; + this._lastDate = undefined; } - this._running = true; - this._request = requestAnimFrame.call(window, () => { - this._update(); - this._request = null; - if (this._running) { - this._refresh(); - } - }); - } - _update(date = Date.now()) { - let remaining = 0; - this._charts.forEach((anims, chart) => { - if (!anims.running || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - let draw = false; - let item; - for (; i >= 0; --i) { - item = items[i]; - if (item._active) { - if (item._total > anims.duration) { - anims.duration = item._total; - } - item.tick(date); - draw = true; - } else { - items[i] = items[items.length - 1]; - items.pop(); + _notify(chart, anims, date, type) { + const callbacks = anims.listeners[type]; + const numSteps = anims.duration; + callbacks.forEach((fn)=>fn({ + chart, + initial: anims.initial, + numSteps, + currentStep: Math.min(date - anims.start, numSteps) + })); + } + _refresh() { + if (this._request) { + return; } - } - if (draw) { - chart.draw(); - this._notify(chart, anims, date, 'progress'); - } - if (!items.length) { - anims.running = false; - this._notify(chart, anims, date, 'complete'); - anims.initial = false; - } - remaining += items.length; - }); - this._lastDate = date; - if (remaining === 0) { - this._running = false; - } - } - _getAnims(chart) { - const charts = this._charts; - let anims = charts.get(chart); - if (!anims) { - anims = { - running: false, - initial: true, - items: [], - listeners: { - complete: [], - progress: [] - } - }; - charts.set(chart, anims); - } - return anims; - } - listen(chart, event, cb) { - this._getAnims(chart).listeners[event].push(cb); - } - add(chart, items) { - if (!items || !items.length) { - return; - } - this._getAnims(chart).items.push(...items); - } - has(chart) { - return this._getAnims(chart).items.length > 0; - } - start(chart) { - const anims = this._charts.get(chart); - if (!anims) { - return; - } - anims.running = true; - anims.start = Date.now(); - anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); - this._refresh(); - } - running(chart) { - if (!this._running) { - return false; - } - const anims = this._charts.get(chart); - if (!anims || !anims.running || !anims.items.length) { - return false; - } - return true; - } - stop(chart) { - const anims = this._charts.get(chart); - if (!anims || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - for (; i >= 0; --i) { - items[i].cancel(); - } - anims.items = []; - this._notify(chart, anims, Date.now(), 'complete'); - } - remove(chart) { - return this._charts.delete(chart); - } -} -var animator = new Animator(); - -/*! - * @kurkle/color v0.1.9 - * https://github.com/kurkle/color#readme - * (c) 2020 Jukka Kurkela - * Released under the MIT License - */ -const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; -const hex = '0123456789ABCDEF'; -const h1 = (b) => hex[b & 0xF]; -const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; -const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF)); -function isShort(v) { - return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); -} -function hexParse(str) { - var len = str.length; - var ret; - if (str[0] === '#') { - if (len === 4 || len === 5) { - ret = { - r: 255 & map$1[str[1]] * 17, - g: 255 & map$1[str[2]] * 17, - b: 255 & map$1[str[3]] * 17, - a: len === 5 ? map$1[str[4]] * 17 : 255 - }; - } else if (len === 7 || len === 9) { - ret = { - r: map$1[str[1]] << 4 | map$1[str[2]], - g: map$1[str[3]] << 4 | map$1[str[4]], - b: map$1[str[5]] << 4 | map$1[str[6]], - a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255 - }; - } - } - return ret; -} -function hexString(v) { - var f = isShort(v) ? h1 : h2; - return v - ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') - : v; -} -function round(v) { - return v + 0.5 | 0; -} -const lim = (v, l, h) => Math.max(Math.min(v, h), l); -function p2b(v) { - return lim(round(v * 2.55), 0, 255); -} -function n2b(v) { - return lim(round(v * 255), 0, 255); -} -function b2n(v) { - return lim(round(v / 2.55) / 100, 0, 1); -} -function n2p(v) { - return lim(round(v * 100), 0, 100); -} -const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; -function rgbParse(str) { - const m = RGB_RE.exec(str); - let a = 255; - let r, g, b; - if (!m) { - return; - } - if (m[7] !== r) { - const v = +m[7]; - a = 255 & (m[8] ? p2b(v) : v * 255); - } - r = +m[1]; - g = +m[3]; - b = +m[5]; - r = 255 & (m[2] ? p2b(r) : r); - g = 255 & (m[4] ? p2b(g) : g); - b = 255 & (m[6] ? p2b(b) : b); - return { - r: r, - g: g, - b: b, - a: a - }; -} -function rgbString(v) { - return v && ( - v.a < 255 - ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` - : `rgb(${v.r}, ${v.g}, ${v.b})` - ); -} -const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; -function hsl2rgbn(h, s, l) { - const a = s * Math.min(l, 1 - l); - const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return [f(0), f(8), f(4)]; -} -function hsv2rgbn(h, s, v) { - const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); - return [f(5), f(3), f(1)]; -} -function hwb2rgbn(h, w, b) { - const rgb = hsl2rgbn(h, 1, 0.5); - let i; - if (w + b > 1) { - i = 1 / (w + b); - w *= i; - b *= i; - } - for (i = 0; i < 3; i++) { - rgb[i] *= 1 - w - b; - rgb[i] += w; - } - return rgb; -} -function rgb2hsl(v) { - const range = 255; - const r = v.r / range; - const g = v.g / range; - const b = v.b / range; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const l = (max + min) / 2; - let h, s, d; - if (max !== min) { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - h = max === r - ? ((g - b) / d) + (g < b ? 6 : 0) - : max === g - ? (b - r) / d + 2 - : (r - g) / d + 4; - h = h * 60 + 0.5; - } - return [h | 0, s || 0, l]; -} -function calln(f, a, b, c) { - return ( - Array.isArray(a) - ? f(a[0], a[1], a[2]) - : f(a, b, c) - ).map(n2b); -} -function hsl2rgb(h, s, l) { - return calln(hsl2rgbn, h, s, l); -} -function hwb2rgb(h, w, b) { - return calln(hwb2rgbn, h, w, b); -} -function hsv2rgb(h, s, v) { - return calln(hsv2rgbn, h, s, v); -} -function hue(h) { - return (h % 360 + 360) % 360; -} -function hueParse(str) { - const m = HUE_RE.exec(str); - let a = 255; - let v; - if (!m) { - return; - } - if (m[5] !== v) { - a = m[6] ? p2b(+m[5]) : n2b(+m[5]); - } - const h = hue(+m[2]); - const p1 = +m[3] / 100; - const p2 = +m[4] / 100; - if (m[1] === 'hwb') { - v = hwb2rgb(h, p1, p2); - } else if (m[1] === 'hsv') { - v = hsv2rgb(h, p1, p2); - } else { - v = hsl2rgb(h, p1, p2); - } - return { - r: v[0], - g: v[1], - b: v[2], - a: a - }; -} -function rotate(v, deg) { - var h = rgb2hsl(v); - h[0] = hue(h[0] + deg); - h = hsl2rgb(h); - v.r = h[0]; - v.g = h[1]; - v.b = h[2]; -} -function hslString(v) { - if (!v) { - return; - } - const a = rgb2hsl(v); - const h = a[0]; - const s = n2p(a[1]); - const l = n2p(a[2]); - return v.a < 255 - ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` - : `hsl(${h}, ${s}%, ${l}%)`; -} -const map$1$1 = { - x: 'dark', - Z: 'light', - Y: 're', - X: 'blu', - W: 'gr', - V: 'medium', - U: 'slate', - A: 'ee', - T: 'ol', - S: 'or', - B: 'ra', - C: 'lateg', - D: 'ights', - R: 'in', - Q: 'turquois', - E: 'hi', - P: 'ro', - O: 'al', - N: 'le', - M: 'de', - L: 'yello', - F: 'en', - K: 'ch', - G: 'arks', - H: 'ea', - I: 'ightg', - J: 'wh' -}; -const names = { - OiceXe: 'f0f8ff', - antiquewEte: 'faebd7', - aqua: 'ffff', - aquamarRe: '7fffd4', - azuY: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '0', - blanKedOmond: 'ffebcd', - Xe: 'ff', - XeviTet: '8a2be2', - bPwn: 'a52a2a', - burlywood: 'deb887', - caMtXe: '5f9ea0', - KartYuse: '7fff00', - KocTate: 'd2691e', - cSO: 'ff7f50', - cSnflowerXe: '6495ed', - cSnsilk: 'fff8dc', - crimson: 'dc143c', - cyan: 'ffff', - xXe: '8b', - xcyan: '8b8b', - xgTMnPd: 'b8860b', - xWay: 'a9a9a9', - xgYF: '6400', - xgYy: 'a9a9a9', - xkhaki: 'bdb76b', - xmagFta: '8b008b', - xTivegYF: '556b2f', - xSange: 'ff8c00', - xScEd: '9932cc', - xYd: '8b0000', - xsOmon: 'e9967a', - xsHgYF: '8fbc8f', - xUXe: '483d8b', - xUWay: '2f4f4f', - xUgYy: '2f4f4f', - xQe: 'ced1', - xviTet: '9400d3', - dAppRk: 'ff1493', - dApskyXe: 'bfff', - dimWay: '696969', - dimgYy: '696969', - dodgerXe: '1e90ff', - fiYbrick: 'b22222', - flSOwEte: 'fffaf0', - foYstWAn: '228b22', - fuKsia: 'ff00ff', - gaRsbSo: 'dcdcdc', - ghostwEte: 'f8f8ff', - gTd: 'ffd700', - gTMnPd: 'daa520', - Way: '808080', - gYF: '8000', - gYFLw: 'adff2f', - gYy: '808080', - honeyMw: 'f0fff0', - hotpRk: 'ff69b4', - RdianYd: 'cd5c5c', - Rdigo: '4b0082', - ivSy: 'fffff0', - khaki: 'f0e68c', - lavFMr: 'e6e6fa', - lavFMrXsh: 'fff0f5', - lawngYF: '7cfc00', - NmoncEffon: 'fffacd', - ZXe: 'add8e6', - ZcSO: 'f08080', - Zcyan: 'e0ffff', - ZgTMnPdLw: 'fafad2', - ZWay: 'd3d3d3', - ZgYF: '90ee90', - ZgYy: 'd3d3d3', - ZpRk: 'ffb6c1', - ZsOmon: 'ffa07a', - ZsHgYF: '20b2aa', - ZskyXe: '87cefa', - ZUWay: '778899', - ZUgYy: '778899', - ZstAlXe: 'b0c4de', - ZLw: 'ffffe0', - lime: 'ff00', - limegYF: '32cd32', - lRF: 'faf0e6', - magFta: 'ff00ff', - maPon: '800000', - VaquamarRe: '66cdaa', - VXe: 'cd', - VScEd: 'ba55d3', - VpurpN: '9370db', - VsHgYF: '3cb371', - VUXe: '7b68ee', - VsprRggYF: 'fa9a', - VQe: '48d1cc', - VviTetYd: 'c71585', - midnightXe: '191970', - mRtcYam: 'f5fffa', - mistyPse: 'ffe4e1', - moccasR: 'ffe4b5', - navajowEte: 'ffdead', - navy: '80', - Tdlace: 'fdf5e6', - Tive: '808000', - TivedBb: '6b8e23', - Sange: 'ffa500', - SangeYd: 'ff4500', - ScEd: 'da70d6', - pOegTMnPd: 'eee8aa', - pOegYF: '98fb98', - pOeQe: 'afeeee', - pOeviTetYd: 'db7093', - papayawEp: 'ffefd5', - pHKpuff: 'ffdab9', - peru: 'cd853f', - pRk: 'ffc0cb', - plum: 'dda0dd', - powMrXe: 'b0e0e6', - purpN: '800080', - YbeccapurpN: '663399', - Yd: 'ff0000', - Psybrown: 'bc8f8f', - PyOXe: '4169e1', - saddNbPwn: '8b4513', - sOmon: 'fa8072', - sandybPwn: 'f4a460', - sHgYF: '2e8b57', - sHshell: 'fff5ee', - siFna: 'a0522d', - silver: 'c0c0c0', - skyXe: '87ceeb', - UXe: '6a5acd', - UWay: '708090', - UgYy: '708090', - snow: 'fffafa', - sprRggYF: 'ff7f', - stAlXe: '4682b4', - tan: 'd2b48c', - teO: '8080', - tEstN: 'd8bfd8', - tomato: 'ff6347', - Qe: '40e0d0', - viTet: 'ee82ee', - JHt: 'f5deb3', - wEte: 'ffffff', - wEtesmoke: 'f5f5f5', - Lw: 'ffff00', - LwgYF: '9acd32' -}; -function unpack() { - const unpacked = {}; - const keys = Object.keys(names); - const tkeys = Object.keys(map$1$1); - let i, j, k, ok, nk; - for (i = 0; i < keys.length; i++) { - ok = nk = keys[i]; - for (j = 0; j < tkeys.length; j++) { - k = tkeys[j]; - nk = nk.replace(k, map$1$1[k]); - } - k = parseInt(names[ok], 16); - unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; - } - return unpacked; -} -let names$1; -function nameParse(str) { - if (!names$1) { - names$1 = unpack(); - names$1.transparent = [0, 0, 0, 0]; - } - const a = names$1[str.toLowerCase()]; - return a && { - r: a[0], - g: a[1], - b: a[2], - a: a.length === 4 ? a[3] : 255 - }; -} -function modHSL(v, i, ratio) { - if (v) { - let tmp = rgb2hsl(v); - tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); - tmp = hsl2rgb(tmp); - v.r = tmp[0]; - v.g = tmp[1]; - v.b = tmp[2]; - } -} -function clone$1(v, proto) { - return v ? Object.assign(proto || {}, v) : v; -} -function fromObject(input) { - var v = {r: 0, g: 0, b: 0, a: 255}; - if (Array.isArray(input)) { - if (input.length >= 3) { - v = {r: input[0], g: input[1], b: input[2], a: 255}; - if (input.length > 3) { - v.a = n2b(input[3]); - } - } - } else { - v = clone$1(input, {r: 0, g: 0, b: 0, a: 1}); - v.a = n2b(v.a); - } - return v; -} -function functionParse(str) { - if (str.charAt(0) === 'r') { - return rgbParse(str); - } - return hueParse(str); -} -class Color { - constructor(input) { - if (input instanceof Color) { - return input; - } - const type = typeof input; - let v; - if (type === 'object') { - v = fromObject(input); - } else if (type === 'string') { - v = hexParse(input) || nameParse(input) || functionParse(input); - } - this._rgb = v; - this._valid = !!v; - } - get valid() { - return this._valid; - } - get rgb() { - var v = clone$1(this._rgb); - if (v) { - v.a = b2n(v.a); - } - return v; - } - set rgb(obj) { - this._rgb = fromObject(obj); - } - rgbString() { - return this._valid ? rgbString(this._rgb) : this._rgb; - } - hexString() { - return this._valid ? hexString(this._rgb) : this._rgb; - } - hslString() { - return this._valid ? hslString(this._rgb) : this._rgb; - } - mix(color, weight) { - const me = this; - if (color) { - const c1 = me.rgb; - const c2 = color.rgb; - let w2; - const p = weight === w2 ? 0.5 : weight; - const w = 2 * p - 1; - const a = c1.a - c2.a; - const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - w2 = 1 - w1; - c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; - c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; - c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; - c1.a = p * c1.a + (1 - p) * c2.a; - me.rgb = c1; - } - return me; - } - clone() { - return new Color(this.rgb); - } - alpha(a) { - this._rgb.a = n2b(a); - return this; - } - clearer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 - ratio; - return this; - } - greyscale() { - const rgb = this._rgb; - const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); - rgb.r = rgb.g = rgb.b = val; - return this; - } - opaquer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 + ratio; - return this; - } - negate() { - const v = this._rgb; - v.r = 255 - v.r; - v.g = 255 - v.g; - v.b = 255 - v.b; - return this; - } - lighten(ratio) { - modHSL(this._rgb, 2, ratio); - return this; - } - darken(ratio) { - modHSL(this._rgb, 2, -ratio); - return this; - } - saturate(ratio) { - modHSL(this._rgb, 1, ratio); - return this; - } - desaturate(ratio) { - modHSL(this._rgb, 1, -ratio); - return this; - } - rotate(deg) { - rotate(this._rgb, deg); - return this; - } -} -function index_esm(input) { - return new Color(input); -} - -const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern; -function color(value) { - return isPatternOrGradient(value) ? value : index_esm(value); -} -function getHoverColor(value) { - return isPatternOrGradient(value) - ? value - : index_esm(value).saturate(0.5).darken(0.1).hexString(); -} - -function noop() {} -const uid = (function() { - let id = 0; - return function() { - return id++; - }; -}()); -function isNullOrUndef(value) { - return value === null || typeof value === 'undefined'; -} -function isArray(value) { - if (Array.isArray && Array.isArray(value)) { - return true; - } - const type = Object.prototype.toString.call(value); - if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { - return true; - } - return false; -} -function isObject(value) { - return value !== null && Object.prototype.toString.call(value) === '[object Object]'; -} -const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value); -function finiteOrDefault(value, defaultValue) { - return isNumberFinite(value) ? value : defaultValue; -} -function valueOrDefault(value, defaultValue) { - return typeof value === 'undefined' ? defaultValue : value; -} -const toPercentage = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 - : value / dimension; -const toDimension = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 * dimension - : +value; -function callback(fn, args, thisArg) { - if (fn && typeof fn.call === 'function') { - return fn.apply(thisArg, args); - } -} -function each(loopable, fn, thisArg, reverse) { - let i, len, keys; - if (isArray(loopable)) { - len = loopable.length; - if (reverse) { - for (i = len - 1; i >= 0; i--) { - fn.call(thisArg, loopable[i], i); - } - } else { - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[i], i); - } - } - } else if (isObject(loopable)) { - keys = Object.keys(loopable); - len = keys.length; - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[keys[i]], keys[i]); - } - } -} -function _elementsEqual(a0, a1) { - let i, ilen, v0, v1; - if (!a0 || !a1 || a0.length !== a1.length) { - return false; - } - for (i = 0, ilen = a0.length; i < ilen; ++i) { - v0 = a0[i]; - v1 = a1[i]; - if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { - return false; - } - } - return true; -} -function clone(source) { - if (isArray(source)) { - return source.map(clone); - } - if (isObject(source)) { - const target = Object.create(null); - const keys = Object.keys(source); - const klen = keys.length; - let k = 0; - for (; k < klen; ++k) { - target[keys[k]] = clone(source[keys[k]]); - } - return target; - } - return source; -} -function isValidKey(key) { - return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; -} -function _merger(key, target, source, options) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - merge(tval, sval, options); - } else { - target[key] = clone(sval); - } -} -function merge(target, source, options) { - const sources = isArray(source) ? source : [source]; - const ilen = sources.length; - if (!isObject(target)) { - return target; - } - options = options || {}; - const merger = options.merger || _merger; - for (let i = 0; i < ilen; ++i) { - source = sources[i]; - if (!isObject(source)) { - continue; - } - const keys = Object.keys(source); - for (let k = 0, klen = keys.length; k < klen; ++k) { - merger(keys[k], target, source, options); - } - } - return target; -} -function mergeIf(target, source) { - return merge(target, source, {merger: _mergerIf}); -} -function _mergerIf(key, target, source) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - mergeIf(tval, sval); - } else if (!Object.prototype.hasOwnProperty.call(target, key)) { - target[key] = clone(sval); - } -} -function _deprecated(scope, value, previous, current) { - if (value !== undefined) { - console.warn(scope + ': "' + previous + - '" is deprecated. Please use "' + current + '" instead'); - } -} -const emptyString = ''; -const dot = '.'; -function indexOfDotOrLength(key, start) { - const idx = key.indexOf(dot, start); - return idx === -1 ? key.length : idx; -} -function resolveObjectKey(obj, key) { - if (key === emptyString) { - return obj; - } - let pos = 0; - let idx = indexOfDotOrLength(key, pos); - while (obj && idx > pos) { - obj = obj[key.substr(pos, idx - pos)]; - pos = idx + 1; - idx = indexOfDotOrLength(key, pos); - } - return obj; -} -function _capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); -} -const defined = (value) => typeof value !== 'undefined'; -const isFunction = (value) => typeof value === 'function'; -const setsEqual = (a, b) => { - if (a.size !== b.size) { - return false; - } - for (const item of a) { - if (!b.has(item)) { - return false; - } - } - return true; -}; -function _isClickEvent(e) { - return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; -} - -const overrides = Object.create(null); -const descriptors = Object.create(null); -function getScope$1(node, key) { - if (!key) { - return node; - } - const keys = key.split('.'); - for (let i = 0, n = keys.length; i < n; ++i) { - const k = keys[i]; - node = node[k] || (node[k] = Object.create(null)); - } - return node; -} -function set(root, scope, values) { - if (typeof scope === 'string') { - return merge(getScope$1(root, scope), values); - } - return merge(getScope$1(root, ''), scope); -} -class Defaults { - constructor(_descriptors) { - this.animation = undefined; - this.backgroundColor = 'rgba(0,0,0,0.1)'; - this.borderColor = 'rgba(0,0,0,0.1)'; - this.color = '#666'; - this.datasets = {}; - this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); - this.elements = {}; - this.events = [ - 'mousemove', - 'mouseout', - 'click', - 'touchstart', - 'touchmove' - ]; - this.font = { - family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - size: 12, - style: 'normal', - lineHeight: 1.2, - weight: null - }; - this.hover = {}; - this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); - this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); - this.hoverColor = (ctx, options) => getHoverColor(options.color); - this.indexAxis = 'x'; - this.interaction = { - mode: 'nearest', - intersect: true - }; - this.maintainAspectRatio = true; - this.onHover = null; - this.onClick = null; - this.parsing = true; - this.plugins = {}; - this.responsive = true; - this.scale = undefined; - this.scales = {}; - this.showLine = true; - this.drawActiveElementsOnTop = true; - this.describe(_descriptors); - } - set(scope, values) { - return set(this, scope, values); - } - get(scope) { - return getScope$1(this, scope); - } - describe(scope, values) { - return set(descriptors, scope, values); - } - override(scope, values) { - return set(overrides, scope, values); - } - route(scope, name, targetScope, targetName) { - const scopeObject = getScope$1(this, scope); - const targetScopeObject = getScope$1(this, targetScope); - const privateName = '_' + name; - Object.defineProperties(scopeObject, { - [privateName]: { - value: scopeObject[name], - writable: true - }, - [name]: { - enumerable: true, - get() { - const local = this[privateName]; - const target = targetScopeObject[targetName]; - if (isObject(local)) { - return Object.assign({}, target, local); - } - return valueOrDefault(local, target); - }, - set(value) { - this[privateName] = value; - } - } - }); - } -} -var defaults = new Defaults({ - _scriptable: (name) => !name.startsWith('on'), - _indexable: (name) => name !== 'events', - hover: { - _fallback: 'interaction' - }, - interaction: { - _scriptable: false, - _indexable: false, - } -}); - -const PI = Math.PI; -const TAU = 2 * PI; -const PITAU = TAU + PI; -const INFINITY = Number.POSITIVE_INFINITY; -const RAD_PER_DEG = PI / 180; -const HALF_PI = PI / 2; -const QUARTER_PI = PI / 4; -const TWO_THIRDS_PI = PI * 2 / 3; -const log10 = Math.log10; -const sign = Math.sign; -function niceNum(range) { - const roundedRange = Math.round(range); - range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; - const niceRange = Math.pow(10, Math.floor(log10(range))); - const fraction = range / niceRange; - const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; - return niceFraction * niceRange; -} -function _factorize(value) { - const result = []; - const sqrt = Math.sqrt(value); - let i; - for (i = 1; i < sqrt; i++) { - if (value % i === 0) { - result.push(i); - result.push(value / i); - } - } - if (sqrt === (sqrt | 0)) { - result.push(sqrt); - } - result.sort((a, b) => a - b).pop(); - return result; -} -function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); -} -function almostEquals(x, y, epsilon) { - return Math.abs(x - y) < epsilon; -} -function almostWhole(x, epsilon) { - const rounded = Math.round(x); - return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x); -} -function _setMinAndMaxByKey(array, target, property) { - let i, ilen, value; - for (i = 0, ilen = array.length; i < ilen; i++) { - value = array[i][property]; - if (!isNaN(value)) { - target.min = Math.min(target.min, value); - target.max = Math.max(target.max, value); - } - } -} -function toRadians(degrees) { - return degrees * (PI / 180); -} -function toDegrees(radians) { - return radians * (180 / PI); -} -function _decimalPlaces(x) { - if (!isNumberFinite(x)) { - return; - } - let e = 1; - let p = 0; - while (Math.round(x * e) / e !== x) { - e *= 10; - p++; - } - return p; -} -function getAngleFromPoint(centrePoint, anglePoint) { - const distanceFromXCenter = anglePoint.x - centrePoint.x; - const distanceFromYCenter = anglePoint.y - centrePoint.y; - const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); - let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); - if (angle < (-0.5 * PI)) { - angle += TAU; - } - return { - angle, - distance: radialDistanceFromCenter - }; -} -function distanceBetweenPoints(pt1, pt2) { - return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); -} -function _angleDiff(a, b) { - return (a - b + PITAU) % TAU - PI; -} -function _normalizeAngle(a) { - return (a % TAU + TAU) % TAU; -} -function _angleBetween(angle, start, end, sameAngleIsFullCircle) { - const a = _normalizeAngle(angle); - const s = _normalizeAngle(start); - const e = _normalizeAngle(end); - const angleToStart = _normalizeAngle(s - a); - const angleToEnd = _normalizeAngle(e - a); - const startToAngle = _normalizeAngle(a - s); - const endToAngle = _normalizeAngle(a - e); - return a === s || a === e || (sameAngleIsFullCircle && s === e) - || (angleToStart > angleToEnd && startToAngle < endToAngle); -} -function _limitValue(value, min, max) { - return Math.max(min, Math.min(max, value)); -} -function _int16Range(value) { - return _limitValue(value, -32768, 32767); -} -function _isBetween(value, start, end, epsilon = 1e-6) { - return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; -} - -function toFontString(font) { - if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { - return null; - } - return (font.style ? font.style + ' ' : '') - + (font.weight ? font.weight + ' ' : '') - + font.size + 'px ' - + font.family; -} -function _measureText(ctx, data, gc, longest, string) { - let textWidth = data[string]; - if (!textWidth) { - textWidth = data[string] = ctx.measureText(string).width; - gc.push(string); - } - if (textWidth > longest) { - longest = textWidth; - } - return longest; -} -function _longestText(ctx, font, arrayOfThings, cache) { - cache = cache || {}; - let data = cache.data = cache.data || {}; - let gc = cache.garbageCollect = cache.garbageCollect || []; - if (cache.font !== font) { - data = cache.data = {}; - gc = cache.garbageCollect = []; - cache.font = font; - } - ctx.save(); - ctx.font = font; - let longest = 0; - const ilen = arrayOfThings.length; - let i, j, jlen, thing, nestedThing; - for (i = 0; i < ilen; i++) { - thing = arrayOfThings[i]; - if (thing !== undefined && thing !== null && isArray(thing) !== true) { - longest = _measureText(ctx, data, gc, longest, thing); - } else if (isArray(thing)) { - for (j = 0, jlen = thing.length; j < jlen; j++) { - nestedThing = thing[j]; - if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { - longest = _measureText(ctx, data, gc, longest, nestedThing); - } - } - } - } - ctx.restore(); - const gcLen = gc.length / 2; - if (gcLen > arrayOfThings.length) { - for (i = 0; i < gcLen; i++) { - delete data[gc[i]]; - } - gc.splice(0, gcLen); - } - return longest; -} -function _alignPixel(chart, pixel, width) { - const devicePixelRatio = chart.currentDevicePixelRatio; - const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; - return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; -} -function clearCanvas(canvas, ctx) { - ctx = ctx || canvas.getContext('2d'); - ctx.save(); - ctx.resetTransform(); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.restore(); -} -function drawPoint(ctx, options, x, y) { - let type, xOffset, yOffset, size, cornerRadius; - const style = options.pointStyle; - const rotation = options.rotation; - const radius = options.radius; - let rad = (rotation || 0) * RAD_PER_DEG; - if (style && typeof style === 'object') { - type = style.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.save(); - ctx.translate(x, y); - ctx.rotate(rad); - ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); - ctx.restore(); - return; - } - } - if (isNaN(radius) || radius <= 0) { - return; - } - ctx.beginPath(); - switch (style) { - default: - ctx.arc(x, y, radius, 0, TAU); - ctx.closePath(); - break; - case 'triangle': - ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - ctx.closePath(); - break; - case 'rectRounded': - cornerRadius = radius * 0.516; - size = radius - cornerRadius; - xOffset = Math.cos(rad + QUARTER_PI) * size; - yOffset = Math.sin(rad + QUARTER_PI) * size; - ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); - ctx.closePath(); - break; - case 'rect': - if (!rotation) { - size = Math.SQRT1_2 * radius; - ctx.rect(x - size, y - size, 2 * size, 2 * size); - break; - } - rad += QUARTER_PI; - case 'rectRot': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + yOffset, y - xOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.lineTo(x - yOffset, y + xOffset); - ctx.closePath(); - break; - case 'crossRot': - rad += QUARTER_PI; - case 'cross': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'star': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - rad += QUARTER_PI; - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'line': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - break; - case 'dash': - ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); - break; - } - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } -} -function _isPointInArea(point, area, margin) { - margin = margin || 0.5; - return !area || (point && point.x > area.left - margin && point.x < area.right + margin && - point.y > area.top - margin && point.y < area.bottom + margin); -} -function clipArea(ctx, area) { - ctx.save(); - ctx.beginPath(); - ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); - ctx.clip(); -} -function unclipArea(ctx) { - ctx.restore(); -} -function _steppedLineTo(ctx, previous, target, flip, mode) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - if (mode === 'middle') { - const midpoint = (previous.x + target.x) / 2.0; - ctx.lineTo(midpoint, previous.y); - ctx.lineTo(midpoint, target.y); - } else if (mode === 'after' !== !!flip) { - ctx.lineTo(previous.x, target.y); - } else { - ctx.lineTo(target.x, previous.y); - } - ctx.lineTo(target.x, target.y); -} -function _bezierCurveTo(ctx, previous, target, flip) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - ctx.bezierCurveTo( - flip ? previous.cp1x : previous.cp2x, - flip ? previous.cp1y : previous.cp2y, - flip ? target.cp2x : target.cp1x, - flip ? target.cp2y : target.cp1y, - target.x, - target.y); -} -function renderText(ctx, text, x, y, font, opts = {}) { - const lines = isArray(text) ? text : [text]; - const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; - let i, line; - ctx.save(); - ctx.font = font.string; - setRenderOpts(ctx, opts); - for (i = 0; i < lines.length; ++i) { - line = lines[i]; - if (stroke) { - if (opts.strokeColor) { - ctx.strokeStyle = opts.strokeColor; - } - if (!isNullOrUndef(opts.strokeWidth)) { - ctx.lineWidth = opts.strokeWidth; - } - ctx.strokeText(line, x, y, opts.maxWidth); - } - ctx.fillText(line, x, y, opts.maxWidth); - decorateText(ctx, x, y, line, opts); - y += font.lineHeight; - } - ctx.restore(); -} -function setRenderOpts(ctx, opts) { - if (opts.translation) { - ctx.translate(opts.translation[0], opts.translation[1]); - } - if (!isNullOrUndef(opts.rotation)) { - ctx.rotate(opts.rotation); - } - if (opts.color) { - ctx.fillStyle = opts.color; - } - if (opts.textAlign) { - ctx.textAlign = opts.textAlign; - } - if (opts.textBaseline) { - ctx.textBaseline = opts.textBaseline; - } -} -function decorateText(ctx, x, y, line, opts) { - if (opts.strikethrough || opts.underline) { - const metrics = ctx.measureText(line); - const left = x - metrics.actualBoundingBoxLeft; - const right = x + metrics.actualBoundingBoxRight; - const top = y - metrics.actualBoundingBoxAscent; - const bottom = y + metrics.actualBoundingBoxDescent; - const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; - ctx.strokeStyle = ctx.fillStyle; - ctx.beginPath(); - ctx.lineWidth = opts.decorationWidth || 2; - ctx.moveTo(left, yDecoration); - ctx.lineTo(right, yDecoration); - ctx.stroke(); - } -} -function addRoundedRectPath(ctx, rect) { - const {x, y, w, h, radius} = rect; - ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true); - ctx.lineTo(x, y + h - radius.bottomLeft); - ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); - ctx.lineTo(x + w - radius.bottomRight, y + h); - ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); - ctx.lineTo(x + w, y + radius.topRight); - ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); - ctx.lineTo(x + radius.topLeft, y); -} - -function _lookup(table, value, cmp) { - cmp = cmp || ((index) => table[index] < value); - let hi = table.length - 1; - let lo = 0; - let mid; - while (hi - lo > 1) { - mid = (lo + hi) >> 1; - if (cmp(mid)) { - lo = mid; - } else { - hi = mid; - } - } - return {lo, hi}; -} -const _lookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] < value); -const _rlookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] >= value); -function _filterBetween(values, min, max) { - let start = 0; - let end = values.length; - while (start < end && values[start] < min) { - start++; - } - while (end > start && values[end - 1] > max) { - end--; - } - return start > 0 || end < values.length - ? values.slice(start, end) - : values; -} -const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; -function listenArrayEvents(array, listener) { - if (array._chartjs) { - array._chartjs.listeners.push(listener); - return; - } - Object.defineProperty(array, '_chartjs', { - configurable: true, - enumerable: false, - value: { - listeners: [listener] - } - }); - arrayEvents.forEach((key) => { - const method = '_onData' + _capitalize(key); - const base = array[key]; - Object.defineProperty(array, key, { - configurable: true, - enumerable: false, - value(...args) { - const res = base.apply(this, args); - array._chartjs.listeners.forEach((object) => { - if (typeof object[method] === 'function') { - object[method](...args); - } + this._running = true; + this._request = requestAnimFrame.call(window, ()=>{ + this._update(); + this._request = null; + if (this._running) { + this._refresh(); + } }); - return res; - } - }); - }); -} -function unlistenArrayEvents(array, listener) { - const stub = array._chartjs; - if (!stub) { - return; - } - const listeners = stub.listeners; - const index = listeners.indexOf(listener); - if (index !== -1) { - listeners.splice(index, 1); - } - if (listeners.length > 0) { - return; - } - arrayEvents.forEach((key) => { - delete array[key]; - }); - delete array._chartjs; -} -function _arrayUnique(items) { - const set = new Set(); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - set.add(items[i]); - } - if (set.size === ilen) { - return items; - } - return Array.from(set); -} - -function _isDomSupported() { - return typeof window !== 'undefined' && typeof document !== 'undefined'; -} -function _getParentNode(domNode) { - let parent = domNode.parentNode; - if (parent && parent.toString() === '[object ShadowRoot]') { - parent = parent.host; - } - return parent; -} -function parseMaxStyle(styleValue, node, parentProperty) { - let valueInPixels; - if (typeof styleValue === 'string') { - valueInPixels = parseInt(styleValue, 10); - if (styleValue.indexOf('%') !== -1) { - valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; } - } else { - valueInPixels = styleValue; - } - return valueInPixels; -} -const getComputedStyle = (element) => window.getComputedStyle(element, null); -function getStyle(el, property) { - return getComputedStyle(el).getPropertyValue(property); -} -const positions = ['top', 'right', 'bottom', 'left']; -function getPositionedStyle(styles, style, suffix) { - const result = {}; - suffix = suffix ? '-' + suffix : ''; - for (let i = 0; i < 4; i++) { - const pos = positions[i]; - result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; - } - result.width = result.left + result.right; - result.height = result.top + result.bottom; - return result; -} -const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot); -function getCanvasPosition(evt, canvas) { - const e = evt.native || evt; - const touches = e.touches; - const source = touches && touches.length ? touches[0] : e; - const {offsetX, offsetY} = source; - let box = false; - let x, y; - if (useOffsetPos(offsetX, offsetY, e.target)) { - x = offsetX; - y = offsetY; - } else { - const rect = canvas.getBoundingClientRect(); - x = source.clientX - rect.left; - y = source.clientY - rect.top; - box = true; - } - return {x, y, box}; -} -function getRelativePosition$1(evt, chart) { - const {canvas, currentDevicePixelRatio} = chart; - const style = getComputedStyle(canvas); - const borderBox = style.boxSizing === 'border-box'; - const paddings = getPositionedStyle(style, 'padding'); - const borders = getPositionedStyle(style, 'border', 'width'); - const {x, y, box} = getCanvasPosition(evt, canvas); - const xOffset = paddings.left + (box && borders.left); - const yOffset = paddings.top + (box && borders.top); - let {width, height} = chart; - if (borderBox) { - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - return { - x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), - y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) - }; -} -function getContainerSize(canvas, width, height) { - let maxWidth, maxHeight; - if (width === undefined || height === undefined) { - const container = _getParentNode(canvas); - if (!container) { - width = canvas.clientWidth; - height = canvas.clientHeight; - } else { - const rect = container.getBoundingClientRect(); - const containerStyle = getComputedStyle(container); - const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); - const containerPadding = getPositionedStyle(containerStyle, 'padding'); - width = rect.width - containerPadding.width - containerBorder.width; - height = rect.height - containerPadding.height - containerBorder.height; - maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); - maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); - } - } - return { - width, - height, - maxWidth: maxWidth || INFINITY, - maxHeight: maxHeight || INFINITY - }; -} -const round1 = v => Math.round(v * 10) / 10; -function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { - const style = getComputedStyle(canvas); - const margins = getPositionedStyle(style, 'margin'); - const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; - const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; - const containerSize = getContainerSize(canvas, bbWidth, bbHeight); - let {width, height} = containerSize; - if (style.boxSizing === 'content-box') { - const borders = getPositionedStyle(style, 'border', 'width'); - const paddings = getPositionedStyle(style, 'padding'); - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - width = Math.max(0, width - margins.width); - height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); - width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); - height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); - if (width && !height) { - height = round1(width / 2); - } - return { - width, - height - }; -} -function retinaScale(chart, forceRatio, forceStyle) { - const pixelRatio = forceRatio || 1; - const deviceHeight = Math.floor(chart.height * pixelRatio); - const deviceWidth = Math.floor(chart.width * pixelRatio); - chart.height = deviceHeight / pixelRatio; - chart.width = deviceWidth / pixelRatio; - const canvas = chart.canvas; - if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) { - canvas.style.height = `${chart.height}px`; - canvas.style.width = `${chart.width}px`; - } - if (chart.currentDevicePixelRatio !== pixelRatio - || canvas.height !== deviceHeight - || canvas.width !== deviceWidth) { - chart.currentDevicePixelRatio = pixelRatio; - canvas.height = deviceHeight; - canvas.width = deviceWidth; - chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - return true; - } - return false; -} -const supportsEventListenerOptions = (function() { - let passiveSupported = false; - try { - const options = { - get passive() { - passiveSupported = true; - return false; - } - }; - window.addEventListener('test', null, options); - window.removeEventListener('test', null, options); - } catch (e) { - } - return passiveSupported; -}()); -function readUsedSize(element, property) { - const value = getStyle(element, property); - const matches = value && value.match(/^(\d+)(\.\d+)?px$/); - return matches ? +matches[1] : undefined; -} - -function getRelativePosition(e, chart) { - if ('native' in e) { - return { - x: e.x, - y: e.y - }; - } - return getRelativePosition$1(e, chart); -} -function evaluateAllVisibleItems(chart, handler) { - const metasets = chart.getSortedVisibleDatasetMetas(); - let index, data, element; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - ({index, data} = metasets[i]); - for (let j = 0, jlen = data.length; j < jlen; ++j) { - element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function binarySearch(metaset, axis, value, intersect) { - const {controller, data, _sorted} = metaset; - const iScale = controller._cachedMeta.iScale; - if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { - const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; - if (!intersect) { - return lookupMethod(data, axis, value); - } else if (controller._sharedOptions) { - const el = data[0]; - const range = typeof el.getRange === 'function' && el.getRange(axis); - if (range) { - const start = lookupMethod(data, axis, value - range); - const end = lookupMethod(data, axis, value + range); - return {lo: start.lo, hi: end.hi}; - } - } - } - return {lo: 0, hi: data.length - 1}; -} -function optimizedEvaluateItems(chart, axis, position, handler, intersect) { - const metasets = chart.getSortedVisibleDatasetMetas(); - const value = position[axis]; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - const {index, data} = metasets[i]; - const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); - for (let j = lo; j <= hi; ++j) { - const element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function getDistanceMetricForAxis(axis) { - const useX = axis.indexOf('x') !== -1; - const useY = axis.indexOf('y') !== -1; - return function(pt1, pt2) { - const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; - const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; - return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); - }; -} -function getIntersectItems(chart, position, axis, useFinalPosition) { - const items = []; - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return items; - } - const evaluationFunc = function(element, datasetIndex, index) { - if (element.inRange(position.x, position.y, useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - }; - optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); - return items; -} -function getNearestRadialItems(chart, position, axis, useFinalPosition) { - let items = []; - function evaluationFunc(element, datasetIndex, index) { - const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition); - const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y}); - if (_angleBetween(angle, startAngle, endAngle)) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) { - let items = []; - const distanceMetric = getDistanceMetricForAxis(axis); - let minDistance = Number.POSITIVE_INFINITY; - function evaluationFunc(element, datasetIndex, index) { - const inRange = element.inRange(position.x, position.y, useFinalPosition); - if (intersect && !inRange) { - return; - } - const center = element.getCenterPoint(useFinalPosition); - const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding); - if (!pointInArea && !inRange) { - return; - } - const distance = distanceMetric(position, center); - if (distance < minDistance) { - items = [{element, datasetIndex, index}]; - minDistance = distance; - } else if (distance === minDistance) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestItems(chart, position, axis, intersect, useFinalPosition) { - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return []; - } - return axis === 'r' && !intersect - ? getNearestRadialItems(chart, position, axis, useFinalPosition) - : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition); -} -function getAxisItems(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const items = []; - const axis = options.axis; - const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; - let intersectsItem = false; - evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { - if (element[rangeMethod](position[axis], useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - if (element.inRange(position.x, position.y, useFinalPosition)) { - intersectsItem = true; - } - }); - if (options.intersect && !intersectsItem) { - return []; - } - return items; -} -var Interaction = { - modes: { - index(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'x'; - const items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) - : getNearestItems(chart, position, axis, false, useFinalPosition); - const elements = []; - if (!items.length) { - return []; - } - chart.getSortedVisibleDatasetMetas().forEach((meta) => { - const index = items[0].index; - const element = meta.data[index]; - if (element && !element.skip) { - elements.push({element, datasetIndex: meta.index, index}); + _update(date = Date.now()) { + let remaining = 0; + this._charts.forEach((anims, chart)=>{ + if (!anims.running || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + let draw = false; + let item; + for(; i >= 0; --i){ + item = items[i]; + if (item._active) { + if (item._total > anims.duration) { + anims.duration = item._total; + } + item.tick(date); + draw = true; + } else { + items[i] = items[items.length - 1]; + items.pop(); + } + } + if (draw) { + chart.draw(); + this._notify(chart, anims, date, 'progress'); + } + if (!items.length) { + anims.running = false; + this._notify(chart, anims, date, 'complete'); + anims.initial = false; + } + remaining += items.length; + }); + this._lastDate = date; + if (remaining === 0) { + this._running = false; } - }); - return elements; - }, - dataset(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - let items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) : - getNearestItems(chart, position, axis, false, useFinalPosition); - if (items.length > 0) { - const datasetIndex = items[0].datasetIndex; - const data = chart.getDatasetMeta(datasetIndex).data; - items = []; - for (let i = 0; i < data.length; ++i) { - items.push({element: data[i], datasetIndex, index: i}); + } + _getAnims(chart) { + const charts = this._charts; + let anims = charts.get(chart); + if (!anims) { + anims = { + running: false, + initial: true, + items: [], + listeners: { + complete: [], + progress: [] + } + }; + charts.set(chart, anims); } - } - return items; - }, - point(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getIntersectItems(chart, position, axis, useFinalPosition); - }, - nearest(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); - }, - x(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition); - }, - y(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition); + return anims; } - } -}; - -const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); -const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/); -function toLineHeight(value, size) { - const matches = ('' + value).match(LINE_HEIGHT); - if (!matches || matches[1] === 'normal') { - return size * 1.2; - } - value = +matches[2]; - switch (matches[3]) { - case 'px': - return value; - case '%': - value /= 100; - break; - } - return size * value; -} -const numberOrZero = v => +v || 0; -function _readValueToProps(value, props) { - const ret = {}; - const objProps = isObject(props); - const keys = objProps ? Object.keys(props) : props; - const read = isObject(value) - ? objProps - ? prop => valueOrDefault(value[prop], value[props[prop]]) - : prop => value[prop] - : () => value; - for (const prop of keys) { - ret[prop] = numberOrZero(read(prop)); - } - return ret; -} -function toTRBL(value) { - return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'}); -} -function toTRBLCorners(value) { - return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']); -} -function toPadding(value) { - const obj = toTRBL(value); - obj.width = obj.left + obj.right; - obj.height = obj.top + obj.bottom; - return obj; -} -function toFont(options, fallback) { - options = options || {}; - fallback = fallback || defaults.font; - let size = valueOrDefault(options.size, fallback.size); - if (typeof size === 'string') { - size = parseInt(size, 10); - } - let style = valueOrDefault(options.style, fallback.style); - if (style && !('' + style).match(FONT_STYLE)) { - console.warn('Invalid font style specified: "' + style + '"'); - style = ''; - } - const font = { - family: valueOrDefault(options.family, fallback.family), - lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), - size, - style, - weight: valueOrDefault(options.weight, fallback.weight), - string: '' - }; - font.string = toFontString(font); - return font; -} -function resolve(inputs, context, index, info) { - let cacheable = true; - let i, ilen, value; - for (i = 0, ilen = inputs.length; i < ilen; ++i) { - value = inputs[i]; - if (value === undefined) { - continue; + listen(chart, event, cb) { + this._getAnims(chart).listeners[event].push(cb); } - if (context !== undefined && typeof value === 'function') { - value = value(context); - cacheable = false; - } - if (index !== undefined && isArray(value)) { - value = value[index % value.length]; - cacheable = false; - } - if (value !== undefined) { - if (info && !cacheable) { - info.cacheable = false; - } - return value; - } - } -} -function _addGrace(minmax, grace, beginAtZero) { - const {min, max} = minmax; - const change = toDimension(grace, (max - min) / 2); - const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; - return { - min: keepZero(min, -Math.abs(change)), - max: keepZero(max, change) - }; -} -function createContext(parentContext, context) { - return Object.assign(Object.create(parentContext), context); -} - -const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; -function filterByPosition(array, position) { - return array.filter(v => v.pos === position); -} -function filterDynamicPositionByAxis(array, axis) { - return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); -} -function sortByWeight(array, reverse) { - return array.sort((a, b) => { - const v0 = reverse ? b : a; - const v1 = reverse ? a : b; - return v0.weight === v1.weight ? - v0.index - v1.index : - v0.weight - v1.weight; - }); -} -function wrapBoxes(boxes) { - const layoutBoxes = []; - let i, ilen, box, pos, stack, stackWeight; - for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { - box = boxes[i]; - ({position: pos, options: {stack, stackWeight = 1}} = box); - layoutBoxes.push({ - index: i, - box, - pos, - horizontal: box.isHorizontal(), - weight: box.weight, - stack: stack && (pos + stack), - stackWeight - }); - } - return layoutBoxes; -} -function buildStacks(layouts) { - const stacks = {}; - for (const wrap of layouts) { - const {stack, pos, stackWeight} = wrap; - if (!stack || !STATIC_POSITIONS.includes(pos)) { - continue; - } - const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0}); - _stack.count++; - _stack.weight += stackWeight; - } - return stacks; -} -function setLayoutDims(layouts, params) { - const stacks = buildStacks(layouts); - const {vBoxMaxWidth, hBoxMaxHeight} = params; - let i, ilen, layout; - for (i = 0, ilen = layouts.length; i < ilen; ++i) { - layout = layouts[i]; - const {fullSize} = layout.box; - const stack = stacks[layout.stack]; - const factor = stack && layout.stackWeight / stack.weight; - if (layout.horizontal) { - layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; - layout.height = hBoxMaxHeight; - } else { - layout.width = vBoxMaxWidth; - layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; - } - } - return stacks; -} -function buildLayoutBoxes(boxes) { - const layoutBoxes = wrapBoxes(boxes); - const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true); - const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); - const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); - const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); - const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); - const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); - const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); - return { - fullSize, - leftAndTop: left.concat(top), - rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), - chartArea: filterByPosition(layoutBoxes, 'chartArea'), - vertical: left.concat(right).concat(centerVertical), - horizontal: top.concat(bottom).concat(centerHorizontal) - }; -} -function getCombinedMax(maxPadding, chartArea, a, b) { - return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); -} -function updateMaxPadding(maxPadding, boxPadding) { - maxPadding.top = Math.max(maxPadding.top, boxPadding.top); - maxPadding.left = Math.max(maxPadding.left, boxPadding.left); - maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); - maxPadding.right = Math.max(maxPadding.right, boxPadding.right); -} -function updateDims(chartArea, params, layout, stacks) { - const {pos, box} = layout; - const maxPadding = chartArea.maxPadding; - if (!isObject(pos)) { - if (layout.size) { - chartArea[pos] -= layout.size; - } - const stack = stacks[layout.stack] || {size: 0, count: 1}; - stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); - layout.size = stack.size / stack.count; - chartArea[pos] += layout.size; - } - if (box.getPadding) { - updateMaxPadding(maxPadding, box.getPadding()); - } - const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); - const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); - const widthChanged = newWidth !== chartArea.w; - const heightChanged = newHeight !== chartArea.h; - chartArea.w = newWidth; - chartArea.h = newHeight; - return layout.horizontal - ? {same: widthChanged, other: heightChanged} - : {same: heightChanged, other: widthChanged}; -} -function handleMaxPadding(chartArea) { - const maxPadding = chartArea.maxPadding; - function updatePos(pos) { - const change = Math.max(maxPadding[pos] - chartArea[pos], 0); - chartArea[pos] += change; - return change; - } - chartArea.y += updatePos('top'); - chartArea.x += updatePos('left'); - updatePos('right'); - updatePos('bottom'); -} -function getMargins(horizontal, chartArea) { - const maxPadding = chartArea.maxPadding; - function marginForPositions(positions) { - const margin = {left: 0, top: 0, right: 0, bottom: 0}; - positions.forEach((pos) => { - margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); - }); - return margin; - } - return horizontal - ? marginForPositions(['left', 'right']) - : marginForPositions(['top', 'bottom']); -} -function fitBoxes(boxes, chartArea, params, stacks) { - const refitBoxes = []; - let i, ilen, layout, box, refit, changed; - for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) { - layout = boxes[i]; - box = layout.box; - box.update( - layout.width || chartArea.w, - layout.height || chartArea.h, - getMargins(layout.horizontal, chartArea) - ); - const {same, other} = updateDims(chartArea, params, layout, stacks); - refit |= same && refitBoxes.length; - changed = changed || other; - if (!box.fullSize) { - refitBoxes.push(layout); - } - } - return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; -} -function setBoxDims(box, left, top, width, height) { - box.top = top; - box.left = left; - box.right = left + width; - box.bottom = top + height; - box.width = width; - box.height = height; -} -function placeBoxes(boxes, chartArea, params, stacks) { - const userPadding = params.padding; - let {x, y} = chartArea; - for (const layout of boxes) { - const box = layout.box; - const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1}; - const weight = (layout.stackWeight / stack.weight) || 1; - if (layout.horizontal) { - const width = chartArea.w * weight; - const height = stack.size || box.height; - if (defined(stack.start)) { - y = stack.start; - } - if (box.fullSize) { - setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); - } else { - setBoxDims(box, chartArea.left + stack.placed, y, width, height); - } - stack.start = y; - stack.placed += width; - y = box.bottom; - } else { - const height = chartArea.h * weight; - const width = stack.size || box.width; - if (defined(stack.start)) { - x = stack.start; - } - if (box.fullSize) { - setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); - } else { - setBoxDims(box, x, chartArea.top + stack.placed, width, height); - } - stack.start = x; - stack.placed += height; - x = box.right; - } - } - chartArea.x = x; - chartArea.y = y; -} -defaults.set('layout', { - autoPadding: true, - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } -}); -var layouts = { - addBox(chart, item) { - if (!chart.boxes) { - chart.boxes = []; - } - item.fullSize = item.fullSize || false; - item.position = item.position || 'top'; - item.weight = item.weight || 0; - item._layers = item._layers || function() { - return [{ - z: 0, - draw(chartArea) { - item.draw(chartArea); + add(chart, items) { + if (!items || !items.length) { + return; } - }]; - }; - chart.boxes.push(item); - }, - removeBox(chart, layoutItem) { - const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; - if (index !== -1) { - chart.boxes.splice(index, 1); + this._getAnims(chart).items.push(...items); } - }, - configure(chart, item, options) { - item.fullSize = options.fullSize; - item.position = options.position; - item.weight = options.weight; - }, - update(chart, width, height, minPadding) { - if (!chart) { - return; + has(chart) { + return this._getAnims(chart).items.length > 0; } - const padding = toPadding(chart.options.layout.padding); - const availableWidth = Math.max(width - padding.width, 0); - const availableHeight = Math.max(height - padding.height, 0); - const boxes = buildLayoutBoxes(chart.boxes); - const verticalBoxes = boxes.vertical; - const horizontalBoxes = boxes.horizontal; - each(chart.boxes, box => { - if (typeof box.beforeLayout === 'function') { - box.beforeLayout(); - } - }); - const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => - wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; - const params = Object.freeze({ - outerWidth: width, - outerHeight: height, - padding, - availableWidth, - availableHeight, - vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, - hBoxMaxHeight: availableHeight / 2 - }); - const maxPadding = Object.assign({}, padding); - updateMaxPadding(maxPadding, toPadding(minPadding)); - const chartArea = Object.assign({ - maxPadding, - w: availableWidth, - h: availableHeight, - x: padding.left, - y: padding.top - }, padding); - const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); - fitBoxes(boxes.fullSize, chartArea, params, stacks); - fitBoxes(verticalBoxes, chartArea, params, stacks); - if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { - fitBoxes(verticalBoxes, chartArea, params, stacks); + start(chart) { + const anims = this._charts.get(chart); + if (!anims) { + return; + } + anims.running = true; + anims.start = Date.now(); + anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0); + this._refresh(); } - handleMaxPadding(chartArea); - placeBoxes(boxes.leftAndTop, chartArea, params, stacks); - chartArea.x += chartArea.w; - chartArea.y += chartArea.h; - placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); - chart.chartArea = { - left: chartArea.left, - top: chartArea.top, - right: chartArea.left + chartArea.w, - bottom: chartArea.top + chartArea.h, - height: chartArea.h, - width: chartArea.w, - }; - each(boxes.chartArea, (layout) => { - const box = layout.box; - Object.assign(box, chart.chartArea); - box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0}); - }); - } -}; - -function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) { - if (!defined(fallback)) { - fallback = _resolve('_fallback', scopes); - } - const cache = { - [Symbol.toStringTag]: 'Object', - _cacheable: true, - _scopes: scopes, - _rootScopes: rootScopes, - _fallback: fallback, - _getTarget: getTarget, - override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback), - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete target._keys; - delete scopes[0][prop]; - return true; - }, - get(target, prop) { - return _cached(target, prop, - () => _resolveWithPrefixes(prop, prefixes, scopes, target)); - }, - getOwnPropertyDescriptor(target, prop) { - return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(scopes[0]); - }, - has(target, prop) { - return getKeysFromAllScopes(target).includes(prop); - }, - ownKeys(target) { - return getKeysFromAllScopes(target); - }, - set(target, prop, value) { - const storage = target._storage || (target._storage = getTarget()); - target[prop] = storage[prop] = value; - delete target._keys; - return true; + running(chart) { + if (!this._running) { + return false; + } + const anims = this._charts.get(chart); + if (!anims || !anims.running || !anims.items.length) { + return false; + } + return true; } - }); -} -function _attachContext(proxy, context, subProxy, descriptorDefaults) { - const cache = { - _cacheable: false, - _proxy: proxy, - _context: context, - _subProxy: subProxy, - _stack: new Set(), - _descriptors: _descriptors(proxy, descriptorDefaults), - setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults), - override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete proxy[prop]; - return true; - }, - get(target, prop, receiver) { - return _cached(target, prop, - () => _resolveWithContext(target, prop, receiver)); - }, - getOwnPropertyDescriptor(target, prop) { - return target._descriptors.allKeys - ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined - : Reflect.getOwnPropertyDescriptor(proxy, prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(proxy); - }, - has(target, prop) { - return Reflect.has(proxy, prop); - }, - ownKeys() { - return Reflect.ownKeys(proxy); - }, - set(target, prop, value) { - proxy[prop] = value; - delete target[prop]; - return true; + stop(chart) { + const anims = this._charts.get(chart); + if (!anims || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + for(; i >= 0; --i){ + items[i].cancel(); + } + anims.items = []; + this._notify(chart, anims, Date.now(), 'complete'); } - }); -} -function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) { - const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy; - return { - allKeys: _allKeys, - scriptable: _scriptable, - indexable: _indexable, - isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable, - isIndexable: isFunction(_indexable) ? _indexable : () => _indexable - }; -} -const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name; -const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' && - (Object.getPrototypeOf(value) === null || value.constructor === Object); -function _cached(target, prop, resolve) { - if (Object.prototype.hasOwnProperty.call(target, prop)) { - return target[prop]; - } - const value = resolve(); - target[prop] = value; - return value; -} -function _resolveWithContext(target, prop, receiver) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - let value = _proxy[prop]; - if (isFunction(value) && descriptors.isScriptable(prop)) { - value = _resolveScriptable(prop, value, target, receiver); - } - if (isArray(value) && value.length) { - value = _resolveArray(prop, value, target, descriptors.isIndexable); - } - if (needsSubResolver(prop, value)) { - value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); - } - return value; -} -function _resolveScriptable(prop, value, target, receiver) { - const {_proxy, _context, _subProxy, _stack} = target; - if (_stack.has(prop)) { - throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); - } - _stack.add(prop); - value = value(_context, _subProxy || receiver); - _stack.delete(prop); - if (needsSubResolver(prop, value)) { - value = createSubResolver(_proxy._scopes, _proxy, prop, value); - } - return value; -} -function _resolveArray(prop, value, target, isIndexable) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - if (defined(_context.index) && isIndexable(prop)) { - value = value[_context.index % value.length]; - } else if (isObject(value[0])) { - const arr = value; - const scopes = _proxy._scopes.filter(s => s !== arr); - value = []; - for (const item of arr) { - const resolver = createSubResolver(scopes, _proxy, prop, item); - value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); + remove(chart) { + return this._charts.delete(chart); } - } - return value; } -function resolveFallback(fallback, prop, value) { - return isFunction(fallback) ? fallback(prop, value) : fallback; -} -const getScope = (key, parent) => key === true ? parent - : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; -function addScopes(set, parentScopes, key, parentFallback, value) { - for (const parent of parentScopes) { - const scope = getScope(key, parent); - if (scope) { - set.add(scope); - const fallback = resolveFallback(scope._fallback, key, value); - if (defined(fallback) && fallback !== key && fallback !== parentFallback) { - return fallback; - } - } else if (scope === false && defined(parentFallback) && key !== parentFallback) { - return null; - } - } - return false; -} -function createSubResolver(parentScopes, resolver, prop, value) { - const rootScopes = resolver._rootScopes; - const fallback = resolveFallback(resolver._fallback, prop, value); - const allScopes = [...parentScopes, ...rootScopes]; - const set = new Set(); - set.add(value); - let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); - if (key === null) { - return false; - } - if (defined(fallback) && fallback !== prop) { - key = addScopesFromKey(set, allScopes, fallback, key, value); - if (key === null) { - return false; - } - } - return _createResolver(Array.from(set), [''], rootScopes, fallback, - () => subGetTarget(resolver, prop, value)); -} -function addScopesFromKey(set, allScopes, key, fallback, item) { - while (key) { - key = addScopes(set, allScopes, key, fallback, item); - } - return key; -} -function subGetTarget(resolver, prop, value) { - const parent = resolver._getTarget(); - if (!(prop in parent)) { - parent[prop] = {}; - } - const target = parent[prop]; - if (isArray(target) && isObject(value)) { - return value; - } - return target; -} -function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { - let value; - for (const prefix of prefixes) { - value = _resolve(readKey(prefix, prop), scopes); - if (defined(value)) { - return needsSubResolver(prop, value) - ? createSubResolver(scopes, proxy, prop, value) - : value; - } - } -} -function _resolve(key, scopes) { - for (const scope of scopes) { - if (!scope) { - continue; - } - const value = scope[key]; - if (defined(value)) { - return value; - } - } -} -function getKeysFromAllScopes(target) { - let keys = target._keys; - if (!keys) { - keys = target._keys = resolveKeysFromAllScopes(target._scopes); - } - return keys; -} -function resolveKeysFromAllScopes(scopes) { - const set = new Set(); - for (const scope of scopes) { - for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) { - set.add(key); - } - } - return Array.from(set); -} - -const EPSILON = Number.EPSILON || 1e-14; -const getPoint = (points, i) => i < points.length && !points[i].skip && points[i]; -const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x'; -function splineCurve(firstPoint, middlePoint, afterPoint, t) { - const previous = firstPoint.skip ? middlePoint : firstPoint; - const current = middlePoint; - const next = afterPoint.skip ? middlePoint : afterPoint; - const d01 = distanceBetweenPoints(current, previous); - const d12 = distanceBetweenPoints(next, current); - let s01 = d01 / (d01 + d12); - let s12 = d12 / (d01 + d12); - s01 = isNaN(s01) ? 0 : s01; - s12 = isNaN(s12) ? 0 : s12; - const fa = t * s01; - const fb = t * s12; - return { - previous: { - x: current.x - fa * (next.x - previous.x), - y: current.y - fa * (next.y - previous.y) - }, - next: { - x: current.x + fb * (next.x - previous.x), - y: current.y + fb * (next.y - previous.y) - } - }; -} -function monotoneAdjust(points, deltaK, mK) { - const pointsLen = points.length; - let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen - 1; ++i) { - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent || !pointAfter) { - continue; - } - if (almostEquals(deltaK[i], 0, EPSILON)) { - mK[i] = mK[i + 1] = 0; - continue; - } - alphaK = mK[i] / deltaK[i]; - betaK = mK[i + 1] / deltaK[i]; - squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); - if (squaredMagnitude <= 9) { - continue; - } - tauK = 3 / Math.sqrt(squaredMagnitude); - mK[i] = alphaK * tauK * deltaK[i]; - mK[i + 1] = betaK * tauK * deltaK[i]; - } -} -function monotoneCompute(points, mK, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - let delta, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - const iPixel = pointCurrent[indexAxis]; - const vPixel = pointCurrent[valueAxis]; - if (pointBefore) { - delta = (iPixel - pointBefore[indexAxis]) / 3; - pointCurrent[`cp1${indexAxis}`] = iPixel - delta; - pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; - } - if (pointAfter) { - delta = (pointAfter[indexAxis] - iPixel) / 3; - pointCurrent[`cp2${indexAxis}`] = iPixel + delta; - pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; - } - } -} -function splineCurveMonotone(points, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - const deltaK = Array(pointsLen).fill(0); - const mK = Array(pointsLen); - let i, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - if (pointAfter) { - const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; - deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; - } - mK[i] = !pointBefore ? deltaK[i] - : !pointAfter ? deltaK[i - 1] - : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0 - : (deltaK[i - 1] + deltaK[i]) / 2; - } - monotoneAdjust(points, deltaK, mK); - monotoneCompute(points, mK, indexAxis); -} -function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); -} -function capBezierPoints(points, area) { - let i, ilen, point, inArea, inAreaPrev; - let inAreaNext = _isPointInArea(points[0], area); - for (i = 0, ilen = points.length; i < ilen; ++i) { - inAreaPrev = inArea; - inArea = inAreaNext; - inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); - if (!inArea) { - continue; - } - point = points[i]; - if (inAreaPrev) { - point.cp1x = capControlPoint(point.cp1x, area.left, area.right); - point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); - } - if (inAreaNext) { - point.cp2x = capControlPoint(point.cp2x, area.left, area.right); - point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); - } - } -} -function _updateBezierControlPoints(points, options, area, loop, indexAxis) { - let i, ilen, point, controlPoints; - if (options.spanGaps) { - points = points.filter((pt) => !pt.skip); - } - if (options.cubicInterpolationMode === 'monotone') { - splineCurveMonotone(points, indexAxis); - } else { - let prev = loop ? points[points.length - 1] : points[0]; - for (i = 0, ilen = points.length; i < ilen; ++i) { - point = points[i]; - controlPoints = splineCurve( - prev, - point, - points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], - options.tension - ); - point.cp1x = controlPoints.previous.x; - point.cp1y = controlPoints.previous.y; - point.cp2x = controlPoints.next.x; - point.cp2y = controlPoints.next.y; - prev = point; - } - } - if (options.capBezierPoints) { - capBezierPoints(points, area); - } -} - -const atEdge = (t) => t === 0 || t === 1; -const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); -const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; -const effects = { - linear: t => t, - easeInQuad: t => t * t, - easeOutQuad: t => -t * (t - 2), - easeInOutQuad: t => ((t /= 0.5) < 1) - ? 0.5 * t * t - : -0.5 * ((--t) * (t - 2) - 1), - easeInCubic: t => t * t * t, - easeOutCubic: t => (t -= 1) * t * t + 1, - easeInOutCubic: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t - : 0.5 * ((t -= 2) * t * t + 2), - easeInQuart: t => t * t * t * t, - easeOutQuart: t => -((t -= 1) * t * t * t - 1), - easeInOutQuart: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t - : -0.5 * ((t -= 2) * t * t * t - 2), - easeInQuint: t => t * t * t * t * t, - easeOutQuint: t => (t -= 1) * t * t * t * t + 1, - easeInOutQuint: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t * t - : 0.5 * ((t -= 2) * t * t * t * t + 2), - easeInSine: t => -Math.cos(t * HALF_PI) + 1, - easeOutSine: t => Math.sin(t * HALF_PI), - easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1), - easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)), - easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1, - easeInOutExpo: t => atEdge(t) ? t : t < 0.5 - ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) - : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), - easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1), - easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t), - easeInOutCirc: t => ((t /= 0.5) < 1) - ? -0.5 * (Math.sqrt(1 - t * t) - 1) - : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), - easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3), - easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3), - easeInOutElastic(t) { - const s = 0.1125; - const p = 0.45; - return atEdge(t) ? t : - t < 0.5 - ? 0.5 * elasticIn(t * 2, s, p) - : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); - }, - easeInBack(t) { - const s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - easeOutBack(t) { - const s = 1.70158; - return (t -= 1) * t * ((s + 1) * t + s) + 1; - }, - easeInOutBack(t) { - let s = 1.70158; - if ((t /= 0.5) < 1) { - return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); - } - return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - easeInBounce: t => 1 - effects.easeOutBounce(1 - t), - easeOutBounce(t) { - const m = 7.5625; - const d = 2.75; - if (t < (1 / d)) { - return m * t * t; - } - if (t < (2 / d)) { - return m * (t -= (1.5 / d)) * t + 0.75; - } - if (t < (2.5 / d)) { - return m * (t -= (2.25 / d)) * t + 0.9375; - } - return m * (t -= (2.625 / d)) * t + 0.984375; - }, - easeInOutBounce: t => (t < 0.5) - ? effects.easeInBounce(t * 2) * 0.5 - : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5, -}; - -function _pointInLine(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: p1.y + t * (p2.y - p1.y) - }; -} -function _steppedInterpolation(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y - : mode === 'after' ? t < 1 ? p1.y : p2.y - : t > 0 ? p2.y : p1.y - }; -} -function _bezierInterpolation(p1, p2, t, mode) { - const cp1 = {x: p1.cp2x, y: p1.cp2y}; - const cp2 = {x: p2.cp1x, y: p2.cp1y}; - const a = _pointInLine(p1, cp1, t); - const b = _pointInLine(cp1, cp2, t); - const c = _pointInLine(cp2, p2, t); - const d = _pointInLine(a, b, t); - const e = _pointInLine(b, c, t); - return _pointInLine(d, e, t); -} - -const intlCache = new Map(); -function getNumberFormat(locale, options) { - options = options || {}; - const cacheKey = locale + JSON.stringify(options); - let formatter = intlCache.get(cacheKey); - if (!formatter) { - formatter = new Intl.NumberFormat(locale, options); - intlCache.set(cacheKey, formatter); - } - return formatter; -} -function formatNumber(num, locale, options) { - return getNumberFormat(locale, options).format(num); -} - -const getRightToLeftAdapter = function(rectX, width) { - return { - x(x) { - return rectX + rectX + width - x; - }, - setWidth(w) { - width = w; - }, - textAlign(align) { - if (align === 'center') { - return align; - } - return align === 'right' ? 'left' : 'right'; - }, - xPlus(x, value) { - return x - value; - }, - leftForLtr(x, itemWidth) { - return x - itemWidth; - }, - }; -}; -const getLeftToRightAdapter = function() { - return { - x(x) { - return x; - }, - setWidth(w) { - }, - textAlign(align) { - return align; - }, - xPlus(x, value) { - return x + value; - }, - leftForLtr(x, _itemWidth) { - return x; - }, - }; -}; -function getRtlAdapter(rtl, rectX, width) { - return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); -} -function overrideTextDirection(ctx, direction) { - let style, original; - if (direction === 'ltr' || direction === 'rtl') { - style = ctx.canvas.style; - original = [ - style.getPropertyValue('direction'), - style.getPropertyPriority('direction'), - ]; - style.setProperty('direction', direction, 'important'); - ctx.prevTextDirection = original; - } -} -function restoreTextDirection(ctx, original) { - if (original !== undefined) { - delete ctx.prevTextDirection; - ctx.canvas.style.setProperty('direction', original[0], original[1]); - } -} - -function propertyFn(property) { - if (property === 'angle') { - return { - between: _angleBetween, - compare: _angleDiff, - normalize: _normalizeAngle, - }; - } - return { - between: _isBetween, - compare: (a, b) => a - b, - normalize: x => x - }; -} -function normalizeSegment({start, end, count, loop, style}) { - return { - start: start % count, - end: end % count, - loop: loop && (end - start + 1) % count === 0, - style - }; -} -function getSegment(segment, points, bounds) { - const {property, start: startBound, end: endBound} = bounds; - const {between, normalize} = propertyFn(property); - const count = points.length; - let {start, end, loop} = segment; - let i, ilen; - if (loop) { - start += count; - end += count; - for (i = 0, ilen = count; i < ilen; ++i) { - if (!between(normalize(points[start % count][property]), startBound, endBound)) { - break; - } - start--; - end--; - } - start %= count; - end %= count; - } - if (end < start) { - end += count; - } - return {start, end, loop, style: segment.style}; -} -function _boundSegment(segment, points, bounds) { - if (!bounds) { - return [segment]; - } - const {property, start: startBound, end: endBound} = bounds; - const count = points.length; - const {compare, between, normalize} = propertyFn(property); - const {start, end, loop, style} = getSegment(segment, points, bounds); - const result = []; - let inside = false; - let subStart = null; - let value, point, prevValue; - const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; - const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value); - const shouldStart = () => inside || startIsBefore(); - const shouldStop = () => !inside || endIsBefore(); - for (let i = start, prev = start; i <= end; ++i) { - point = points[i % count]; - if (point.skip) { - continue; - } - value = normalize(point[property]); - if (value === prevValue) { - continue; - } - inside = between(value, startBound, endBound); - if (subStart === null && shouldStart()) { - subStart = compare(value, startBound) === 0 ? i : prev; - } - if (subStart !== null && shouldStop()) { - result.push(normalizeSegment({start: subStart, end: i, loop, count, style})); - subStart = null; - } - prev = i; - prevValue = value; - } - if (subStart !== null) { - result.push(normalizeSegment({start: subStart, end, loop, count, style})); - } - return result; -} -function _boundSegments(line, bounds) { - const result = []; - const segments = line.segments; - for (let i = 0; i < segments.length; i++) { - const sub = _boundSegment(segments[i], line.points, bounds); - if (sub.length) { - result.push(...sub); - } - } - return result; -} -function findStartAndEnd(points, count, loop, spanGaps) { - let start = 0; - let end = count - 1; - if (loop && !spanGaps) { - while (start < count && !points[start].skip) { - start++; - } - } - while (start < count && points[start].skip) { - start++; - } - start %= count; - if (loop) { - end += start; - } - while (end > start && points[end % count].skip) { - end--; - } - end %= count; - return {start, end}; -} -function solidSegments(points, start, max, loop) { - const count = points.length; - const result = []; - let last = start; - let prev = points[start]; - let end; - for (end = start + 1; end <= max; ++end) { - const cur = points[end % count]; - if (cur.skip || cur.stop) { - if (!prev.skip) { - loop = false; - result.push({start: start % count, end: (end - 1) % count, loop}); - start = last = cur.stop ? end : null; - } - } else { - last = end; - if (prev.skip) { - start = end; - } - } - prev = cur; - } - if (last !== null) { - result.push({start: start % count, end: last % count, loop}); - } - return result; -} -function _computeSegments(line, segmentOptions) { - const points = line.points; - const spanGaps = line.options.spanGaps; - const count = points.length; - if (!count) { - return []; - } - const loop = !!line._loop; - const {start, end} = findStartAndEnd(points, count, loop, spanGaps); - if (spanGaps === true) { - return splitByStyles(line, [{start, end, loop}], points, segmentOptions); - } - const max = end < start ? end + count : end; - const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; - return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); -} -function splitByStyles(line, segments, points, segmentOptions) { - if (!segmentOptions || !segmentOptions.setContext || !points) { - return segments; - } - return doSplitByStyles(line, segments, points, segmentOptions); -} -function doSplitByStyles(line, segments, points, segmentOptions) { - const chartContext = line._chart.getContext(); - const baseStyle = readStyle(line.options); - const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; - const count = points.length; - const result = []; - let prevStyle = baseStyle; - let start = segments[0].start; - let i = start; - function addStyle(s, e, l, st) { - const dir = spanGaps ? -1 : 1; - if (s === e) { - return; - } - s += count; - while (points[s % count].skip) { - s -= dir; - } - while (points[e % count].skip) { - e += dir; - } - if (s % count !== e % count) { - result.push({start: s % count, end: e % count, loop: l, style: st}); - prevStyle = st; - start = e % count; - } - } - for (const segment of segments) { - start = spanGaps ? start : segment.start; - let prev = points[start % count]; - let style; - for (i = start + 1; i <= segment.end; i++) { - const pt = points[i % count]; - style = readStyle(segmentOptions.setContext(createContext(chartContext, { - type: 'segment', - p0: prev, - p1: pt, - p0DataIndex: (i - 1) % count, - p1DataIndex: i % count, - datasetIndex - }))); - if (styleChanged(style, prevStyle)) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - prev = pt; - prevStyle = style; - } - if (start < i - 1) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - } - return result; -} -function readStyle(options) { - return { - backgroundColor: options.backgroundColor, - borderCapStyle: options.borderCapStyle, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderJoinStyle: options.borderJoinStyle, - borderWidth: options.borderWidth, - borderColor: options.borderColor - }; -} -function styleChanged(style, prevStyle) { - return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle); -} - -var helpers = /*#__PURE__*/Object.freeze({ -__proto__: null, -easingEffects: effects, -color: color, -getHoverColor: getHoverColor, -noop: noop, -uid: uid, -isNullOrUndef: isNullOrUndef, -isArray: isArray, -isObject: isObject, -isFinite: isNumberFinite, -finiteOrDefault: finiteOrDefault, -valueOrDefault: valueOrDefault, -toPercentage: toPercentage, -toDimension: toDimension, -callback: callback, -each: each, -_elementsEqual: _elementsEqual, -clone: clone, -_merger: _merger, -merge: merge, -mergeIf: mergeIf, -_mergerIf: _mergerIf, -_deprecated: _deprecated, -resolveObjectKey: resolveObjectKey, -_capitalize: _capitalize, -defined: defined, -isFunction: isFunction, -setsEqual: setsEqual, -_isClickEvent: _isClickEvent, -toFontString: toFontString, -_measureText: _measureText, -_longestText: _longestText, -_alignPixel: _alignPixel, -clearCanvas: clearCanvas, -drawPoint: drawPoint, -_isPointInArea: _isPointInArea, -clipArea: clipArea, -unclipArea: unclipArea, -_steppedLineTo: _steppedLineTo, -_bezierCurveTo: _bezierCurveTo, -renderText: renderText, -addRoundedRectPath: addRoundedRectPath, -_lookup: _lookup, -_lookupByKey: _lookupByKey, -_rlookupByKey: _rlookupByKey, -_filterBetween: _filterBetween, -listenArrayEvents: listenArrayEvents, -unlistenArrayEvents: unlistenArrayEvents, -_arrayUnique: _arrayUnique, -_createResolver: _createResolver, -_attachContext: _attachContext, -_descriptors: _descriptors, -splineCurve: splineCurve, -splineCurveMonotone: splineCurveMonotone, -_updateBezierControlPoints: _updateBezierControlPoints, -_isDomSupported: _isDomSupported, -_getParentNode: _getParentNode, -getStyle: getStyle, -getRelativePosition: getRelativePosition$1, -getMaximumSize: getMaximumSize, -retinaScale: retinaScale, -supportsEventListenerOptions: supportsEventListenerOptions, -readUsedSize: readUsedSize, -fontString: fontString, -requestAnimFrame: requestAnimFrame, -throttled: throttled, -debounce: debounce, -_toLeftRightCenter: _toLeftRightCenter, -_alignStartEnd: _alignStartEnd, -_textX: _textX, -_pointInLine: _pointInLine, -_steppedInterpolation: _steppedInterpolation, -_bezierInterpolation: _bezierInterpolation, -formatNumber: formatNumber, -toLineHeight: toLineHeight, -_readValueToProps: _readValueToProps, -toTRBL: toTRBL, -toTRBLCorners: toTRBLCorners, -toPadding: toPadding, -toFont: toFont, -resolve: resolve, -_addGrace: _addGrace, -createContext: createContext, -PI: PI, -TAU: TAU, -PITAU: PITAU, -INFINITY: INFINITY, -RAD_PER_DEG: RAD_PER_DEG, -HALF_PI: HALF_PI, -QUARTER_PI: QUARTER_PI, -TWO_THIRDS_PI: TWO_THIRDS_PI, -log10: log10, -sign: sign, -niceNum: niceNum, -_factorize: _factorize, -isNumber: isNumber, -almostEquals: almostEquals, -almostWhole: almostWhole, -_setMinAndMaxByKey: _setMinAndMaxByKey, -toRadians: toRadians, -toDegrees: toDegrees, -_decimalPlaces: _decimalPlaces, -getAngleFromPoint: getAngleFromPoint, -distanceBetweenPoints: distanceBetweenPoints, -_angleDiff: _angleDiff, -_normalizeAngle: _normalizeAngle, -_angleBetween: _angleBetween, -_limitValue: _limitValue, -_int16Range: _int16Range, -_isBetween: _isBetween, -getRtlAdapter: getRtlAdapter, -overrideTextDirection: overrideTextDirection, -restoreTextDirection: restoreTextDirection, -_boundSegment: _boundSegment, -_boundSegments: _boundSegments, -_computeSegments: _computeSegments -}); - -class BasePlatform { - acquireContext(canvas, aspectRatio) {} - releaseContext(context) { - return false; - } - addEventListener(chart, type, listener) {} - removeEventListener(chart, type, listener) {} - getDevicePixelRatio() { - return 1; - } - getMaximumSize(element, width, height, aspectRatio) { - width = Math.max(0, width || element.width); - height = height || element.height; - return { - width, - height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) - }; - } - isAttached(canvas) { - return true; - } - updateConfig(config) { - } -} - -class BasicPlatform extends BasePlatform { - acquireContext(item) { - return item && item.getContext && item.getContext('2d') || null; - } - updateConfig(config) { - config.options.animation = false; - } -} - -const EXPANDO_KEY = '$chartjs'; -const EVENT_TYPES = { - touchstart: 'mousedown', - touchmove: 'mousemove', - touchend: 'mouseup', - pointerenter: 'mouseenter', - pointerdown: 'mousedown', - pointermove: 'mousemove', - pointerup: 'mouseup', - pointerleave: 'mouseout', - pointerout: 'mouseout' -}; -const isNullOrEmpty = value => value === null || value === ''; -function initCanvas(canvas, aspectRatio) { - const style = canvas.style; - const renderHeight = canvas.getAttribute('height'); - const renderWidth = canvas.getAttribute('width'); - canvas[EXPANDO_KEY] = { - initial: { - height: renderHeight, - width: renderWidth, - style: { - display: style.display, - height: style.height, - width: style.width - } - } - }; - style.display = style.display || 'block'; - style.boxSizing = style.boxSizing || 'border-box'; - if (isNullOrEmpty(renderWidth)) { - const displayWidth = readUsedSize(canvas, 'width'); - if (displayWidth !== undefined) { - canvas.width = displayWidth; - } - } - if (isNullOrEmpty(renderHeight)) { - if (canvas.style.height === '') { - canvas.height = canvas.width / (aspectRatio || 2); - } else { - const displayHeight = readUsedSize(canvas, 'height'); - if (displayHeight !== undefined) { - canvas.height = displayHeight; - } - } - } - return canvas; -} -const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; -function addListener(node, type, listener) { - node.addEventListener(type, listener, eventListenerOptions); -} -function removeListener(chart, type, listener) { - chart.canvas.removeEventListener(type, listener, eventListenerOptions); -} -function fromNativeEvent(event, chart) { - const type = EVENT_TYPES[event.type] || event.type; - const {x, y} = getRelativePosition$1(event, chart); - return { - type, - chart, - native: event, - x: x !== undefined ? x : null, - y: y !== undefined ? y : null, - }; -} -function nodeListContains(nodeList, canvas) { - for (const node of nodeList) { - if (node === canvas || node.contains(canvas)) { - return true; - } - } -} -function createAttachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.addedNodes, canvas); - trigger = trigger && !nodeListContains(entry.removedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -function createDetachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.removedNodes, canvas); - trigger = trigger && !nodeListContains(entry.addedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -const drpListeningCharts = new Map(); -let oldDevicePixelRatio = 0; -function onWindowResize() { - const dpr = window.devicePixelRatio; - if (dpr === oldDevicePixelRatio) { - return; - } - oldDevicePixelRatio = dpr; - drpListeningCharts.forEach((resize, chart) => { - if (chart.currentDevicePixelRatio !== dpr) { - resize(); - } - }); -} -function listenDevicePixelRatioChanges(chart, resize) { - if (!drpListeningCharts.size) { - window.addEventListener('resize', onWindowResize); - } - drpListeningCharts.set(chart, resize); -} -function unlistenDevicePixelRatioChanges(chart) { - drpListeningCharts.delete(chart); - if (!drpListeningCharts.size) { - window.removeEventListener('resize', onWindowResize); - } -} -function createResizeObserver(chart, type, listener) { - const canvas = chart.canvas; - const container = canvas && _getParentNode(canvas); - if (!container) { - return; - } - const resize = throttled((width, height) => { - const w = container.clientWidth; - listener(width, height); - if (w < container.clientWidth) { - listener(); - } - }, window); - const observer = new ResizeObserver(entries => { - const entry = entries[0]; - const width = entry.contentRect.width; - const height = entry.contentRect.height; - if (width === 0 && height === 0) { - return; - } - resize(width, height); - }); - observer.observe(container); - listenDevicePixelRatioChanges(chart, resize); - return observer; -} -function releaseObserver(chart, type, observer) { - if (observer) { - observer.disconnect(); - } - if (type === 'resize') { - unlistenDevicePixelRatioChanges(chart); - } -} -function createProxyAndListen(chart, type, listener) { - const canvas = chart.canvas; - const proxy = throttled((event) => { - if (chart.ctx !== null) { - listener(fromNativeEvent(event, chart)); - } - }, chart, (args) => { - const event = args[0]; - return [event, event.offsetX, event.offsetY]; - }); - addListener(canvas, type, proxy); - return proxy; -} -class DomPlatform extends BasePlatform { - acquireContext(canvas, aspectRatio) { - const context = canvas && canvas.getContext && canvas.getContext('2d'); - if (context && context.canvas === canvas) { - initCanvas(canvas, aspectRatio); - return context; - } - return null; - } - releaseContext(context) { - const canvas = context.canvas; - if (!canvas[EXPANDO_KEY]) { - return false; - } - const initial = canvas[EXPANDO_KEY].initial; - ['height', 'width'].forEach((prop) => { - const value = initial[prop]; - if (isNullOrUndef(value)) { - canvas.removeAttribute(prop); - } else { - canvas.setAttribute(prop, value); - } - }); - const style = initial.style || {}; - Object.keys(style).forEach((key) => { - canvas.style[key] = style[key]; - }); - canvas.width = canvas.width; - delete canvas[EXPANDO_KEY]; - return true; - } - addEventListener(chart, type, listener) { - this.removeEventListener(chart, type); - const proxies = chart.$proxies || (chart.$proxies = {}); - const handlers = { - attach: createAttachObserver, - detach: createDetachObserver, - resize: createResizeObserver - }; - const handler = handlers[type] || createProxyAndListen; - proxies[type] = handler(chart, type, listener); - } - removeEventListener(chart, type) { - const proxies = chart.$proxies || (chart.$proxies = {}); - const proxy = proxies[type]; - if (!proxy) { - return; - } - const handlers = { - attach: releaseObserver, - detach: releaseObserver, - resize: releaseObserver - }; - const handler = handlers[type] || removeListener; - handler(chart, type, proxy); - proxies[type] = undefined; - } - getDevicePixelRatio() { - return window.devicePixelRatio; - } - getMaximumSize(canvas, width, height, aspectRatio) { - return getMaximumSize(canvas, width, height, aspectRatio); - } - isAttached(canvas) { - const container = _getParentNode(canvas); - return !!(container && container.isConnected); - } -} - -function _detectPlatform(canvas) { - if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { - return BasicPlatform; - } - return DomPlatform; -} - -var platforms = /*#__PURE__*/Object.freeze({ -__proto__: null, -_detectPlatform: _detectPlatform, -BasePlatform: BasePlatform, -BasicPlatform: BasicPlatform, -DomPlatform: DomPlatform -}); +var animator = /* #__PURE__ */ new Animator(); const transparent = 'transparent'; const interpolators = { - boolean(from, to, factor) { - return factor > 0.5 ? to : from; - }, - color(from, to, factor) { - const c0 = color(from || transparent); - const c1 = c0.valid && color(to || transparent); - return c1 && c1.valid - ? c1.mix(c0, factor).hexString() - : to; - }, - number(from, to, factor) { - return from + (to - from) * factor; - } + boolean (from, to, factor) { + return factor > 0.5 ? to : from; + }, + color (from, to, factor) { + const c0 = color(from || transparent); + const c1 = c0.valid && color(to || transparent); + return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to; + }, + number (from, to, factor) { + return from + (to - from) * factor; + } }; class Animation { - constructor(cfg, target, prop, to) { - const currentValue = target[prop]; - to = resolve([cfg.to, to, currentValue, cfg.from]); - const from = resolve([cfg.from, currentValue, to]); - this._active = true; - this._fn = cfg.fn || interpolators[cfg.type || typeof from]; - this._easing = effects[cfg.easing] || effects.linear; - this._start = Math.floor(Date.now() + (cfg.delay || 0)); - this._duration = this._total = Math.floor(cfg.duration); - this._loop = !!cfg.loop; - this._target = target; - this._prop = prop; - this._from = from; - this._to = to; - this._promises = undefined; - } - active() { - return this._active; - } - update(cfg, to, date) { - if (this._active) { - this._notify(false); - const currentValue = this._target[this._prop]; - const elapsed = date - this._start; - const remain = this._duration - elapsed; - this._start = date; - this._duration = Math.floor(Math.max(remain, cfg.duration)); - this._total += elapsed; - this._loop = !!cfg.loop; - this._to = resolve([cfg.to, to, currentValue, cfg.from]); - this._from = resolve([cfg.from, currentValue, to]); + constructor(cfg, target, prop, to){ + const currentValue = target[prop]; + to = resolve([ + cfg.to, + to, + currentValue, + cfg.from + ]); + const from = resolve([ + cfg.from, + currentValue, + to + ]); + this._active = true; + this._fn = cfg.fn || interpolators[cfg.type || typeof from]; + this._easing = effects[cfg.easing] || effects.linear; + this._start = Math.floor(Date.now() + (cfg.delay || 0)); + this._duration = this._total = Math.floor(cfg.duration); + this._loop = !!cfg.loop; + this._target = target; + this._prop = prop; + this._from = from; + this._to = to; + this._promises = undefined; } - } - cancel() { - if (this._active) { - this.tick(Date.now()); - this._active = false; - this._notify(false); + active() { + return this._active; } - } - tick(date) { - const elapsed = date - this._start; - const duration = this._duration; - const prop = this._prop; - const from = this._from; - const loop = this._loop; - const to = this._to; - let factor; - this._active = from !== to && (loop || (elapsed < duration)); - if (!this._active) { - this._target[prop] = to; - this._notify(true); - return; + update(cfg, to, date) { + if (this._active) { + this._notify(false); + const currentValue = this._target[this._prop]; + const elapsed = date - this._start; + const remain = this._duration - elapsed; + this._start = date; + this._duration = Math.floor(Math.max(remain, cfg.duration)); + this._total += elapsed; + this._loop = !!cfg.loop; + this._to = resolve([ + cfg.to, + to, + currentValue, + cfg.from + ]); + this._from = resolve([ + cfg.from, + currentValue, + to + ]); + } } - if (elapsed < 0) { - this._target[prop] = from; - return; + cancel() { + if (this._active) { + this.tick(Date.now()); + this._active = false; + this._notify(false); + } } - factor = (elapsed / duration) % 2; - factor = loop && factor > 1 ? 2 - factor : factor; - factor = this._easing(Math.min(1, Math.max(0, factor))); - this._target[prop] = this._fn(from, to, factor); - } - wait() { - const promises = this._promises || (this._promises = []); - return new Promise((res, rej) => { - promises.push({res, rej}); - }); - } - _notify(resolved) { - const method = resolved ? 'res' : 'rej'; - const promises = this._promises || []; - for (let i = 0; i < promises.length; i++) { - promises[i][method](); + tick(date) { + const elapsed = date - this._start; + const duration = this._duration; + const prop = this._prop; + const from = this._from; + const loop = this._loop; + const to = this._to; + let factor; + this._active = from !== to && (loop || elapsed < duration); + if (!this._active) { + this._target[prop] = to; + this._notify(true); + return; + } + if (elapsed < 0) { + this._target[prop] = from; + return; + } + factor = elapsed / duration % 2; + factor = loop && factor > 1 ? 2 - factor : factor; + factor = this._easing(Math.min(1, Math.max(0, factor))); + this._target[prop] = this._fn(from, to, factor); + } + wait() { + const promises = this._promises || (this._promises = []); + return new Promise((res, rej)=>{ + promises.push({ + res, + rej + }); + }); + } + _notify(resolved) { + const method = resolved ? 'res' : 'rej'; + const promises = this._promises || []; + for(let i = 0; i < promises.length; i++){ + promises[i][method](); + } } - } } -const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; -const colors = ['color', 'borderColor', 'backgroundColor']; -defaults.set('animation', { - delay: undefined, - duration: 1000, - easing: 'easeOutQuart', - fn: undefined, - from: undefined, - loop: undefined, - to: undefined, - type: undefined, -}); -const animationOptions = Object.keys(defaults.animation); -defaults.describe('animation', { - _fallback: false, - _indexable: false, - _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn', -}); -defaults.set('animations', { - colors: { - type: 'color', - properties: colors - }, - numbers: { - type: 'number', - properties: numbers - }, -}); -defaults.describe('animations', { - _fallback: 'animation', -}); -defaults.set('transitions', { - active: { - animation: { - duration: 400 - } - }, - resize: { - animation: { - duration: 0 - } - }, - show: { - animations: { - colors: { - from: 'transparent' - }, - visible: { - type: 'boolean', - duration: 0 - }, - } - }, - hide: { - animations: { - colors: { - to: 'transparent' - }, - visible: { - type: 'boolean', - easing: 'linear', - fn: v => v | 0 - }, - } - } -}); class Animations { - constructor(chart, config) { - this._chart = chart; - this._properties = new Map(); - this.configure(config); - } - configure(config) { - if (!isObject(config)) { - return; + constructor(chart, config){ + this._chart = chart; + this._properties = new Map(); + this.configure(config); } - const animatedProps = this._properties; - Object.getOwnPropertyNames(config).forEach(key => { - const cfg = config[key]; - if (!isObject(cfg)) { - return; - } - const resolved = {}; - for (const option of animationOptions) { - resolved[option] = cfg[option]; - } - (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => { - if (prop === key || !animatedProps.has(prop)) { - animatedProps.set(prop, resolved); + configure(config) { + if (!isObject(config)) { + return; } - }); - }); - } - _animateOptions(target, values) { - const newOptions = values.options; - const options = resolveTargetOptions(target, newOptions); - if (!options) { - return []; + const animationOptions = Object.keys(defaults.animation); + const animatedProps = this._properties; + Object.getOwnPropertyNames(config).forEach((key)=>{ + const cfg = config[key]; + if (!isObject(cfg)) { + return; + } + const resolved = {}; + for (const option of animationOptions){ + resolved[option] = cfg[option]; + } + (isArray(cfg.properties) && cfg.properties || [ + key + ]).forEach((prop)=>{ + if (prop === key || !animatedProps.has(prop)) { + animatedProps.set(prop, resolved); + } + }); + }); } - const animations = this._createAnimations(options, newOptions); - if (newOptions.$shared) { - awaitAll(target.options.$animations, newOptions).then(() => { - target.options = newOptions; - }, () => { - }); - } - return animations; - } - _createAnimations(target, values) { - const animatedProps = this._properties; - const animations = []; - const running = target.$animations || (target.$animations = {}); - const props = Object.keys(values); - const date = Date.now(); - let i; - for (i = props.length - 1; i >= 0; --i) { - const prop = props[i]; - if (prop.charAt(0) === '$') { - continue; - } - if (prop === 'options') { - animations.push(...this._animateOptions(target, values)); - continue; - } - const value = values[prop]; - let animation = running[prop]; - const cfg = animatedProps.get(prop); - if (animation) { - if (cfg && animation.active()) { - animation.update(cfg, value, date); - continue; - } else { - animation.cancel(); + _animateOptions(target, values) { + const newOptions = values.options; + const options = resolveTargetOptions(target, newOptions); + if (!options) { + return []; } - } - if (!cfg || !cfg.duration) { - target[prop] = value; - continue; - } - running[prop] = animation = new Animation(cfg, target, prop, value); - animations.push(animation); + const animations = this._createAnimations(options, newOptions); + if (newOptions.$shared) { + awaitAll(target.options.$animations, newOptions).then(()=>{ + target.options = newOptions; + }, ()=>{ + }); + } + return animations; } - return animations; - } - update(target, values) { - if (this._properties.size === 0) { - Object.assign(target, values); - return; + _createAnimations(target, values) { + const animatedProps = this._properties; + const animations = []; + const running = target.$animations || (target.$animations = {}); + const props = Object.keys(values); + const date = Date.now(); + let i; + for(i = props.length - 1; i >= 0; --i){ + const prop = props[i]; + if (prop.charAt(0) === '$') { + continue; + } + if (prop === 'options') { + animations.push(...this._animateOptions(target, values)); + continue; + } + const value = values[prop]; + let animation = running[prop]; + const cfg = animatedProps.get(prop); + if (animation) { + if (cfg && animation.active()) { + animation.update(cfg, value, date); + continue; + } else { + animation.cancel(); + } + } + if (!cfg || !cfg.duration) { + target[prop] = value; + continue; + } + running[prop] = animation = new Animation(cfg, target, prop, value); + animations.push(animation); + } + return animations; } - const animations = this._createAnimations(target, values); - if (animations.length) { - animator.add(this._chart, animations); - return true; + update(target, values) { + if (this._properties.size === 0) { + Object.assign(target, values); + return; + } + const animations = this._createAnimations(target, values); + if (animations.length) { + animator.add(this._chart, animations); + return true; + } } - } } function awaitAll(animations, properties) { - const running = []; - const keys = Object.keys(properties); - for (let i = 0; i < keys.length; i++) { - const anim = animations[keys[i]]; - if (anim && anim.active()) { - running.push(anim.wait()); + const running = []; + const keys = Object.keys(properties); + for(let i = 0; i < keys.length; i++){ + const anim = animations[keys[i]]; + if (anim && anim.active()) { + running.push(anim.wait()); + } } - } - return Promise.all(running); + return Promise.all(running); } function resolveTargetOptions(target, newOptions) { - if (!newOptions) { - return; - } - let options = target.options; - if (!options) { - target.options = newOptions; - return; - } - if (options.$shared) { - target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); - } - return options; + if (!newOptions) { + return; + } + let options = target.options; + if (!options) { + target.options = newOptions; + return; + } + if (options.$shared) { + target.options = options = Object.assign({}, options, { + $shared: false, + $animations: {} + }); + } + return options; } function scaleClip(scale, allowedOverflow) { - const opts = scale && scale.options || {}; - const reverse = opts.reverse; - const min = opts.min === undefined ? allowedOverflow : 0; - const max = opts.max === undefined ? allowedOverflow : 0; - return { - start: reverse ? max : min, - end: reverse ? min : max - }; + const opts = scale && scale.options || {}; + const reverse = opts.reverse; + const min = opts.min === undefined ? allowedOverflow : 0; + const max = opts.max === undefined ? allowedOverflow : 0; + return { + start: reverse ? max : min, + end: reverse ? min : max + }; } function defaultClip(xScale, yScale, allowedOverflow) { - if (allowedOverflow === false) { - return false; - } - const x = scaleClip(xScale, allowedOverflow); - const y = scaleClip(yScale, allowedOverflow); - return { - top: y.end, - right: x.end, - bottom: y.start, - left: x.start - }; + if (allowedOverflow === false) { + return false; + } + const x = scaleClip(xScale, allowedOverflow); + const y = scaleClip(yScale, allowedOverflow); + return { + top: y.end, + right: x.end, + bottom: y.start, + left: x.start + }; } function toClip(value) { - let t, r, b, l; - if (isObject(value)) { - t = value.top; - r = value.right; - b = value.bottom; - l = value.left; - } else { - t = r = b = l = value; - } - return { - top: t, - right: r, - bottom: b, - left: l, - disabled: value === false - }; + let t, r, b, l; + if (isObject(value)) { + t = value.top; + r = value.right; + b = value.bottom; + l = value.left; + } else { + t = r = b = l = value; + } + return { + top: t, + right: r, + bottom: b, + left: l, + disabled: value === false + }; } function getSortedDatasetIndices(chart, filterVisible) { - const keys = []; - const metasets = chart._getSortedDatasetMetas(filterVisible); - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - keys.push(metasets[i].index); - } - return keys; + const keys = []; + const metasets = chart._getSortedDatasetMetas(filterVisible); + let i, ilen; + for(i = 0, ilen = metasets.length; i < ilen; ++i){ + keys.push(metasets[i].index); + } + return keys; } function applyStack(stack, value, dsIndex, options = {}) { - const keys = stack.keys; - const singleMode = options.mode === 'single'; - let i, ilen, datasetIndex, otherValue; - if (value === null) { - return; - } - for (i = 0, ilen = keys.length; i < ilen; ++i) { - datasetIndex = +keys[i]; - if (datasetIndex === dsIndex) { - if (options.all) { - continue; - } - break; + const keys = stack.keys; + const singleMode = options.mode === 'single'; + let i, ilen, datasetIndex, otherValue; + if (value === null) { + return; } - otherValue = stack.values[datasetIndex]; - if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) { - value += otherValue; + for(i = 0, ilen = keys.length; i < ilen; ++i){ + datasetIndex = +keys[i]; + if (datasetIndex === dsIndex) { + if (options.all) { + continue; + } + break; + } + otherValue = stack.values[datasetIndex]; + if (isNumberFinite(otherValue) && (singleMode || value === 0 || sign(value) === sign(otherValue))) { + value += otherValue; + } } - } - return value; + return value; } function convertObjectDataToArray(data) { - const keys = Object.keys(data); - const adata = new Array(keys.length); - let i, ilen, key; - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - adata[i] = { - x: key, - y: data[key] - }; - } - return adata; + const keys = Object.keys(data); + const adata = new Array(keys.length); + let i, ilen, key; + for(i = 0, ilen = keys.length; i < ilen; ++i){ + key = keys[i]; + adata[i] = { + x: key, + y: data[key] + }; + } + return adata; } function isStacked(scale, meta) { - const stacked = scale && scale.options.stacked; - return stacked || (stacked === undefined && meta.stack !== undefined); + const stacked = scale && scale.options.stacked; + return stacked || stacked === undefined && meta.stack !== undefined; } function getStackKey(indexScale, valueScale, meta) { - return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; + return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; } function getUserBounds(scale) { - const {min, max, minDefined, maxDefined} = scale.getUserBounds(); - return { - min: minDefined ? min : Number.NEGATIVE_INFINITY, - max: maxDefined ? max : Number.POSITIVE_INFINITY - }; + const { min , max , minDefined , maxDefined } = scale.getUserBounds(); + return { + min: minDefined ? min : Number.NEGATIVE_INFINITY, + max: maxDefined ? max : Number.POSITIVE_INFINITY + }; } function getOrCreateStack(stacks, stackKey, indexValue) { - const subStack = stacks[stackKey] || (stacks[stackKey] = {}); - return subStack[indexValue] || (subStack[indexValue] = {}); + const subStack = stacks[stackKey] || (stacks[stackKey] = {}); + return subStack[indexValue] || (subStack[indexValue] = {}); } function getLastIndexInStack(stack, vScale, positive, type) { - for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) { - const value = stack[meta.index]; - if ((positive && value > 0) || (!positive && value < 0)) { - return meta.index; + for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){ + const value = stack[meta.index]; + if (positive && value > 0 || !positive && value < 0) { + return meta.index; + } } - } - return null; + return null; } function updateStacks(controller, parsed) { - const {chart, _cachedMeta: meta} = controller; - const stacks = chart._stacks || (chart._stacks = {}); - const {iScale, vScale, index: datasetIndex} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const key = getStackKey(iScale, vScale, meta); - const ilen = parsed.length; - let stack; - for (let i = 0; i < ilen; ++i) { - const item = parsed[i]; - const {[iAxis]: index, [vAxis]: value} = item; - const itemStacks = item._stacks || (item._stacks = {}); - stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); - stack[datasetIndex] = value; - stack._top = getLastIndexInStack(stack, vScale, true, meta.type); - stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); - } + const { chart , _cachedMeta: meta } = controller; + const stacks = chart._stacks || (chart._stacks = {}); + const { iScale , vScale , index: datasetIndex } = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const key = getStackKey(iScale, vScale, meta); + const ilen = parsed.length; + let stack; + for(let i = 0; i < ilen; ++i){ + const item = parsed[i]; + const { [iAxis]: index , [vAxis]: value } = item; + const itemStacks = item._stacks || (item._stacks = {}); + stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); + stack[datasetIndex] = value; + stack._top = getLastIndexInStack(stack, vScale, true, meta.type); + stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); + const visualValues = stack._visualValues || (stack._visualValues = {}); + visualValues[datasetIndex] = value; + } } function getFirstScaleId(chart, axis) { - const scales = chart.scales; - return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); + const scales = chart.scales; + return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift(); } function createDatasetContext(parent, index) { - return createContext(parent, - { - active: false, - dataset: undefined, - datasetIndex: index, - index, - mode: 'default', - type: 'dataset' - } - ); + return createContext(parent, { + active: false, + dataset: undefined, + datasetIndex: index, + index, + mode: 'default', + type: 'dataset' + }); } function createDataContext(parent, index, element) { - return createContext(parent, { - active: false, - dataIndex: index, - parsed: undefined, - raw: undefined, - element, - index, - mode: 'default', - type: 'data' - }); + return createContext(parent, { + active: false, + dataIndex: index, + parsed: undefined, + raw: undefined, + element, + index, + mode: 'default', + type: 'data' + }); } function clearStacks(meta, items) { - const datasetIndex = meta.controller.index; - const axis = meta.vScale && meta.vScale.axis; - if (!axis) { - return; - } - items = items || meta._parsed; - for (const parsed of items) { - const stacks = parsed._stacks; - if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { - return; + const datasetIndex = meta.controller.index; + const axis = meta.vScale && meta.vScale.axis; + if (!axis) { + return; + } + items = items || meta._parsed; + for (const parsed of items){ + const stacks = parsed._stacks; + if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { + return; + } + delete stacks[axis][datasetIndex]; + if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) { + delete stacks[axis]._visualValues[datasetIndex]; + } } - delete stacks[axis][datasetIndex]; - } } -const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none'; -const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached); -const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked - && {keys: getSortedDatasetIndices(chart, true), values: null}; +const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none'; +const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached); +const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && { + keys: getSortedDatasetIndices(chart, true), + values: null + }; class DatasetController { - constructor(chart, datasetIndex) { - this.chart = chart; - this._ctx = chart.ctx; - this.index = datasetIndex; - this._cachedDataOpts = {}; - this._cachedMeta = this.getMeta(); - this._type = this._cachedMeta.type; - this.options = undefined; - this._parsing = false; - this._data = undefined; - this._objectData = undefined; - this._sharedOptions = undefined; - this._drawStart = undefined; - this._drawCount = undefined; - this.enableOptionSharing = false; - this.$context = undefined; - this._syncList = []; - this.initialize(); - } - initialize() { - const meta = this._cachedMeta; - this.configure(); - this.linkScales(); - meta._stacked = isStacked(meta.vScale, meta); - this.addElements(); - } - updateIndex(datasetIndex) { - if (this.index !== datasetIndex) { - clearStacks(this._cachedMeta); + static defaults = {}; + static datasetElementType = null; + static dataElementType = null; + constructor(chart, datasetIndex){ + this.chart = chart; + this._ctx = chart.ctx; + this.index = datasetIndex; + this._cachedDataOpts = {}; + this._cachedMeta = this.getMeta(); + this._type = this._cachedMeta.type; + this.options = undefined; + this._parsing = false; + this._data = undefined; + this._objectData = undefined; + this._sharedOptions = undefined; + this._drawStart = undefined; + this._drawCount = undefined; + this.enableOptionSharing = false; + this.supportsDecimation = false; + this.$context = undefined; + this._syncList = []; + this.datasetElementType = new.target.datasetElementType; + this.dataElementType = new.target.dataElementType; + this.initialize(); } - this.index = datasetIndex; - } - linkScales() { - const chart = this.chart; - const meta = this._cachedMeta; - const dataset = this.getDataset(); - const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; - const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); - const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); - const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); - const indexAxis = meta.indexAxis; - const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); - const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); - meta.xScale = this.getScaleForId(xid); - meta.yScale = this.getScaleForId(yid); - meta.rScale = this.getScaleForId(rid); - meta.iScale = this.getScaleForId(iid); - meta.vScale = this.getScaleForId(vid); - } - getDataset() { - return this.chart.data.datasets[this.index]; - } - getMeta() { - return this.chart.getDatasetMeta(this.index); - } - getScaleForId(scaleID) { - return this.chart.scales[scaleID]; - } - _getOtherScale(scale) { - const meta = this._cachedMeta; - return scale === meta.iScale - ? meta.vScale - : meta.iScale; - } - reset() { - this._update('reset'); - } - _destroy() { - const meta = this._cachedMeta; - if (this._data) { - unlistenArrayEvents(this._data, this); - } - if (meta._stacked) { - clearStacks(meta); - } - } - _dataCheck() { - const dataset = this.getDataset(); - const data = dataset.data || (dataset.data = []); - const _data = this._data; - if (isObject(data)) { - this._data = convertObjectDataToArray(data); - } else if (_data !== data) { - if (_data) { - unlistenArrayEvents(_data, this); + initialize() { const meta = this._cachedMeta; - clearStacks(meta); - meta._parsed = []; - } - if (data && Object.isExtensible(data)) { - listenArrayEvents(data, this); - } - this._syncList = []; - this._data = data; - } - } - addElements() { - const meta = this._cachedMeta; - this._dataCheck(); - if (this.datasetElementType) { - meta.dataset = new this.datasetElementType(); - } - } - buildOrUpdateElements(resetNewElements) { - const meta = this._cachedMeta; - const dataset = this.getDataset(); - let stackChanged = false; - this._dataCheck(); - const oldStacked = meta._stacked; - meta._stacked = isStacked(meta.vScale, meta); - if (meta.stack !== dataset.stack) { - stackChanged = true; - clearStacks(meta); - meta.stack = dataset.stack; - } - this._resyncElements(resetNewElements); - if (stackChanged || oldStacked !== meta._stacked) { - updateStacks(this, meta._parsed); - } - } - configure() { - const config = this.chart.config; - const scopeKeys = config.datasetScopeKeys(this._type); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); - this.options = config.createResolver(scopes, this.getContext()); - this._parsing = this.options.parsing; - this._cachedDataOpts = {}; - } - parse(start, count) { - const {_cachedMeta: meta, _data: data} = this; - const {iScale, _stacked} = meta; - const iAxis = iScale.axis; - let sorted = start === 0 && count === data.length ? true : meta._sorted; - let prev = start > 0 && meta._parsed[start - 1]; - let i, cur, parsed; - if (this._parsing === false) { - meta._parsed = data; - meta._sorted = true; - parsed = data; - } else { - if (isArray(data[start])) { - parsed = this.parseArrayData(meta, data, start, count); - } else if (isObject(data[start])) { - parsed = this.parseObjectData(meta, data, start, count); - } else { - parsed = this.parsePrimitiveData(meta, data, start, count); - } - const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]); - for (i = 0; i < count; ++i) { - meta._parsed[i + start] = cur = parsed[i]; - if (sorted) { - if (isNotInOrderComparedToPrev()) { - sorted = false; - } - prev = cur; + this.configure(); + this.linkScales(); + meta._stacked = isStacked(meta.vScale, meta); + this.addElements(); + if (this.options.fill && !this.chart.isPluginEnabled('filler')) { + console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options"); } - } - meta._sorted = sorted; } - if (_stacked) { - updateStacks(this, parsed); - } - } - parsePrimitiveData(meta, data, start, count) { - const {iScale, vScale} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = new Array(count); - let i, ilen, index; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - parsed[i] = { - [iAxis]: singleScale || iScale.parse(labels[index], index), - [vAxis]: vScale.parse(data[index], index) - }; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const {xScale, yScale} = meta; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(item[0], index), - y: yScale.parse(item[1], index) - }; - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const {xScale, yScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(resolveObjectKey(item, xAxisKey), index), - y: yScale.parse(resolveObjectKey(item, yAxisKey), index) - }; - } - return parsed; - } - getParsed(index) { - return this._cachedMeta._parsed[index]; - } - getDataElement(index) { - return this._cachedMeta.data[index]; - } - applyStack(scale, parsed, mode) { - const chart = this.chart; - const meta = this._cachedMeta; - const value = parsed[scale.axis]; - const stack = { - keys: getSortedDatasetIndices(chart, true), - values: parsed._stacks[scale.axis] - }; - return applyStack(stack, value, meta.index, {mode}); - } - updateRangeFromParsed(range, scale, parsed, stack) { - const parsedValue = parsed[scale.axis]; - let value = parsedValue === null ? NaN : parsedValue; - const values = stack && parsed._stacks[scale.axis]; - if (stack && values) { - stack.values = values; - value = applyStack(stack, parsedValue, this._cachedMeta.index); - } - range.min = Math.min(range.min, value); - range.max = Math.max(range.max, value); - } - getMinMax(scale, canStack) { - const meta = this._cachedMeta; - const _parsed = meta._parsed; - const sorted = meta._sorted && scale === meta.iScale; - const ilen = _parsed.length; - const otherScale = this._getOtherScale(scale); - const stack = createStack(canStack, meta, this.chart); - const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; - const {min: otherMin, max: otherMax} = getUserBounds(otherScale); - let i, parsed; - function _skip() { - parsed = _parsed[i]; - const otherValue = parsed[otherScale.axis]; - return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; - } - for (i = 0; i < ilen; ++i) { - if (_skip()) { - continue; - } - this.updateRangeFromParsed(range, scale, parsed, stack); - if (sorted) { - break; - } - } - if (sorted) { - for (i = ilen - 1; i >= 0; --i) { - if (_skip()) { - continue; + updateIndex(datasetIndex) { + if (this.index !== datasetIndex) { + clearStacks(this._cachedMeta); } - this.updateRangeFromParsed(range, scale, parsed, stack); - break; - } + this.index = datasetIndex; } - return range; - } - getAllParsedValues(scale) { - const parsed = this._cachedMeta._parsed; - const values = []; - let i, ilen, value; - for (i = 0, ilen = parsed.length; i < ilen; ++i) { - value = parsed[i][scale.axis]; - if (isNumberFinite(value)) { - values.push(value); - } + linkScales() { + const chart = this.chart; + const meta = this._cachedMeta; + const dataset = this.getDataset(); + const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y; + const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); + const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); + const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); + const indexAxis = meta.indexAxis; + const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); + const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); + meta.xScale = this.getScaleForId(xid); + meta.yScale = this.getScaleForId(yid); + meta.rScale = this.getScaleForId(rid); + meta.iScale = this.getScaleForId(iid); + meta.vScale = this.getScaleForId(vid); } - return values; - } - getMaxOverflow() { - return false; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const vScale = meta.vScale; - const parsed = this.getParsed(index); - return { - label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', - value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' - }; - } - _update(mode) { - const meta = this._cachedMeta; - this.update(mode || 'default'); - meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); - } - update(mode) {} - draw() { - const ctx = this._ctx; - const chart = this.chart; - const meta = this._cachedMeta; - const elements = meta.data || []; - const area = chart.chartArea; - const active = []; - const start = this._drawStart || 0; - const count = this._drawCount || (elements.length - start); - const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; - let i; - if (meta.dataset) { - meta.dataset.draw(ctx, area, start, count); + getDataset() { + return this.chart.data.datasets[this.index]; } - for (i = start; i < start + count; ++i) { - const element = elements[i]; - if (element.hidden) { - continue; - } - if (element.active && drawActiveElementsOnTop) { - active.push(element); - } else { - element.draw(ctx, area); - } + getMeta() { + return this.chart.getDatasetMeta(this.index); } - for (i = 0; i < active.length; ++i) { - active[i].draw(ctx, area); + getScaleForId(scaleID) { + return this.chart.scales[scaleID]; } - } - getStyle(index, active) { - const mode = active ? 'active' : 'default'; - return index === undefined && this._cachedMeta.dataset - ? this.resolveDatasetElementOptions(mode) - : this.resolveDataElementOptions(index || 0, mode); - } - getContext(index, active, mode) { - const dataset = this.getDataset(); - let context; - if (index >= 0 && index < this._cachedMeta.data.length) { - const element = this._cachedMeta.data[index]; - context = element.$context || - (element.$context = createDataContext(this.getContext(), index, element)); - context.parsed = this.getParsed(index); - context.raw = dataset.data[index]; - context.index = context.dataIndex = index; - } else { - context = this.$context || - (this.$context = createDatasetContext(this.chart.getContext(), this.index)); - context.dataset = dataset; - context.index = context.datasetIndex = this.index; + _getOtherScale(scale) { + const meta = this._cachedMeta; + return scale === meta.iScale ? meta.vScale : meta.iScale; } - context.active = !!active; - context.mode = mode; - return context; - } - resolveDatasetElementOptions(mode) { - return this._resolveElementOptions(this.datasetElementType.id, mode); - } - resolveDataElementOptions(index, mode) { - return this._resolveElementOptions(this.dataElementType.id, mode, index); - } - _resolveElementOptions(elementType, mode = 'default', index) { - const active = mode === 'active'; - const cache = this._cachedDataOpts; - const cacheKey = elementType + '-' + mode; - const cached = cache[cacheKey]; - const sharing = this.enableOptionSharing && defined(index); - if (cached) { - return cloneIfNotShared(cached, sharing); + reset() { + this._update('reset'); } - const config = this.chart.config; - const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); - const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, '']; - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - const names = Object.keys(defaults.elements[elementType]); - const context = () => this.getContext(index, active); - const values = config.resolveNamedOptions(scopes, names, context, prefixes); - if (values.$shared) { - values.$shared = sharing; - cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); - } - return values; - } - _resolveAnimations(index, transition, active) { - const chart = this.chart; - const cache = this._cachedDataOpts; - const cacheKey = `animation-${transition}`; - const cached = cache[cacheKey]; - if (cached) { - return cached; - } - let options; - if (chart.options.animation !== false) { - const config = this.chart.config; - const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - options = config.createResolver(scopes, this.getContext(index, active, transition)); - } - const animations = new Animations(chart, options && options.animations); - if (options && options._cacheable) { - cache[cacheKey] = Object.freeze(animations); - } - return animations; - } - getSharedOptions(options) { - if (!options.$shared) { - return; - } - return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); - } - includeOptions(mode, sharedOptions) { - return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; - } - updateElement(element, index, properties, mode) { - if (isDirectUpdateMode(mode)) { - Object.assign(element, properties); - } else { - this._resolveAnimations(index, mode).update(element, properties); - } - } - updateSharedOptions(sharedOptions, mode, newOptions) { - if (sharedOptions && !isDirectUpdateMode(mode)) { - this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); - } - } - _setStyle(element, index, mode, active) { - element.active = active; - const options = this.getStyle(index, active); - this._resolveAnimations(index, mode, active).update(element, { - options: (!active && this.getSharedOptions(options)) || options - }); - } - removeHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', false); - } - setHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', true); - } - _removeDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', false); - } - } - _setDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', true); - } - } - _resyncElements(resetNewElements) { - const data = this._data; - const elements = this._cachedMeta.data; - for (const [method, arg1, arg2] of this._syncList) { - this[method](arg1, arg2); - } - this._syncList = []; - const numMeta = elements.length; - const numData = data.length; - const count = Math.min(numData, numMeta); - if (count) { - this.parse(0, count); - } - if (numData > numMeta) { - this._insertElements(numMeta, numData - numMeta, resetNewElements); - } else if (numData < numMeta) { - this._removeElements(numData, numMeta - numData); - } - } - _insertElements(start, count, resetNewElements = true) { - const meta = this._cachedMeta; - const data = meta.data; - const end = start + count; - let i; - const move = (arr) => { - arr.length += count; - for (i = arr.length - 1; i >= end; i--) { - arr[i] = arr[i - count]; - } - }; - move(data); - for (i = start; i < end; ++i) { - data[i] = new this.dataElementType(); - } - if (this._parsing) { - move(meta._parsed); - } - this.parse(start, count); - if (resetNewElements) { - this.updateElements(data, start, count, 'reset'); - } - } - updateElements(element, start, count, mode) {} - _removeElements(start, count) { - const meta = this._cachedMeta; - if (this._parsing) { - const removed = meta._parsed.splice(start, count); - if (meta._stacked) { - clearStacks(meta, removed); - } - } - meta.data.splice(start, count); - } - _sync(args) { - if (this._parsing) { - this._syncList.push(args); - } else { - const [method, arg1, arg2] = args; - this[method](arg1, arg2); - } - this.chart._dataChanges.push([this.index, ...args]); - } - _onDataPush() { - const count = arguments.length; - this._sync(['_insertElements', this.getDataset().data.length - count, count]); - } - _onDataPop() { - this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]); - } - _onDataShift() { - this._sync(['_removeElements', 0, 1]); - } - _onDataSplice(start, count) { - if (count) { - this._sync(['_removeElements', start, count]); - } - const newCount = arguments.length - 2; - if (newCount) { - this._sync(['_insertElements', start, newCount]); - } - } - _onDataUnshift() { - this._sync(['_insertElements', 0, arguments.length]); - } -} -DatasetController.defaults = {}; -DatasetController.prototype.datasetElementType = null; -DatasetController.prototype.dataElementType = null; - -class Element { - constructor() { - this.x = undefined; - this.y = undefined; - this.active = false; - this.options = undefined; - this.$animations = undefined; - } - tooltipPosition(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - hasValue() { - return isNumber(this.x) && isNumber(this.y); - } - getProps(props, final) { - const anims = this.$animations; - if (!final || !anims) { - return this; - } - const ret = {}; - props.forEach(prop => { - ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; - }); - return ret; - } -} -Element.defaults = {}; -Element.defaultRoutes = undefined; - -const formatters = { - values(value) { - return isArray(value) ? value : '' + value; - }, - numeric(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const locale = this.chart.options.locale; - let notation; - let delta = tickValue; - if (ticks.length > 1) { - const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); - if (maxTick < 1e-4 || maxTick > 1e+15) { - notation = 'scientific'; - } - delta = calculateDelta(tickValue, ticks); - } - const logDelta = log10(Math.abs(delta)); - const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); - const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; - Object.assign(options, this.options.ticks.format); - return formatNumber(tickValue, locale, options); - }, - logarithmic(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); - if (remain === 1 || remain === 2 || remain === 5) { - return formatters.numeric.call(this, tickValue, index, ticks); - } - return ''; - } -}; -function calculateDelta(tickValue, ticks) { - let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; - if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { - delta = tickValue - Math.floor(tickValue); - } - return delta; -} -var Ticks = {formatters}; - -defaults.set('scale', { - display: true, - offset: false, - reverse: false, - beginAtZero: false, - bounds: 'ticks', - grace: 0, - grid: { - display: true, - lineWidth: 1, - drawBorder: true, - drawOnChartArea: true, - drawTicks: true, - tickLength: 8, - tickWidth: (_ctx, options) => options.lineWidth, - tickColor: (_ctx, options) => options.color, - offset: false, - borderDash: [], - borderDashOffset: 0.0, - borderWidth: 1 - }, - title: { - display: false, - text: '', - padding: { - top: 4, - bottom: 4 - } - }, - ticks: { - minRotation: 0, - maxRotation: 50, - mirror: false, - textStrokeWidth: 0, - textStrokeColor: '', - padding: 3, - display: true, - autoSkip: true, - autoSkipPadding: 3, - labelOffset: 0, - callback: Ticks.formatters.values, - minor: {}, - major: {}, - align: 'center', - crossAlign: 'near', - showLabelBackdrop: false, - backdropColor: 'rgba(255, 255, 255, 0.75)', - backdropPadding: 2, - } -}); -defaults.route('scale.ticks', 'color', '', 'color'); -defaults.route('scale.grid', 'color', '', 'borderColor'); -defaults.route('scale.grid', 'borderColor', '', 'borderColor'); -defaults.route('scale.title', 'color', '', 'color'); -defaults.describe('scale', { - _fallback: false, - _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', - _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash', -}); -defaults.describe('scales', { - _fallback: 'scale', -}); -defaults.describe('scale.ticks', { - _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback', - _indexable: (name) => name !== 'backdropPadding', -}); - -function autoSkip(scale, ticks) { - const tickOpts = scale.options.ticks; - const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale); - const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; - const numMajorIndices = majorIndices.length; - const first = majorIndices[0]; - const last = majorIndices[numMajorIndices - 1]; - const newTicks = []; - if (numMajorIndices > ticksLimit) { - skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); - return newTicks; - } - const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); - if (numMajorIndices > 0) { - let i, ilen; - const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; - skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); - for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { - skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); - } - skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); - return newTicks; - } - skip(ticks, newTicks, spacing); - return newTicks; -} -function determineMaxTicks(scale) { - const offset = scale.options.offset; - const tickLength = scale._tickSize(); - const maxScale = scale._length / tickLength + (offset ? 0 : 1); - const maxChart = scale._maxLength / tickLength; - return Math.floor(Math.min(maxScale, maxChart)); -} -function calculateSpacing(majorIndices, ticks, ticksLimit) { - const evenMajorSpacing = getEvenSpacing(majorIndices); - const spacing = ticks.length / ticksLimit; - if (!evenMajorSpacing) { - return Math.max(spacing, 1); - } - const factors = _factorize(evenMajorSpacing); - for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { - const factor = factors[i]; - if (factor > spacing) { - return factor; - } - } - return Math.max(spacing, 1); -} -function getMajorIndices(ticks) { - const result = []; - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (ticks[i].major) { - result.push(i); - } - } - return result; -} -function skipMajors(ticks, newTicks, majorIndices, spacing) { - let count = 0; - let next = majorIndices[0]; - let i; - spacing = Math.ceil(spacing); - for (i = 0; i < ticks.length; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = majorIndices[count * spacing]; - } - } -} -function skip(ticks, newTicks, spacing, majorStart, majorEnd) { - const start = valueOrDefault(majorStart, 0); - const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); - let count = 0; - let length, i, next; - spacing = Math.ceil(spacing); - if (majorEnd) { - length = majorEnd - majorStart; - spacing = length / Math.floor(length / spacing); - } - next = start; - while (next < 0) { - count++; - next = Math.round(start + count * spacing); - } - for (i = Math.max(start, 0); i < end; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = Math.round(start + count * spacing); - } - } -} -function getEvenSpacing(arr) { - const len = arr.length; - let i, diff; - if (len < 2) { - return false; - } - for (diff = arr[0], i = 1; i < len; ++i) { - if (arr[i] - arr[i - 1] !== diff) { - return false; - } - } - return diff; -} - -const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align; -const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; -function sample(arr, numItems) { - const result = []; - const increment = arr.length / numItems; - const len = arr.length; - let i = 0; - for (; i < len; i += increment) { - result.push(arr[Math.floor(i)]); - } - return result; -} -function getPixelForGridLine(scale, index, offsetGridLines) { - const length = scale.ticks.length; - const validIndex = Math.min(index, length - 1); - const start = scale._startPixel; - const end = scale._endPixel; - const epsilon = 1e-6; - let lineValue = scale.getPixelForTick(validIndex); - let offset; - if (offsetGridLines) { - if (length === 1) { - offset = Math.max(lineValue - start, end - lineValue); - } else if (index === 0) { - offset = (scale.getPixelForTick(1) - lineValue) / 2; - } else { - offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; - } - lineValue += validIndex < index ? offset : -offset; - if (lineValue < start - epsilon || lineValue > end + epsilon) { - return; - } - } - return lineValue; -} -function garbageCollect(caches, length) { - each(caches, (cache) => { - const gc = cache.gc; - const gcLen = gc.length / 2; - let i; - if (gcLen > length) { - for (i = 0; i < gcLen; ++i) { - delete cache.data[gc[i]]; - } - gc.splice(0, gcLen); - } - }); -} -function getTickMarkLength(options) { - return options.drawTicks ? options.tickLength : 0; -} -function getTitleHeight(options, fallback) { - if (!options.display) { - return 0; - } - const font = toFont(options.font, fallback); - const padding = toPadding(options.padding); - const lines = isArray(options.text) ? options.text.length : 1; - return (lines * font.lineHeight) + padding.height; -} -function createScaleContext(parent, scale) { - return createContext(parent, { - scale, - type: 'scale' - }); -} -function createTickContext(parent, index, tick) { - return createContext(parent, { - tick, - index, - type: 'tick' - }); -} -function titleAlign(align, position, reverse) { - let ret = _toLeftRightCenter(align); - if ((reverse && position !== 'right') || (!reverse && position === 'right')) { - ret = reverseAlign(ret); - } - return ret; -} -function titleArgs(scale, offset, position, align) { - const {top, left, bottom, right, chart} = scale; - const {chartArea, scales} = chart; - let rotation = 0; - let maxWidth, titleX, titleY; - const height = bottom - top; - const width = right - left; - if (scale.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; - } else if (position === 'center') { - titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; - } else { - titleY = offsetFromEdge(scale, position, offset); - } - maxWidth = right - left; - } else { - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; - } else if (position === 'center') { - titleX = (chartArea.left + chartArea.right) / 2 - width + offset; - } else { - titleX = offsetFromEdge(scale, position, offset); - } - titleY = _alignStartEnd(align, bottom, top); - rotation = position === 'left' ? -HALF_PI : HALF_PI; - } - return {titleX, titleY, maxWidth, rotation}; -} -class Scale extends Element { - constructor(cfg) { - super(); - this.id = cfg.id; - this.type = cfg.type; - this.options = undefined; - this.ctx = cfg.ctx; - this.chart = cfg.chart; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this._margins = { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - this.maxWidth = undefined; - this.maxHeight = undefined; - this.paddingTop = undefined; - this.paddingBottom = undefined; - this.paddingLeft = undefined; - this.paddingRight = undefined; - this.axis = undefined; - this.labelRotation = undefined; - this.min = undefined; - this.max = undefined; - this._range = undefined; - this.ticks = []; - this._gridLineItems = null; - this._labelItems = null; - this._labelSizes = null; - this._length = 0; - this._maxLength = 0; - this._longestTextCache = {}; - this._startPixel = undefined; - this._endPixel = undefined; - this._reversePixels = false; - this._userMax = undefined; - this._userMin = undefined; - this._suggestedMax = undefined; - this._suggestedMin = undefined; - this._ticksLength = 0; - this._borderValue = 0; - this._cache = {}; - this._dataLimitsCached = false; - this.$context = undefined; - } - init(options) { - this.options = options.setContext(this.getContext()); - this.axis = options.axis; - this._userMin = this.parse(options.min); - this._userMax = this.parse(options.max); - this._suggestedMin = this.parse(options.suggestedMin); - this._suggestedMax = this.parse(options.suggestedMax); - } - parse(raw, index) { - return raw; - } - getUserBounds() { - let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this; - _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); - _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); - _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); - _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); - return { - min: finiteOrDefault(_userMin, _suggestedMin), - max: finiteOrDefault(_userMax, _suggestedMax), - minDefined: isNumberFinite(_userMin), - maxDefined: isNumberFinite(_userMax) - }; - } - getMinMax(canStack) { - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - let range; - if (minDefined && maxDefined) { - return {min, max}; - } - const metas = this.getMatchingVisibleMetas(); - for (let i = 0, ilen = metas.length; i < ilen; ++i) { - range = metas[i].controller.getMinMax(this, canStack); - if (!minDefined) { - min = Math.min(min, range.min); - } - if (!maxDefined) { - max = Math.max(max, range.max); - } - } - min = maxDefined && min > max ? max : min; - max = minDefined && min > max ? min : max; - return { - min: finiteOrDefault(min, finiteOrDefault(max, min)), - max: finiteOrDefault(max, finiteOrDefault(min, max)) - }; - } - getPadding() { - return { - left: this.paddingLeft || 0, - top: this.paddingTop || 0, - right: this.paddingRight || 0, - bottom: this.paddingBottom || 0 - }; - } - getTicks() { - return this.ticks; - } - getLabels() { - const data = this.chart.data; - return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; - } - beforeLayout() { - this._cache = {}; - this._dataLimitsCached = false; - } - beforeUpdate() { - callback(this.options.beforeUpdate, [this]); - } - update(maxWidth, maxHeight, margins) { - const {beginAtZero, grace, ticks: tickOpts} = this.options; - const sampleSize = tickOpts.sampleSize; - this.beforeUpdate(); - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins = Object.assign({ - left: 0, - right: 0, - top: 0, - bottom: 0 - }, margins); - this.ticks = null; - this._labelSizes = null; - this._gridLineItems = null; - this._labelItems = null; - this.beforeSetDimensions(); - this.setDimensions(); - this.afterSetDimensions(); - this._maxLength = this.isHorizontal() - ? this.width + margins.left + margins.right - : this.height + margins.top + margins.bottom; - if (!this._dataLimitsCached) { - this.beforeDataLimits(); - this.determineDataLimits(); - this.afterDataLimits(); - this._range = _addGrace(this, grace, beginAtZero); - this._dataLimitsCached = true; - } - this.beforeBuildTicks(); - this.ticks = this.buildTicks() || []; - this.afterBuildTicks(); - const samplingEnabled = sampleSize < this.ticks.length; - this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); - this.configure(); - this.beforeCalculateLabelRotation(); - this.calculateLabelRotation(); - this.afterCalculateLabelRotation(); - if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { - this.ticks = autoSkip(this, this.ticks); - this._labelSizes = null; - } - if (samplingEnabled) { - this._convertTicksToLabels(this.ticks); - } - this.beforeFit(); - this.fit(); - this.afterFit(); - this.afterUpdate(); - } - configure() { - let reversePixels = this.options.reverse; - let startPixel, endPixel; - if (this.isHorizontal()) { - startPixel = this.left; - endPixel = this.right; - } else { - startPixel = this.top; - endPixel = this.bottom; - reversePixels = !reversePixels; - } - this._startPixel = startPixel; - this._endPixel = endPixel; - this._reversePixels = reversePixels; - this._length = endPixel - startPixel; - this._alignToPixels = this.options.alignToPixels; - } - afterUpdate() { - callback(this.options.afterUpdate, [this]); - } - beforeSetDimensions() { - callback(this.options.beforeSetDimensions, [this]); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = 0; - this.right = this.width; - } else { - this.height = this.maxHeight; - this.top = 0; - this.bottom = this.height; - } - this.paddingLeft = 0; - this.paddingTop = 0; - this.paddingRight = 0; - this.paddingBottom = 0; - } - afterSetDimensions() { - callback(this.options.afterSetDimensions, [this]); - } - _callHooks(name) { - this.chart.notifyPlugins(name, this.getContext()); - callback(this.options[name], [this]); - } - beforeDataLimits() { - this._callHooks('beforeDataLimits'); - } - determineDataLimits() {} - afterDataLimits() { - this._callHooks('afterDataLimits'); - } - beforeBuildTicks() { - this._callHooks('beforeBuildTicks'); - } - buildTicks() { - return []; - } - afterBuildTicks() { - this._callHooks('afterBuildTicks'); - } - beforeTickToLabelConversion() { - callback(this.options.beforeTickToLabelConversion, [this]); - } - generateTickLabels(ticks) { - const tickOpts = this.options.ticks; - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - tick = ticks[i]; - tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this); - } - } - afterTickToLabelConversion() { - callback(this.options.afterTickToLabelConversion, [this]); - } - beforeCalculateLabelRotation() { - callback(this.options.beforeCalculateLabelRotation, [this]); - } - calculateLabelRotation() { - const options = this.options; - const tickOpts = options.ticks; - const numTicks = this.ticks.length; - const minRotation = tickOpts.minRotation || 0; - const maxRotation = tickOpts.maxRotation; - let labelRotation = minRotation; - let tickWidth, maxHeight, maxLabelDiagonal; - if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { - this.labelRotation = minRotation; - return; - } - const labelSizes = this._getLabelSizes(); - const maxLabelWidth = labelSizes.widest.width; - const maxLabelHeight = labelSizes.highest.height; - const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); - tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); - if (maxLabelWidth + 6 > tickWidth) { - tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); - maxHeight = this.maxHeight - getTickMarkLength(options.grid) - - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); - maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); - labelRotation = toDegrees(Math.min( - Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), - Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)) - )); - labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); - } - this.labelRotation = labelRotation; - } - afterCalculateLabelRotation() { - callback(this.options.afterCalculateLabelRotation, [this]); - } - beforeFit() { - callback(this.options.beforeFit, [this]); - } - fit() { - const minSize = { - width: 0, - height: 0 - }; - const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this; - const display = this._isVisible(); - const isHorizontal = this.isHorizontal(); - if (display) { - const titleHeight = getTitleHeight(titleOpts, chart.options.font); - if (isHorizontal) { - minSize.width = this.maxWidth; - minSize.height = getTickMarkLength(gridOpts) + titleHeight; - } else { - minSize.height = this.maxHeight; - minSize.width = getTickMarkLength(gridOpts) + titleHeight; - } - if (tickOpts.display && this.ticks.length) { - const {first, last, widest, highest} = this._getLabelSizes(); - const tickPadding = tickOpts.padding * 2; - const angleRadians = toRadians(this.labelRotation); - const cos = Math.cos(angleRadians); - const sin = Math.sin(angleRadians); - if (isHorizontal) { - const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; - minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); - } else { - const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; - minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); + _destroy() { + const meta = this._cachedMeta; + if (this._data) { + unlistenArrayEvents(this._data, this); } - this._calculatePadding(first, last, sin, cos); - } - } - this._handleMargins(); - if (isHorizontal) { - this.width = this._length = chart.width - this._margins.left - this._margins.right; - this.height = minSize.height; - } else { - this.width = minSize.width; - this.height = this._length = chart.height - this._margins.top - this._margins.bottom; - } - } - _calculatePadding(first, last, sin, cos) { - const {ticks: {align, padding}, position} = this.options; - const isRotated = this.labelRotation !== 0; - const labelsBelowTicks = position !== 'top' && this.axis === 'x'; - if (this.isHorizontal()) { - const offsetLeft = this.getPixelForTick(0) - this.left; - const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); - let paddingLeft = 0; - let paddingRight = 0; - if (isRotated) { - if (labelsBelowTicks) { - paddingLeft = cos * first.width; - paddingRight = sin * last.height; - } else { - paddingLeft = sin * first.height; - paddingRight = cos * last.width; + if (meta._stacked) { + clearStacks(meta); } - } else if (align === 'start') { - paddingRight = last.width; - } else if (align === 'end') { - paddingLeft = first.width; - } else { - paddingLeft = first.width / 2; - paddingRight = last.width / 2; - } - this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); - this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); - } else { - let paddingTop = last.height / 2; - let paddingBottom = first.height / 2; - if (align === 'start') { - paddingTop = 0; - paddingBottom = first.height; - } else if (align === 'end') { - paddingTop = last.height; - paddingBottom = 0; - } - this.paddingTop = paddingTop + padding; - this.paddingBottom = paddingBottom + padding; } - } - _handleMargins() { - if (this._margins) { - this._margins.left = Math.max(this.paddingLeft, this._margins.left); - this._margins.top = Math.max(this.paddingTop, this._margins.top); - this._margins.right = Math.max(this.paddingRight, this._margins.right); - this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); - } - } - afterFit() { - callback(this.options.afterFit, [this]); - } - isHorizontal() { - const {axis, position} = this.options; - return position === 'top' || position === 'bottom' || axis === 'x'; - } - isFullSize() { - return this.options.fullSize; - } - _convertTicksToLabels(ticks) { - this.beforeTickToLabelConversion(); - this.generateTickLabels(ticks); - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (isNullOrUndef(ticks[i].label)) { - ticks.splice(i, 1); - ilen--; - i--; - } - } - this.afterTickToLabelConversion(); - } - _getLabelSizes() { - let labelSizes = this._labelSizes; - if (!labelSizes) { - const sampleSize = this.options.ticks.sampleSize; - let ticks = this.ticks; - if (sampleSize < ticks.length) { - ticks = sample(ticks, sampleSize); - } - this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length); - } - return labelSizes; - } - _computeLabelSizes(ticks, length) { - const {ctx, _longestTextCache: caches} = this; - const widths = []; - const heights = []; - let widestLabelSize = 0; - let highestLabelSize = 0; - let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; - for (i = 0; i < length; ++i) { - label = ticks[i].label; - tickFont = this._resolveTickFontOptions(i); - ctx.font = fontString = tickFont.string; - cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; - lineHeight = tickFont.lineHeight; - width = height = 0; - if (!isNullOrUndef(label) && !isArray(label)) { - width = _measureText(ctx, cache.data, cache.gc, width, label); - height = lineHeight; - } else if (isArray(label)) { - for (j = 0, jlen = label.length; j < jlen; ++j) { - nestedLabel = label[j]; - if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { - width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); - height += lineHeight; - } - } - } - widths.push(width); - heights.push(height); - widestLabelSize = Math.max(width, widestLabelSize); - highestLabelSize = Math.max(height, highestLabelSize); - } - garbageCollect(caches, length); - const widest = widths.indexOf(widestLabelSize); - const highest = heights.indexOf(highestLabelSize); - const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0}); - return { - first: valueAt(0), - last: valueAt(length - 1), - widest: valueAt(widest), - highest: valueAt(highest), - widths, - heights, - }; - } - getLabelForValue(value) { - return value; - } - getPixelForValue(value, index) { - return NaN; - } - getValueForPixel(pixel) {} - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getPixelForDecimal(decimal) { - if (this._reversePixels) { - decimal = 1 - decimal; - } - const pixel = this._startPixel + decimal * this._length; - return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); - } - getDecimalForPixel(pixel) { - const decimal = (pixel - this._startPixel) / this._length; - return this._reversePixels ? 1 - decimal : decimal; - } - getBasePixel() { - return this.getPixelForValue(this.getBaseValue()); - } - getBaseValue() { - const {min, max} = this; - return min < 0 && max < 0 ? max : - min > 0 && max > 0 ? min : - 0; - } - getContext(index) { - const ticks = this.ticks || []; - if (index >= 0 && index < ticks.length) { - const tick = ticks[index]; - return tick.$context || - (tick.$context = createTickContext(this.getContext(), index, tick)); - } - return this.$context || - (this.$context = createScaleContext(this.chart.getContext(), this)); - } - _tickSize() { - const optionTicks = this.options.ticks; - const rot = toRadians(this.labelRotation); - const cos = Math.abs(Math.cos(rot)); - const sin = Math.abs(Math.sin(rot)); - const labelSizes = this._getLabelSizes(); - const padding = optionTicks.autoSkipPadding || 0; - const w = labelSizes ? labelSizes.widest.width + padding : 0; - const h = labelSizes ? labelSizes.highest.height + padding : 0; - return this.isHorizontal() - ? h * cos > w * sin ? w / cos : h / sin - : h * sin < w * cos ? h / cos : w / sin; - } - _isVisible() { - const display = this.options.display; - if (display !== 'auto') { - return !!display; - } - return this.getMatchingVisibleMetas().length > 0; - } - _computeGridLineItems(chartArea) { - const axis = this.axis; - const chart = this.chart; - const options = this.options; - const {grid, position} = options; - const offset = grid.offset; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const ticksLength = ticks.length + (offset ? 1 : 0); - const tl = getTickMarkLength(grid); - const items = []; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0; - const axisHalfWidth = axisWidth / 2; - const alignBorderValue = function(pixel) { - return _alignPixel(chart, pixel, axisWidth); - }; - let borderValue, i, lineValue, alignedLineValue; - let tx1, ty1, tx2, ty2, x1, y1, x2, y2; - if (position === 'top') { - borderValue = alignBorderValue(this.bottom); - ty1 = this.bottom - tl; - ty2 = borderValue - axisHalfWidth; - y1 = alignBorderValue(chartArea.top) + axisHalfWidth; - y2 = chartArea.bottom; - } else if (position === 'bottom') { - borderValue = alignBorderValue(this.top); - y1 = chartArea.top; - y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; - ty1 = borderValue + axisHalfWidth; - ty2 = this.top + tl; - } else if (position === 'left') { - borderValue = alignBorderValue(this.right); - tx1 = this.right - tl; - tx2 = borderValue - axisHalfWidth; - x1 = alignBorderValue(chartArea.left) + axisHalfWidth; - x2 = chartArea.right; - } else if (position === 'right') { - borderValue = alignBorderValue(this.left); - x1 = chartArea.left; - x2 = alignBorderValue(chartArea.right) - axisHalfWidth; - tx1 = borderValue + axisHalfWidth; - tx2 = this.left + tl; - } else if (axis === 'x') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - y1 = chartArea.top; - y2 = chartArea.bottom; - ty1 = borderValue + axisHalfWidth; - ty2 = ty1 + tl; - } else if (axis === 'y') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - tx1 = borderValue - axisHalfWidth; - tx2 = tx1 - tl; - x1 = chartArea.left; - x2 = chartArea.right; - } - const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); - const step = Math.max(1, Math.ceil(ticksLength / limit)); - for (i = 0; i < ticksLength; i += step) { - const optsAtIndex = grid.setContext(this.getContext(i)); - const lineWidth = optsAtIndex.lineWidth; - const lineColor = optsAtIndex.color; - const borderDash = grid.borderDash || []; - const borderDashOffset = optsAtIndex.borderDashOffset; - const tickWidth = optsAtIndex.tickWidth; - const tickColor = optsAtIndex.tickColor; - const tickBorderDash = optsAtIndex.tickBorderDash || []; - const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; - lineValue = getPixelForGridLine(this, i, offset); - if (lineValue === undefined) { - continue; - } - alignedLineValue = _alignPixel(chart, lineValue, lineWidth); - if (isHorizontal) { - tx1 = tx2 = x1 = x2 = alignedLineValue; - } else { - ty1 = ty2 = y1 = y2 = alignedLineValue; - } - items.push({ - tx1, - ty1, - tx2, - ty2, - x1, - y1, - x2, - y2, - width: lineWidth, - color: lineColor, - borderDash, - borderDashOffset, - tickWidth, - tickColor, - tickBorderDash, - tickBorderDashOffset, - }); - } - this._ticksLength = ticksLength; - this._borderValue = borderValue; - return items; - } - _computeLabelItems(chartArea) { - const axis = this.axis; - const options = this.options; - const {position, ticks: optionTicks} = options; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const {align, crossAlign, padding, mirror} = optionTicks; - const tl = getTickMarkLength(options.grid); - const tickAndPadding = tl + padding; - const hTickAndPadding = mirror ? -padding : tickAndPadding; - const rotation = -toRadians(this.labelRotation); - const items = []; - let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; - let textBaseline = 'middle'; - if (position === 'top') { - y = this.bottom - hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'bottom') { - y = this.top + hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'left') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (position === 'right') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (axis === 'x') { - if (position === 'center') { - y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; - } - textAlign = this._getXAxisLabelAlignment(); - } else if (axis === 'y') { - if (position === 'center') { - x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - x = this.chart.scales[positionAxisID].getPixelForValue(value); - } - textAlign = this._getYAxisLabelAlignment(tl).textAlign; - } - if (axis === 'y') { - if (align === 'start') { - textBaseline = 'top'; - } else if (align === 'end') { - textBaseline = 'bottom'; - } - } - const labelSizes = this._getLabelSizes(); - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - label = tick.label; - const optsAtIndex = optionTicks.setContext(this.getContext(i)); - pixel = this.getPixelForTick(i) + optionTicks.labelOffset; - font = this._resolveTickFontOptions(i); - lineHeight = font.lineHeight; - lineCount = isArray(label) ? label.length : 1; - const halfCount = lineCount / 2; - const color = optsAtIndex.color; - const strokeColor = optsAtIndex.textStrokeColor; - const strokeWidth = optsAtIndex.textStrokeWidth; - if (isHorizontal) { - x = pixel; - if (position === 'top') { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = -lineCount * lineHeight + lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; - } else { - textOffset = -labelSizes.highest.height + lineHeight / 2; - } - } else { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; - } else { - textOffset = labelSizes.highest.height - lineCount * lineHeight; - } - } - if (mirror) { - textOffset *= -1; - } - } else { - y = pixel; - textOffset = (1 - lineCount) * lineHeight / 2; - } - let backdrop; - if (optsAtIndex.showLabelBackdrop) { - const labelPadding = toPadding(optsAtIndex.backdropPadding); - const height = labelSizes.heights[i]; - const width = labelSizes.widths[i]; - let top = y + textOffset - labelPadding.top; - let left = x - labelPadding.left; - switch (textBaseline) { - case 'middle': - top -= height / 2; - break; - case 'bottom': - top -= height; - break; - } - switch (textAlign) { - case 'center': - left -= width / 2; - break; - case 'right': - left -= width; - break; - } - backdrop = { - left, - top, - width: width + labelPadding.width, - height: height + labelPadding.height, - color: optsAtIndex.backdropColor, - }; - } - items.push({ - rotation, - label, - font, - color, - strokeColor, - strokeWidth, - textOffset, - textAlign, - textBaseline, - translation: [x, y], - backdrop, - }); - } - return items; - } - _getXAxisLabelAlignment() { - const {position, ticks} = this.options; - const rotation = -toRadians(this.labelRotation); - if (rotation) { - return position === 'top' ? 'left' : 'right'; - } - let align = 'center'; - if (ticks.align === 'start') { - align = 'left'; - } else if (ticks.align === 'end') { - align = 'right'; - } - return align; - } - _getYAxisLabelAlignment(tl) { - const {position, ticks: {crossAlign, mirror, padding}} = this.options; - const labelSizes = this._getLabelSizes(); - const tickAndPadding = tl + padding; - const widest = labelSizes.widest.width; - let textAlign; - let x; - if (position === 'left') { - if (mirror) { - x = this.right + padding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += (widest / 2); - } else { - textAlign = 'right'; - x += widest; - } - } else { - x = this.right - tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x = this.left; - } - } - } else if (position === 'right') { - if (mirror) { - x = this.left + padding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x -= widest; - } - } else { - x = this.left + tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += widest / 2; - } else { - textAlign = 'right'; - x = this.right; - } - } - } else { - textAlign = 'right'; - } - return {textAlign, x}; - } - _computeLabelArea() { - if (this.options.ticks.mirror) { - return; - } - const chart = this.chart; - const position = this.options.position; - if (position === 'left' || position === 'right') { - return {top: 0, left: this.left, bottom: chart.height, right: this.right}; - } if (position === 'top' || position === 'bottom') { - return {top: this.top, left: 0, bottom: this.bottom, right: chart.width}; - } - } - drawBackground() { - const {ctx, options: {backgroundColor}, left, top, width, height} = this; - if (backgroundColor) { - ctx.save(); - ctx.fillStyle = backgroundColor; - ctx.fillRect(left, top, width, height); - ctx.restore(); - } - } - getLineWidthForValue(value) { - const grid = this.options.grid; - if (!this._isVisible() || !grid.display) { - return 0; - } - const ticks = this.ticks; - const index = ticks.findIndex(t => t.value === value); - if (index >= 0) { - const opts = grid.setContext(this.getContext(index)); - return opts.lineWidth; - } - return 0; - } - drawGrid(chartArea) { - const grid = this.options.grid; - const ctx = this.ctx; - const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); - let i, ilen; - const drawLine = (p1, p2, style) => { - if (!style.width || !style.color) { - return; - } - ctx.save(); - ctx.lineWidth = style.width; - ctx.strokeStyle = style.color; - ctx.setLineDash(style.borderDash || []); - ctx.lineDashOffset = style.borderDashOffset; - ctx.beginPath(); - ctx.moveTo(p1.x, p1.y); - ctx.lineTo(p2.x, p2.y); - ctx.stroke(); - ctx.restore(); - }; - if (grid.display) { - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - if (grid.drawOnChartArea) { - drawLine( - {x: item.x1, y: item.y1}, - {x: item.x2, y: item.y2}, - item - ); - } - if (grid.drawTicks) { - drawLine( - {x: item.tx1, y: item.ty1}, - {x: item.tx2, y: item.ty2}, - { - color: item.tickColor, - width: item.tickWidth, - borderDash: item.tickBorderDash, - borderDashOffset: item.tickBorderDashOffset + _dataCheck() { + const dataset = this.getDataset(); + const data = dataset.data || (dataset.data = []); + const _data = this._data; + if (isObject(data)) { + this._data = convertObjectDataToArray(data); + } else if (_data !== data) { + if (_data) { + unlistenArrayEvents(_data, this); + const meta = this._cachedMeta; + clearStacks(meta); + meta._parsed = []; } - ); + if (data && Object.isExtensible(data)) { + listenArrayEvents(data, this); + } + this._syncList = []; + this._data = data; } - } } - } - drawBorder() { - const {chart, ctx, options: {grid}} = this; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0; - if (!axisWidth) { - return; - } - const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; - const borderValue = this._borderValue; - let x1, x2, y1, y2; - if (this.isHorizontal()) { - x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; - x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; - y1 = y2 = borderValue; - } else { - y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; - y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; - x1 = x2 = borderValue; - } - ctx.save(); - ctx.lineWidth = borderOpts.borderWidth; - ctx.strokeStyle = borderOpts.borderColor; - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); - ctx.restore(); - } - drawLabels(chartArea) { - const optionTicks = this.options.ticks; - if (!optionTicks.display) { - return; - } - const ctx = this.ctx; - const area = this._computeLabelArea(); - if (area) { - clipArea(ctx, area); - } - const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - const tickFont = item.font; - const label = item.label; - if (item.backdrop) { - ctx.fillStyle = item.backdrop.color; - ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); - } - let y = item.textOffset; - renderText(ctx, label, 0, y, tickFont, item); - } - if (area) { - unclipArea(ctx); - } - } - drawTitle() { - const {ctx, options: {position, title, reverse}} = this; - if (!title.display) { - return; - } - const font = toFont(title.font); - const padding = toPadding(title.padding); - const align = title.align; - let offset = font.lineHeight / 2; - if (position === 'bottom' || position === 'center' || isObject(position)) { - offset += padding.bottom; - if (isArray(title.text)) { - offset += font.lineHeight * (title.text.length - 1); - } - } else { - offset += padding.top; - } - const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align); - renderText(ctx, title.text, 0, 0, font, { - color: title.color, - maxWidth, - rotation, - textAlign: titleAlign(align, position, reverse), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } - draw(chartArea) { - if (!this._isVisible()) { - return; - } - this.drawBackground(); - this.drawGrid(chartArea); - this.drawBorder(); - this.drawTitle(); - this.drawLabels(chartArea); - } - _layers() { - const opts = this.options; - const tz = opts.ticks && opts.ticks.z || 0; - const gz = valueOrDefault(opts.grid && opts.grid.z, -1); - if (!this._isVisible() || this.draw !== Scale.prototype.draw) { - return [{ - z: tz, - draw: (chartArea) => { - this.draw(chartArea); + addElements() { + const meta = this._cachedMeta; + this._dataCheck(); + if (this.datasetElementType) { + meta.dataset = new this.datasetElementType(); } - }]; } - return [{ - z: gz, - draw: (chartArea) => { - this.drawBackground(); - this.drawGrid(chartArea); - this.drawTitle(); - } - }, { - z: gz + 1, - draw: () => { - this.drawBorder(); - } - }, { - z: tz, - draw: (chartArea) => { - this.drawLabels(chartArea); - } - }]; - } - getMatchingVisibleMetas(type) { - const metas = this.chart.getSortedVisibleDatasetMetas(); - const axisID = this.axis + 'AxisID'; - const result = []; - let i, ilen; - for (i = 0, ilen = metas.length; i < ilen; ++i) { - const meta = metas[i]; - if (meta[axisID] === this.id && (!type || meta.type === type)) { - result.push(meta); - } + buildOrUpdateElements(resetNewElements) { + const meta = this._cachedMeta; + const dataset = this.getDataset(); + let stackChanged = false; + this._dataCheck(); + const oldStacked = meta._stacked; + meta._stacked = isStacked(meta.vScale, meta); + if (meta.stack !== dataset.stack) { + stackChanged = true; + clearStacks(meta); + meta.stack = dataset.stack; + } + this._resyncElements(resetNewElements); + if (stackChanged || oldStacked !== meta._stacked) { + updateStacks(this, meta._parsed); + } } - return result; - } - _resolveTickFontOptions(index) { - const opts = this.options.ticks.setContext(this.getContext(index)); - return toFont(opts.font); - } - _maxDigits() { - const fontSize = this._resolveTickFontOptions(0).lineHeight; - return (this.isHorizontal() ? this.width : this.height) / fontSize; - } -} - -class TypedRegistry { - constructor(type, scope, override) { - this.type = type; - this.scope = scope; - this.override = override; - this.items = Object.create(null); - } - isForType(type) { - return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); - } - register(item) { - const proto = Object.getPrototypeOf(item); - let parentScope; - if (isIChartComponent(proto)) { - parentScope = this.register(proto); + configure() { + const config = this.chart.config; + const scopeKeys = config.datasetScopeKeys(this._type); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); + this.options = config.createResolver(scopes, this.getContext()); + this._parsing = this.options.parsing; + this._cachedDataOpts = {}; } - const items = this.items; - const id = item.id; - const scope = this.scope + '.' + id; - if (!id) { - throw new Error('class does not have id: ' + item); + parse(start, count) { + const { _cachedMeta: meta , _data: data } = this; + const { iScale , _stacked } = meta; + const iAxis = iScale.axis; + let sorted = start === 0 && count === data.length ? true : meta._sorted; + let prev = start > 0 && meta._parsed[start - 1]; + let i, cur, parsed; + if (this._parsing === false) { + meta._parsed = data; + meta._sorted = true; + parsed = data; + } else { + if (isArray(data[start])) { + parsed = this.parseArrayData(meta, data, start, count); + } else if (isObject(data[start])) { + parsed = this.parseObjectData(meta, data, start, count); + } else { + parsed = this.parsePrimitiveData(meta, data, start, count); + } + const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis]; + for(i = 0; i < count; ++i){ + meta._parsed[i + start] = cur = parsed[i]; + if (sorted) { + if (isNotInOrderComparedToPrev()) { + sorted = false; + } + prev = cur; + } + } + meta._sorted = sorted; + } + if (_stacked) { + updateStacks(this, parsed); + } } - if (id in items) { - return scope; + parsePrimitiveData(meta, data, start, count) { + const { iScale , vScale } = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = new Array(count); + let i, ilen, index; + for(i = 0, ilen = count; i < ilen; ++i){ + index = i + start; + parsed[i] = { + [iAxis]: singleScale || iScale.parse(labels[index], index), + [vAxis]: vScale.parse(data[index], index) + }; + } + return parsed; } - items[id] = item; - registerDefaults(item, scope, parentScope); - if (this.override) { - defaults.override(item.id, item.overrides); + parseArrayData(meta, data, start, count) { + const { xScale , yScale } = meta; + const parsed = new Array(count); + let i, ilen, index, item; + for(i = 0, ilen = count; i < ilen; ++i){ + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(item[0], index), + y: yScale.parse(item[1], index) + }; + } + return parsed; } - return scope; - } - get(id) { - return this.items[id]; - } - unregister(item) { - const items = this.items; - const id = item.id; - const scope = this.scope; - if (id in items) { - delete items[id]; + parseObjectData(meta, data, start, count) { + const { xScale , yScale } = meta; + const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; + const parsed = new Array(count); + let i, ilen, index, item; + for(i = 0, ilen = count; i < ilen; ++i){ + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(resolveObjectKey(item, xAxisKey), index), + y: yScale.parse(resolveObjectKey(item, yAxisKey), index) + }; + } + return parsed; } - if (scope && id in defaults[scope]) { - delete defaults[scope][id]; - if (this.override) { - delete overrides[id]; - } + getParsed(index) { + return this._cachedMeta._parsed[index]; } - } -} -function registerDefaults(item, scope, parentScope) { - const itemDefaults = merge(Object.create(null), [ - parentScope ? defaults.get(parentScope) : {}, - defaults.get(scope), - item.defaults - ]); - defaults.set(scope, itemDefaults); - if (item.defaultRoutes) { - routeDefaults(scope, item.defaultRoutes); - } - if (item.descriptors) { - defaults.describe(scope, item.descriptors); - } -} -function routeDefaults(scope, routes) { - Object.keys(routes).forEach(property => { - const propertyParts = property.split('.'); - const sourceName = propertyParts.pop(); - const sourceScope = [scope].concat(propertyParts).join('.'); - const parts = routes[property].split('.'); - const targetName = parts.pop(); - const targetScope = parts.join('.'); - defaults.route(sourceScope, sourceName, targetScope, targetName); - }); -} -function isIChartComponent(proto) { - return 'id' in proto && 'defaults' in proto; -} - -class Registry { - constructor() { - this.controllers = new TypedRegistry(DatasetController, 'datasets', true); - this.elements = new TypedRegistry(Element, 'elements'); - this.plugins = new TypedRegistry(Object, 'plugins'); - this.scales = new TypedRegistry(Scale, 'scales'); - this._typedRegistries = [this.controllers, this.scales, this.elements]; - } - add(...args) { - this._each('register', args); - } - remove(...args) { - this._each('unregister', args); - } - addControllers(...args) { - this._each('register', args, this.controllers); - } - addElements(...args) { - this._each('register', args, this.elements); - } - addPlugins(...args) { - this._each('register', args, this.plugins); - } - addScales(...args) { - this._each('register', args, this.scales); - } - getController(id) { - return this._get(id, this.controllers, 'controller'); - } - getElement(id) { - return this._get(id, this.elements, 'element'); - } - getPlugin(id) { - return this._get(id, this.plugins, 'plugin'); - } - getScale(id) { - return this._get(id, this.scales, 'scale'); - } - removeControllers(...args) { - this._each('unregister', args, this.controllers); - } - removeElements(...args) { - this._each('unregister', args, this.elements); - } - removePlugins(...args) { - this._each('unregister', args, this.plugins); - } - removeScales(...args) { - this._each('unregister', args, this.scales); - } - _each(method, args, typedRegistry) { - [...args].forEach(arg => { - const reg = typedRegistry || this._getRegistryForType(arg); - if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) { - this._exec(method, reg, arg); - } else { - each(arg, item => { - const itemReg = typedRegistry || this._getRegistryForType(item); - this._exec(method, itemReg, item); + getDataElement(index) { + return this._cachedMeta.data[index]; + } + applyStack(scale, parsed, mode) { + const chart = this.chart; + const meta = this._cachedMeta; + const value = parsed[scale.axis]; + const stack = { + keys: getSortedDatasetIndices(chart, true), + values: parsed._stacks[scale.axis]._visualValues + }; + return applyStack(stack, value, meta.index, { + mode }); - } - }); - } - _exec(method, registry, component) { - const camelMethod = _capitalize(method); - callback(component['before' + camelMethod], [], component); - registry[method](component); - callback(component['after' + camelMethod], [], component); - } - _getRegistryForType(type) { - for (let i = 0; i < this._typedRegistries.length; i++) { - const reg = this._typedRegistries[i]; - if (reg.isForType(type)) { - return reg; - } } - return this.plugins; - } - _get(id, typedRegistry, type) { - const item = typedRegistry.get(id); - if (item === undefined) { - throw new Error('"' + id + '" is not a registered ' + type + '.'); + updateRangeFromParsed(range, scale, parsed, stack) { + const parsedValue = parsed[scale.axis]; + let value = parsedValue === null ? NaN : parsedValue; + const values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + value = applyStack(stack, parsedValue, this._cachedMeta.index); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); } - return item; - } -} -var registry = new Registry(); - -class PluginService { - constructor() { - this._init = []; - } - notify(chart, hook, args, filter) { - if (hook === 'beforeInit') { - this._init = this._createDescriptors(chart, true); - this._notify(this._init, chart, 'install'); + getMinMax(scale, canStack) { + const meta = this._cachedMeta; + const _parsed = meta._parsed; + const sorted = meta._sorted && scale === meta.iScale; + const ilen = _parsed.length; + const otherScale = this._getOtherScale(scale); + const stack = createStack(canStack, meta, this.chart); + const range = { + min: Number.POSITIVE_INFINITY, + max: Number.NEGATIVE_INFINITY + }; + const { min: otherMin , max: otherMax } = getUserBounds(otherScale); + let i, parsed; + function _skip() { + parsed = _parsed[i]; + const otherValue = parsed[otherScale.axis]; + return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; + } + for(i = 0; i < ilen; ++i){ + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + if (sorted) { + break; + } + } + if (sorted) { + for(i = ilen - 1; i >= 0; --i){ + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + break; + } + } + return range; } - const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); - const result = this._notify(descriptors, chart, hook, args); - if (hook === 'afterDestroy') { - this._notify(descriptors, chart, 'stop'); - this._notify(this._init, chart, 'uninstall'); + getAllParsedValues(scale) { + const parsed = this._cachedMeta._parsed; + const values = []; + let i, ilen, value; + for(i = 0, ilen = parsed.length; i < ilen; ++i){ + value = parsed[i][scale.axis]; + if (isNumberFinite(value)) { + values.push(value); + } + } + return values; } - return result; - } - _notify(descriptors, chart, hook, args) { - args = args || {}; - for (const descriptor of descriptors) { - const plugin = descriptor.plugin; - const method = plugin[hook]; - const params = [chart, args, descriptor.options]; - if (callback(method, params, plugin) === false && args.cancelable) { + getMaxOverflow() { return false; - } } - return true; - } - invalidate() { - if (!isNullOrUndef(this._cache)) { - this._oldCache = this._cache; - this._cache = undefined; + getLabelAndValue(index) { + const meta = this._cachedMeta; + const iScale = meta.iScale; + const vScale = meta.vScale; + const parsed = this.getParsed(index); + return { + label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', + value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' + }; } - } - _descriptors(chart) { - if (this._cache) { - return this._cache; + _update(mode) { + const meta = this._cachedMeta; + this.update(mode || 'default'); + meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); } - const descriptors = this._cache = this._createDescriptors(chart); - this._notifyStateChanges(chart); - return descriptors; - } - _createDescriptors(chart, all) { - const config = chart && chart.config; - const options = valueOrDefault(config.options && config.options.plugins, {}); - const plugins = allPlugins(config); - return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); - } - _notifyStateChanges(chart) { - const previousDescriptors = this._oldCache || []; - const descriptors = this._cache; - const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id)); - this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); - this._notify(diff(descriptors, previousDescriptors), chart, 'start'); - } -} -function allPlugins(config) { - const plugins = []; - const keys = Object.keys(registry.plugins.items); - for (let i = 0; i < keys.length; i++) { - plugins.push(registry.getPlugin(keys[i])); - } - const local = config.plugins || []; - for (let i = 0; i < local.length; i++) { - const plugin = local[i]; - if (plugins.indexOf(plugin) === -1) { - plugins.push(plugin); + update(mode) {} + draw() { + const ctx = this._ctx; + const chart = this.chart; + const meta = this._cachedMeta; + const elements = meta.data || []; + const area = chart.chartArea; + const active = []; + const start = this._drawStart || 0; + const count = this._drawCount || elements.length - start; + const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; + let i; + if (meta.dataset) { + meta.dataset.draw(ctx, area, start, count); + } + for(i = start; i < start + count; ++i){ + const element = elements[i]; + if (element.hidden) { + continue; + } + if (element.active && drawActiveElementsOnTop) { + active.push(element); + } else { + element.draw(ctx, area); + } + } + for(i = 0; i < active.length; ++i){ + active[i].draw(ctx, area); + } } - } - return plugins; -} -function getOpts(options, all) { - if (!all && options === false) { - return null; - } - if (options === true) { - return {}; - } - return options; -} -function createDescriptors(chart, plugins, options, all) { - const result = []; - const context = chart.getContext(); - for (let i = 0; i < plugins.length; i++) { - const plugin = plugins[i]; - const id = plugin.id; - const opts = getOpts(options[id], all); - if (opts === null) { - continue; + getStyle(index, active) { + const mode = active ? 'active' : 'default'; + return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode); } - result.push({ - plugin, - options: pluginOpts(chart.config, plugin, opts, context) - }); - } - return result; -} -function pluginOpts(config, plugin, opts, context) { - const keys = config.pluginScopeKeys(plugin); - const scopes = config.getOptionScopes(opts, keys); - return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true}); -} - -function getIndexAxis(type, options) { - const datasetDefaults = defaults.datasets[type] || {}; - const datasetOptions = (options.datasets || {})[type] || {}; - return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; -} -function getAxisFromDefaultScaleID(id, indexAxis) { - let axis = id; - if (id === '_index_') { - axis = indexAxis; - } else if (id === '_value_') { - axis = indexAxis === 'x' ? 'y' : 'x'; - } - return axis; -} -function getDefaultScaleIDFromAxis(axis, indexAxis) { - return axis === indexAxis ? '_index_' : '_value_'; -} -function axisFromPosition(position) { - if (position === 'top' || position === 'bottom') { - return 'x'; - } - if (position === 'left' || position === 'right') { - return 'y'; - } -} -function determineAxis(id, scaleOptions) { - if (id === 'x' || id === 'y') { - return id; - } - return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); -} -function mergeScaleConfig(config, options) { - const chartDefaults = overrides[config.type] || {scales: {}}; - const configScales = options.scales || {}; - const chartIndexAxis = getIndexAxis(config.type, options); - const firstIDs = Object.create(null); - const scales = Object.create(null); - Object.keys(configScales).forEach(id => { - const scaleConf = configScales[id]; - if (!isObject(scaleConf)) { - return console.error(`Invalid scale configuration for scale: ${id}`); + getContext(index, active, mode) { + const dataset = this.getDataset(); + let context; + if (index >= 0 && index < this._cachedMeta.data.length) { + const element = this._cachedMeta.data[index]; + context = element.$context || (element.$context = createDataContext(this.getContext(), index, element)); + context.parsed = this.getParsed(index); + context.raw = dataset.data[index]; + context.index = context.dataIndex = index; + } else { + context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index)); + context.dataset = dataset; + context.index = context.datasetIndex = this.index; + } + context.active = !!active; + context.mode = mode; + return context; } - if (scaleConf._proxy) { - return console.warn(`Ignoring resolver passed as options for scale: ${id}`); + resolveDatasetElementOptions(mode) { + return this._resolveElementOptions(this.datasetElementType.id, mode); } - const axis = determineAxis(id, scaleConf); - const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); - const defaultScaleOptions = chartDefaults.scales || {}; - firstIDs[axis] = firstIDs[axis] || id; - scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]); - }); - config.data.datasets.forEach(dataset => { - const type = dataset.type || config.type; - const indexAxis = dataset.indexAxis || getIndexAxis(type, options); - const datasetDefaults = overrides[type] || {}; - const defaultScaleOptions = datasetDefaults.scales || {}; - Object.keys(defaultScaleOptions).forEach(defaultID => { - const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); - const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; - scales[id] = scales[id] || Object.create(null); - mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); - }); - }); - Object.keys(scales).forEach(key => { - const scale = scales[key]; - mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); - }); - return scales; -} -function initOptions(config) { - const options = config.options || (config.options = {}); - options.plugins = valueOrDefault(options.plugins, {}); - options.scales = mergeScaleConfig(config, options); -} -function initData(data) { - data = data || {}; - data.datasets = data.datasets || []; - data.labels = data.labels || []; - return data; -} -function initConfig(config) { - config = config || {}; - config.data = initData(config.data); - initOptions(config); - return config; -} -const keyCache = new Map(); -const keysCached = new Set(); -function cachedKeys(cacheKey, generate) { - let keys = keyCache.get(cacheKey); - if (!keys) { - keys = generate(); - keyCache.set(cacheKey, keys); - keysCached.add(keys); - } - return keys; -} -const addIfFound = (set, obj, key) => { - const opts = resolveObjectKey(obj, key); - if (opts !== undefined) { - set.add(opts); - } -}; -class Config { - constructor(config) { - this._config = initConfig(config); - this._scopeCache = new Map(); - this._resolverCache = new Map(); - } - get platform() { - return this._config.platform; - } - get type() { - return this._config.type; - } - set type(type) { - this._config.type = type; - } - get data() { - return this._config.data; - } - set data(data) { - this._config.data = initData(data); - } - get options() { - return this._config.options; - } - set options(options) { - this._config.options = options; - } - get plugins() { - return this._config.plugins; - } - update() { - const config = this._config; - this.clearCache(); - initOptions(config); - } - clearCache() { - this._scopeCache.clear(); - this._resolverCache.clear(); - } - datasetScopeKeys(datasetType) { - return cachedKeys(datasetType, - () => [[ - `datasets.${datasetType}`, - '' - ]]); - } - datasetAnimationScopeKeys(datasetType, transition) { - return cachedKeys(`${datasetType}.transition.${transition}`, - () => [ - [ - `datasets.${datasetType}.transitions.${transition}`, - `transitions.${transition}`, - ], - [ - `datasets.${datasetType}`, - '' - ] - ]); - } - datasetElementScopeKeys(datasetType, elementType) { - return cachedKeys(`${datasetType}-${elementType}`, - () => [[ - `datasets.${datasetType}.elements.${elementType}`, - `datasets.${datasetType}`, - `elements.${elementType}`, - '' - ]]); - } - pluginScopeKeys(plugin) { - const id = plugin.id; - const type = this.type; - return cachedKeys(`${type}-plugin-${id}`, - () => [[ - `plugins.${id}`, - ...plugin.additionalOptionScopes || [], - ]]); - } - _cachedScopes(mainScope, resetCache) { - const _scopeCache = this._scopeCache; - let cache = _scopeCache.get(mainScope); - if (!cache || resetCache) { - cache = new Map(); - _scopeCache.set(mainScope, cache); + resolveDataElementOptions(index, mode) { + return this._resolveElementOptions(this.dataElementType.id, mode, index); } - return cache; - } - getOptionScopes(mainScope, keyLists, resetCache) { - const {options, type} = this; - const cache = this._cachedScopes(mainScope, resetCache); - const cached = cache.get(keyLists); - if (cached) { - return cached; + _resolveElementOptions(elementType, mode = 'default', index) { + const active = mode === 'active'; + const cache = this._cachedDataOpts; + const cacheKey = elementType + '-' + mode; + const cached = cache[cacheKey]; + const sharing = this.enableOptionSharing && defined(index); + if (cached) { + return cloneIfNotShared(cached, sharing); + } + const config = this.chart.config; + const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); + const prefixes = active ? [ + `${elementType}Hover`, + 'hover', + elementType, + '' + ] : [ + elementType, + '' + ]; + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + const names = Object.keys(defaults.elements[elementType]); + const context = ()=>this.getContext(index, active, mode); + const values = config.resolveNamedOptions(scopes, names, context, prefixes); + if (values.$shared) { + values.$shared = sharing; + cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); + } + return values; } - const scopes = new Set(); - keyLists.forEach(keys => { - if (mainScope) { - scopes.add(mainScope); - keys.forEach(key => addIfFound(scopes, mainScope, key)); - } - keys.forEach(key => addIfFound(scopes, options, key)); - keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); - keys.forEach(key => addIfFound(scopes, defaults, key)); - keys.forEach(key => addIfFound(scopes, descriptors, key)); - }); - const array = Array.from(scopes); - if (array.length === 0) { - array.push(Object.create(null)); + _resolveAnimations(index, transition, active) { + const chart = this.chart; + const cache = this._cachedDataOpts; + const cacheKey = `animation-${transition}`; + const cached = cache[cacheKey]; + if (cached) { + return cached; + } + let options; + if (chart.options.animation !== false) { + const config = this.chart.config; + const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + options = config.createResolver(scopes, this.getContext(index, active, transition)); + } + const animations = new Animations(chart, options && options.animations); + if (options && options._cacheable) { + cache[cacheKey] = Object.freeze(animations); + } + return animations; } - if (keysCached.has(keyLists)) { - cache.set(keyLists, array); + getSharedOptions(options) { + if (!options.$shared) { + return; + } + return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); } - return array; - } - chartOptionScopes() { - const {options, type} = this; - return [ - options, - overrides[type] || {}, - defaults.datasets[type] || {}, - {type}, - defaults, - descriptors - ]; - } - resolveNamedOptions(scopes, names, context, prefixes = ['']) { - const result = {$shared: true}; - const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes); - let options = resolver; - if (needContext(resolver, names)) { - result.$shared = false; - context = isFunction(context) ? context() : context; - const subResolver = this.createResolver(scopes, context, subPrefixes); - options = _attachContext(resolver, context, subResolver); + includeOptions(mode, sharedOptions) { + return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; } - for (const prop of names) { - result[prop] = options[prop]; + _getSharedOptions(start, mode) { + const firstOpts = this.resolveDataElementOptions(start, mode); + const previouslySharedOptions = this._sharedOptions; + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions; + this.updateSharedOptions(sharedOptions, mode, firstOpts); + return { + sharedOptions, + includeOptions + }; } - return result; - } - createResolver(scopes, context, prefixes = [''], descriptorDefaults) { - const {resolver} = getResolver(this._resolverCache, scopes, prefixes); - return isObject(context) - ? _attachContext(resolver, context, undefined, descriptorDefaults) - : resolver; - } -} -function getResolver(resolverCache, scopes, prefixes) { - let cache = resolverCache.get(scopes); - if (!cache) { - cache = new Map(); - resolverCache.set(scopes, cache); - } - const cacheKey = prefixes.join(); - let cached = cache.get(cacheKey); - if (!cached) { - const resolver = _createResolver(scopes, prefixes); - cached = { - resolver, - subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover')) - }; - cache.set(cacheKey, cached); - } - return cached; -} -const hasFunction = value => isObject(value) - && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false); -function needContext(proxy, names) { - const {isScriptable, isIndexable} = _descriptors(proxy); - for (const prop of names) { - const scriptable = isScriptable(prop); - const indexable = isIndexable(prop); - const value = (indexable || scriptable) && proxy[prop]; - if ((scriptable && (isFunction(value) || hasFunction(value))) - || (indexable && isArray(value))) { - return true; + updateElement(element, index, properties, mode) { + if (isDirectUpdateMode(mode)) { + Object.assign(element, properties); + } else { + this._resolveAnimations(index, mode).update(element, properties); + } } - } - return false; -} - -var version = "3.7.0"; - -const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; -function positionIsHorizontal(position, axis) { - return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); -} -function compare2Level(l1, l2) { - return function(a, b) { - return a[l1] === b[l1] - ? a[l2] - b[l2] - : a[l1] - b[l1]; - }; -} -function onAnimationsComplete(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - chart.notifyPlugins('afterRender'); - callback(animationOptions && animationOptions.onComplete, [context], chart); -} -function onAnimationProgress(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - callback(animationOptions && animationOptions.onProgress, [context], chart); -} -function getCanvas(item) { - if (_isDomSupported() && typeof item === 'string') { - item = document.getElementById(item); - } else if (item && item.length) { - item = item[0]; - } - if (item && item.canvas) { - item = item.canvas; - } - return item; -} -const instances = {}; -const getChart = (key) => { - const canvas = getCanvas(key); - return Object.values(instances).filter((c) => c.canvas === canvas).pop(); -}; -function moveNumericKeys(obj, start, move) { - const keys = Object.keys(obj); - for (const key of keys) { - const intKey = +key; - if (intKey >= start) { - const value = obj[key]; - delete obj[key]; - if (move > 0 || intKey > start) { - obj[intKey + move] = value; - } + updateSharedOptions(sharedOptions, mode, newOptions) { + if (sharedOptions && !isDirectUpdateMode(mode)) { + this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); + } } - } -} -function determineLastEvent(e, lastEvent, inChartArea, isClick) { - if (!inChartArea || e.type === 'mouseout') { - return null; - } - if (isClick) { - return lastEvent; - } - return e; -} -class Chart { - constructor(item, userConfig) { - const config = this.config = new Config(userConfig); - const initialCanvas = getCanvas(item); - const existingChart = getChart(initialCanvas); - if (existingChart) { - throw new Error( - 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + - ' must be destroyed before the canvas can be reused.' - ); - } - const options = config.createResolver(config.chartOptionScopes(), this.getContext()); - this.platform = new (config.platform || _detectPlatform(initialCanvas))(); - this.platform.updateConfig(config); - const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); - const canvas = context && context.canvas; - const height = canvas && canvas.height; - const width = canvas && canvas.width; - this.id = uid(); - this.ctx = context; - this.canvas = canvas; - this.width = width; - this.height = height; - this._options = options; - this._aspectRatio = this.aspectRatio; - this._layers = []; - this._metasets = []; - this._stacks = undefined; - this.boxes = []; - this.currentDevicePixelRatio = undefined; - this.chartArea = undefined; - this._active = []; - this._lastEvent = undefined; - this._listeners = {}; - this._responsiveListeners = undefined; - this._sortedMetasets = []; - this.scales = {}; - this._plugins = new PluginService(); - this.$proxies = {}; - this._hiddenIndices = {}; - this.attached = false; - this._animationsDisabled = undefined; - this.$context = undefined; - this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0); - this._dataChanges = []; - instances[this.id] = this; - if (!context || !canvas) { - console.error("Failed to create chart: can't acquire context from the given item"); - return; - } - animator.listen(this, 'complete', onAnimationsComplete); - animator.listen(this, 'progress', onAnimationProgress); - this._initialize(); - if (this.attached) { - this.update(); - } - } - get aspectRatio() { - const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this; - if (!isNullOrUndef(aspectRatio)) { - return aspectRatio; - } - if (maintainAspectRatio && _aspectRatio) { - return _aspectRatio; - } - return height ? width / height : null; - } - get data() { - return this.config.data; - } - set data(data) { - this.config.data = data; - } - get options() { - return this._options; - } - set options(options) { - this.config.options = options; - } - _initialize() { - this.notifyPlugins('beforeInit'); - if (this.options.responsive) { - this.resize(); - } else { - retinaScale(this, this.options.devicePixelRatio); - } - this.bindEvents(); - this.notifyPlugins('afterInit'); - return this; - } - clear() { - clearCanvas(this.canvas, this.ctx); - return this; - } - stop() { - animator.stop(this); - return this; - } - resize(width, height) { - if (!animator.running(this)) { - this._resize(width, height); - } else { - this._resizeBeforeDraw = {width, height}; - } - } - _resize(width, height) { - const options = this.options; - const canvas = this.canvas; - const aspectRatio = options.maintainAspectRatio && this.aspectRatio; - const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); - const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); - const mode = this.width ? 'resize' : 'attach'; - this.width = newSize.width; - this.height = newSize.height; - this._aspectRatio = this.aspectRatio; - if (!retinaScale(this, newRatio, true)) { - return; - } - this.notifyPlugins('resize', {size: newSize}); - callback(options.onResize, [this, newSize], this); - if (this.attached) { - if (this._doResize(mode)) { - this.render(); - } - } - } - ensureScalesHaveIDs() { - const options = this.options; - const scalesOptions = options.scales || {}; - each(scalesOptions, (axisOptions, axisID) => { - axisOptions.id = axisID; - }); - } - buildOrUpdateScales() { - const options = this.options; - const scaleOpts = options.scales; - const scales = this.scales; - const updated = Object.keys(scales).reduce((obj, id) => { - obj[id] = false; - return obj; - }, {}); - let items = []; - if (scaleOpts) { - items = items.concat( - Object.keys(scaleOpts).map((id) => { - const scaleOptions = scaleOpts[id]; - const axis = determineAxis(id, scaleOptions); - const isRadial = axis === 'r'; - const isHorizontal = axis === 'x'; - return { - options: scaleOptions, - dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', - dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' - }; - }) - ); - } - each(items, (item) => { - const scaleOptions = item.options; - const id = scaleOptions.id; - const axis = determineAxis(id, scaleOptions); - const scaleType = valueOrDefault(scaleOptions.type, item.dtype); - if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { - scaleOptions.position = item.dposition; - } - updated[id] = true; - let scale = null; - if (id in scales && scales[id].type === scaleType) { - scale = scales[id]; - } else { - const scaleClass = registry.getScale(scaleType); - scale = new scaleClass({ - id, - type: scaleType, - ctx: this.ctx, - chart: this + _setStyle(element, index, mode, active) { + element.active = active; + const options = this.getStyle(index, active); + this._resolveAnimations(index, mode, active).update(element, { + options: !active && this.getSharedOptions(options) || options }); - scales[scale.id] = scale; - } - scale.init(scaleOptions, options); - }); - each(updated, (hasUpdated, id) => { - if (!hasUpdated) { - delete scales[id]; - } - }); - each(scales, (scale) => { - layouts.configure(this, scale, scale.options); - layouts.addBox(this, scale); - }); - } - _updateMetasets() { - const metasets = this._metasets; - const numData = this.data.datasets.length; - const numMeta = metasets.length; - metasets.sort((a, b) => a.index - b.index); - if (numMeta > numData) { - for (let i = numData; i < numMeta; ++i) { - this._destroyDatasetMeta(i); - } - metasets.splice(numData, numMeta - numData); } - this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); - } - _removeUnreferencedMetasets() { - const {_metasets: metasets, data: {datasets}} = this; - if (metasets.length > datasets.length) { - delete this._stacks; + removeHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', false); } - metasets.forEach((meta, index) => { - if (datasets.filter(x => x === meta._dataset).length === 0) { - this._destroyDatasetMeta(index); - } - }); - } - buildOrUpdateControllers() { - const newControllers = []; - const datasets = this.data.datasets; - let i, ilen; - this._removeUnreferencedMetasets(); - for (i = 0, ilen = datasets.length; i < ilen; i++) { - const dataset = datasets[i]; - let meta = this.getDatasetMeta(i); - const type = dataset.type || this.config.type; - if (meta.type && meta.type !== type) { - this._destroyDatasetMeta(i); - meta = this.getDatasetMeta(i); - } - meta.type = type; - meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); - meta.order = dataset.order || 0; - meta.index = i; - meta.label = '' + dataset.label; - meta.visible = this.isDatasetVisible(i); - if (meta.controller) { - meta.controller.updateIndex(i); - meta.controller.linkScales(); - } else { - const ControllerClass = registry.getController(type); - const {datasetElementType, dataElementType} = defaults.datasets[type]; - Object.assign(ControllerClass.prototype, { - dataElementType: registry.getElement(dataElementType), - datasetElementType: datasetElementType && registry.getElement(datasetElementType) - }); - meta.controller = new ControllerClass(this, i); - newControllers.push(meta.controller); - } + setHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', true); } - this._updateMetasets(); - return newControllers; - } - _resetElements() { - each(this.data.datasets, (dataset, datasetIndex) => { - this.getDatasetMeta(datasetIndex).controller.reset(); - }, this); - } - reset() { - this._resetElements(); - this.notifyPlugins('reset'); - } - update(mode) { - const config = this.config; - config.update(); - const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); - const animsDisabled = this._animationsDisabled = !options.animation; - this._updateScales(); - this._checkEventBindings(); - this._updateHiddenIndices(); - this._plugins.invalidate(); - if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) { - return; + _removeDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', false); + } } - const newControllers = this.buildOrUpdateControllers(); - this.notifyPlugins('beforeElementsUpdate'); - let minPadding = 0; - for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) { - const {controller} = this.getDatasetMeta(i); - const reset = !animsDisabled && newControllers.indexOf(controller) === -1; - controller.buildOrUpdateElements(reset); - minPadding = Math.max(+controller.getMaxOverflow(), minPadding); + _setDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', true); + } } - minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; - this._updateLayout(minPadding); - if (!animsDisabled) { - each(newControllers, (controller) => { - controller.reset(); - }); + _resyncElements(resetNewElements) { + const data = this._data; + const elements = this._cachedMeta.data; + for (const [method, arg1, arg2] of this._syncList){ + this[method](arg1, arg2); + } + this._syncList = []; + const numMeta = elements.length; + const numData = data.length; + const count = Math.min(numData, numMeta); + if (count) { + this.parse(0, count); + } + if (numData > numMeta) { + this._insertElements(numMeta, numData - numMeta, resetNewElements); + } else if (numData < numMeta) { + this._removeElements(numData, numMeta - numData); + } } - this._updateDatasets(mode); - this.notifyPlugins('afterUpdate', {mode}); - this._layers.sort(compare2Level('z', '_idx')); - const {_active, _lastEvent} = this; - if (_lastEvent) { - this._eventHandler(_lastEvent, true); - } else if (_active.length) { - this._updateHoverStyles(_active, _active, true); + _insertElements(start, count, resetNewElements = true) { + const meta = this._cachedMeta; + const data = meta.data; + const end = start + count; + let i; + const move = (arr)=>{ + arr.length += count; + for(i = arr.length - 1; i >= end; i--){ + arr[i] = arr[i - count]; + } + }; + move(data); + for(i = start; i < end; ++i){ + data[i] = new this.dataElementType(); + } + if (this._parsing) { + move(meta._parsed); + } + this.parse(start, count); + if (resetNewElements) { + this.updateElements(data, start, count, 'reset'); + } } - this.render(); - } - _updateScales() { - each(this.scales, (scale) => { - layouts.removeBox(this, scale); - }); - this.ensureScalesHaveIDs(); - this.buildOrUpdateScales(); - } - _checkEventBindings() { - const options = this.options; - const existingEvents = new Set(Object.keys(this._listeners)); - const newEvents = new Set(options.events); - if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { - this.unbindEvents(); - this.bindEvents(); + updateElements(element, start, count, mode) {} + _removeElements(start, count) { + const meta = this._cachedMeta; + if (this._parsing) { + const removed = meta._parsed.splice(start, count); + if (meta._stacked) { + clearStacks(meta, removed); + } + } + meta.data.splice(start, count); } - } - _updateHiddenIndices() { - const {_hiddenIndices} = this; - const changes = this._getUniformDataChanges() || []; - for (const {method, start, count} of changes) { - const move = method === '_removeElements' ? -count : count; - moveNumericKeys(_hiddenIndices, start, move); + _sync(args) { + if (this._parsing) { + this._syncList.push(args); + } else { + const [method, arg1, arg2] = args; + this[method](arg1, arg2); + } + this.chart._dataChanges.push([ + this.index, + ...args + ]); } - } - _getUniformDataChanges() { - const _dataChanges = this._dataChanges; - if (!_dataChanges || !_dataChanges.length) { - return; + _onDataPush() { + const count = arguments.length; + this._sync([ + '_insertElements', + this.getDataset().data.length - count, + count + ]); } - this._dataChanges = []; - const datasetCount = this.data.datasets.length; - const makeSet = (idx) => new Set( - _dataChanges - .filter(c => c[0] === idx) - .map((c, i) => i + ',' + c.splice(1).join(',')) - ); - const changeSet = makeSet(0); - for (let i = 1; i < datasetCount; i++) { - if (!setsEqual(changeSet, makeSet(i))) { - return; - } + _onDataPop() { + this._sync([ + '_removeElements', + this._cachedMeta.data.length - 1, + 1 + ]); } - return Array.from(changeSet) - .map(c => c.split(',')) - .map(a => ({method: a[1], start: +a[2], count: +a[3]})); - } - _updateLayout(minPadding) { - if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) { - return; + _onDataShift() { + this._sync([ + '_removeElements', + 0, + 1 + ]); } - layouts.update(this, this.width, this.height, minPadding); - const area = this.chartArea; - const noArea = area.width <= 0 || area.height <= 0; - this._layers = []; - each(this.boxes, (box) => { - if (noArea && box.position === 'chartArea') { - return; - } - if (box.configure) { - box.configure(); - } - this._layers.push(...box._layers()); - }, this); - this._layers.forEach((item, index) => { - item._idx = index; - }); - this.notifyPlugins('afterLayout'); - } - _updateDatasets(mode) { - if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { - return; + _onDataSplice(start, count) { + if (count) { + this._sync([ + '_removeElements', + start, + count + ]); + } + const newCount = arguments.length - 2; + if (newCount) { + this._sync([ + '_insertElements', + start, + newCount + ]); + } } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this.getDatasetMeta(i).controller.configure(); + _onDataUnshift() { + this._sync([ + '_insertElements', + 0, + arguments.length + ]); } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); - } - this.notifyPlugins('afterDatasetsUpdate', {mode}); - } - _updateDataset(index, mode) { - const meta = this.getDatasetMeta(index); - const args = {meta, index, mode, cancelable: true}; - if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { - return; - } - meta.controller._update(mode); - args.cancelable = false; - this.notifyPlugins('afterDatasetUpdate', args); - } - render() { - if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) { - return; - } - if (animator.has(this)) { - if (this.attached && !animator.running(this)) { - animator.start(this); - } - } else { - this.draw(); - onAnimationsComplete({chart: this}); - } - } - draw() { - let i; - if (this._resizeBeforeDraw) { - const {width, height} = this._resizeBeforeDraw; - this._resize(width, height); - this._resizeBeforeDraw = null; - } - this.clear(); - if (this.width <= 0 || this.height <= 0) { - return; - } - if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) { - return; - } - const layers = this._layers; - for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { - layers[i].draw(this.chartArea); - } - this._drawDatasets(); - for (; i < layers.length; ++i) { - layers[i].draw(this.chartArea); - } - this.notifyPlugins('afterDraw'); - } - _getSortedDatasetMetas(filterVisible) { - const metasets = this._sortedMetasets; - const result = []; - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - const meta = metasets[i]; - if (!filterVisible || meta.visible) { - result.push(meta); - } - } - return result; - } - getSortedVisibleDatasetMetas() { - return this._getSortedDatasetMetas(true); - } - _drawDatasets() { - if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) { - return; - } - const metasets = this.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - this._drawDataset(metasets[i]); - } - this.notifyPlugins('afterDatasetsDraw'); - } - _drawDataset(meta) { - const ctx = this.ctx; - const clip = meta._clip; - const useClip = !clip.disabled; - const area = this.chartArea; - const args = { - meta, - index: meta.index, - cancelable: true - }; - if (this.notifyPlugins('beforeDatasetDraw', args) === false) { - return; - } - if (useClip) { - clipArea(ctx, { - left: clip.left === false ? 0 : area.left - clip.left, - right: clip.right === false ? this.width : area.right + clip.right, - top: clip.top === false ? 0 : area.top - clip.top, - bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom - }); - } - meta.controller.draw(); - if (useClip) { - unclipArea(ctx); - } - args.cancelable = false; - this.notifyPlugins('afterDatasetDraw', args); - } - getElementsAtEventForMode(e, mode, options, useFinalPosition) { - const method = Interaction.modes[mode]; - if (typeof method === 'function') { - return method(this, e, options, useFinalPosition); - } - return []; - } - getDatasetMeta(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - const metasets = this._metasets; - let meta = metasets.filter(x => x && x._dataset === dataset).pop(); - if (!meta) { - meta = { - type: null, - data: [], - dataset: null, - controller: null, - hidden: null, - xAxisID: null, - yAxisID: null, - order: dataset && dataset.order || 0, - index: datasetIndex, - _dataset: dataset, - _parsed: [], - _sorted: false - }; - metasets.push(meta); - } - return meta; - } - getContext() { - return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'})); - } - getVisibleDatasetCount() { - return this.getSortedVisibleDatasetMetas().length; - } - isDatasetVisible(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - if (!dataset) { - return false; - } - const meta = this.getDatasetMeta(datasetIndex); - return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; - } - setDatasetVisibility(datasetIndex, visible) { - const meta = this.getDatasetMeta(datasetIndex); - meta.hidden = !visible; - } - toggleDataVisibility(index) { - this._hiddenIndices[index] = !this._hiddenIndices[index]; - } - getDataVisibility(index) { - return !this._hiddenIndices[index]; - } - _updateVisibility(datasetIndex, dataIndex, visible) { - const mode = visible ? 'show' : 'hide'; - const meta = this.getDatasetMeta(datasetIndex); - const anims = meta.controller._resolveAnimations(undefined, mode); - if (defined(dataIndex)) { - meta.data[dataIndex].hidden = !visible; - this.update(); - } else { - this.setDatasetVisibility(datasetIndex, visible); - anims.update(meta, {visible}); - this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); - } - } - hide(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, false); - } - show(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, true); - } - _destroyDatasetMeta(datasetIndex) { - const meta = this._metasets[datasetIndex]; - if (meta && meta.controller) { - meta.controller._destroy(); - } - delete this._metasets[datasetIndex]; - } - _stop() { - let i, ilen; - this.stop(); - animator.remove(this); - for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._destroyDatasetMeta(i); - } - } - destroy() { - this.notifyPlugins('beforeDestroy'); - const {canvas, ctx} = this; - this._stop(); - this.config.clearCache(); - if (canvas) { - this.unbindEvents(); - clearCanvas(canvas, ctx); - this.platform.releaseContext(ctx); - this.canvas = null; - this.ctx = null; - } - this.notifyPlugins('destroy'); - delete instances[this.id]; - this.notifyPlugins('afterDestroy'); - } - toBase64Image(...args) { - return this.canvas.toDataURL(...args); - } - bindEvents() { - this.bindUserEvents(); - if (this.options.responsive) { - this.bindResponsiveEvents(); - } else { - this.attached = true; - } - } - bindUserEvents() { - const listeners = this._listeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const listener = (e, x, y) => { - e.offsetX = x; - e.offsetY = y; - this._eventHandler(e); - }; - each(this.options.events, (type) => _add(type, listener)); - } - bindResponsiveEvents() { - if (!this._responsiveListeners) { - this._responsiveListeners = {}; - } - const listeners = this._responsiveListeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const _remove = (type, listener) => { - if (listeners[type]) { - platform.removeEventListener(this, type, listener); - delete listeners[type]; - } - }; - const listener = (width, height) => { - if (this.canvas) { - this.resize(width, height); - } - }; - let detached; - const attached = () => { - _remove('attach', attached); - this.attached = true; - this.resize(); - _add('resize', listener); - _add('detach', detached); - }; - detached = () => { - this.attached = false; - _remove('resize', listener); - this._stop(); - this._resize(0, 0); - _add('attach', attached); - }; - if (platform.isAttached(this.canvas)) { - attached(); - } else { - detached(); - } - } - unbindEvents() { - each(this._listeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._listeners = {}; - each(this._responsiveListeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._responsiveListeners = undefined; - } - updateHoverStyle(items, mode, enabled) { - const prefix = enabled ? 'set' : 'remove'; - let meta, item, i, ilen; - if (mode === 'dataset') { - meta = this.getDatasetMeta(items[0].datasetIndex); - meta.controller['_' + prefix + 'DatasetHoverStyle'](); - } - for (i = 0, ilen = items.length; i < ilen; ++i) { - item = items[i]; - const controller = item && this.getDatasetMeta(item.datasetIndex).controller; - if (controller) { - controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); - } - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements) { - const lastActive = this._active || []; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('No dataset found at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(active, lastActive); - if (changed) { - this._active = active; - this._lastEvent = null; - this._updateHoverStyles(active, lastActive); - } - } - notifyPlugins(hook, args, filter) { - return this._plugins.notify(this, hook, args, filter); - } - _updateHoverStyles(active, lastActive, replay) { - const hoverOptions = this.options.hover; - const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index)); - const deactivated = diff(lastActive, active); - const activated = replay ? active : diff(active, lastActive); - if (deactivated.length) { - this.updateHoverStyle(deactivated, hoverOptions.mode, false); - } - if (activated.length && hoverOptions.mode) { - this.updateHoverStyle(activated, hoverOptions.mode, true); - } - } - _eventHandler(e, replay) { - const args = { - event: e, - replay, - cancelable: true, - inChartArea: _isPointInArea(e, this.chartArea, this._minPadding) - }; - const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type); - if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { - return; - } - const changed = this._handleEvent(e, replay, args.inChartArea); - args.cancelable = false; - this.notifyPlugins('afterEvent', args, eventFilter); - if (changed || args.changed) { - this.render(); - } - return this; - } - _handleEvent(e, replay, inChartArea) { - const {_active: lastActive = [], options} = this; - const useFinalPosition = replay; - const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); - const isClick = _isClickEvent(e); - const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); - if (inChartArea) { - this._lastEvent = null; - callback(options.onHover, [e, active, this], this); - if (isClick) { - callback(options.onClick, [e, active, this], this); - } - } - const changed = !_elementsEqual(active, lastActive); - if (changed || replay) { - this._active = active; - this._updateHoverStyles(active, lastActive, replay); - } - this._lastEvent = lastEvent; - return changed; - } - _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const hoverOptions = this.options.hover; - return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); - } } -const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); -const enumerable = true; -Object.defineProperties(Chart, { - defaults: { - enumerable, - value: defaults - }, - instances: { - enumerable, - value: instances - }, - overrides: { - enumerable, - value: overrides - }, - registry: { - enumerable, - value: registry - }, - version: { - enumerable, - value: version - }, - getChart: { - enumerable, - value: getChart - }, - register: { - enumerable, - value: (...items) => { - registry.add(...items); - invalidatePlugins(); - } - }, - unregister: { - enumerable, - value: (...items) => { - registry.remove(...items); - invalidatePlugins(); - } - } -}); - -function abstract() { - throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); -} -class DateAdapter { - constructor(options) { - this.options = options || {}; - } - formats() { - return abstract(); - } - parse(value, format) { - return abstract(); - } - format(timestamp, format) { - return abstract(); - } - add(timestamp, amount, unit) { - return abstract(); - } - diff(a, b, unit) { - return abstract(); - } - startOf(timestamp, unit, weekday) { - return abstract(); - } - endOf(timestamp, unit) { - return abstract(); - } -} -DateAdapter.override = function(members) { - Object.assign(DateAdapter.prototype, members); -}; -var _adapters = { - _date: DateAdapter -}; function getAllScaleValues(scale, type) { - if (!scale._cache.$bar) { - const visibleMetas = scale.getMatchingVisibleMetas(type); - let values = []; - for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) { - values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); + if (!scale._cache.$bar) { + const visibleMetas = scale.getMatchingVisibleMetas(type); + let values = []; + for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){ + values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); + } + scale._cache.$bar = _arrayUnique(values.sort((a, b)=>a - b)); } - scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b)); - } - return scale._cache.$bar; + return scale._cache.$bar; } -function computeMinSampleSize(meta) { - const scale = meta.iScale; - const values = getAllScaleValues(scale, meta.type); - let min = scale._length; - let i, ilen, curr, prev; - const updateMinAndPrev = () => { - if (curr === 32767 || curr === -32768) { - return; + function computeMinSampleSize(meta) { + const scale = meta.iScale; + const values = getAllScaleValues(scale, meta.type); + let min = scale._length; + let i, ilen, curr, prev; + const updateMinAndPrev = ()=>{ + if (curr === 32767 || curr === -32768) { + return; + } + if (defined(prev)) { + min = Math.min(min, Math.abs(curr - prev) || min); + } + prev = curr; + }; + for(i = 0, ilen = values.length; i < ilen; ++i){ + curr = scale.getPixelForValue(values[i]); + updateMinAndPrev(); } - if (defined(prev)) { - min = Math.min(min, Math.abs(curr - prev) || min); + prev = undefined; + for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){ + curr = scale.getPixelForTick(i); + updateMinAndPrev(); } - prev = curr; - }; - for (i = 0, ilen = values.length; i < ilen; ++i) { - curr = scale.getPixelForValue(values[i]); - updateMinAndPrev(); - } - prev = undefined; - for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { - curr = scale.getPixelForTick(i); - updateMinAndPrev(); - } - return min; + return min; } -function computeFitCategoryTraits(index, ruler, options, stackCount) { - const thickness = options.barThickness; - let size, ratio; - if (isNullOrUndef(thickness)) { - size = ruler.min * options.categoryPercentage; - ratio = options.barPercentage; - } else { - size = thickness * stackCount; - ratio = 1; - } - return { - chunk: size / stackCount, - ratio, - start: ruler.pixels[index] - (size / 2) - }; + function computeFitCategoryTraits(index, ruler, options, stackCount) { + const thickness = options.barThickness; + let size, ratio; + if (isNullOrUndef(thickness)) { + size = ruler.min * options.categoryPercentage; + ratio = options.barPercentage; + } else { + size = thickness * stackCount; + ratio = 1; + } + return { + chunk: size / stackCount, + ratio, + start: ruler.pixels[index] - size / 2 + }; } -function computeFlexCategoryTraits(index, ruler, options, stackCount) { - const pixels = ruler.pixels; - const curr = pixels[index]; - let prev = index > 0 ? pixels[index - 1] : null; - let next = index < pixels.length - 1 ? pixels[index + 1] : null; - const percent = options.categoryPercentage; - if (prev === null) { - prev = curr - (next === null ? ruler.end - ruler.start : next - curr); - } - if (next === null) { - next = curr + curr - prev; - } - const start = curr - (curr - Math.min(prev, next)) / 2 * percent; - const size = Math.abs(next - prev) / 2 * percent; - return { - chunk: size / stackCount, - ratio: options.barPercentage, - start - }; + function computeFlexCategoryTraits(index, ruler, options, stackCount) { + const pixels = ruler.pixels; + const curr = pixels[index]; + let prev = index > 0 ? pixels[index - 1] : null; + let next = index < pixels.length - 1 ? pixels[index + 1] : null; + const percent = options.categoryPercentage; + if (prev === null) { + prev = curr - (next === null ? ruler.end - ruler.start : next - curr); + } + if (next === null) { + next = curr + curr - prev; + } + const start = curr - (curr - Math.min(prev, next)) / 2 * percent; + const size = Math.abs(next - prev) / 2 * percent; + return { + chunk: size / stackCount, + ratio: options.barPercentage, + start + }; } function parseFloatBar(entry, item, vScale, i) { - const startValue = vScale.parse(entry[0], i); - const endValue = vScale.parse(entry[1], i); - const min = Math.min(startValue, endValue); - const max = Math.max(startValue, endValue); - let barStart = min; - let barEnd = max; - if (Math.abs(min) > Math.abs(max)) { - barStart = max; - barEnd = min; - } - item[vScale.axis] = barEnd; - item._custom = { - barStart, - barEnd, - start: startValue, - end: endValue, - min, - max - }; + const startValue = vScale.parse(entry[0], i); + const endValue = vScale.parse(entry[1], i); + const min = Math.min(startValue, endValue); + const max = Math.max(startValue, endValue); + let barStart = min; + let barEnd = max; + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + item[vScale.axis] = barEnd; + item._custom = { + barStart, + barEnd, + start: startValue, + end: endValue, + min, + max + }; } function parseValue(entry, item, vScale, i) { - if (isArray(entry)) { - parseFloatBar(entry, item, vScale, i); - } else { - item[vScale.axis] = vScale.parse(entry, i); - } - return item; + if (isArray(entry)) { + parseFloatBar(entry, item, vScale, i); + } else { + item[vScale.axis] = vScale.parse(entry, i); + } + return item; } function parseArrayOrPrimitive(meta, data, start, count) { - const iScale = meta.iScale; - const vScale = meta.vScale; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = []; - let i, ilen, item, entry; - for (i = start, ilen = start + count; i < ilen; ++i) { - entry = data[i]; - item = {}; - item[iScale.axis] = singleScale || iScale.parse(labels[i], i); - parsed.push(parseValue(entry, item, vScale, i)); - } - return parsed; + const iScale = meta.iScale; + const vScale = meta.vScale; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = []; + let i, ilen, item, entry; + for(i = start, ilen = start + count; i < ilen; ++i){ + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; } function isFloatBar(custom) { - return custom && custom.barStart !== undefined && custom.barEnd !== undefined; + return custom && custom.barStart !== undefined && custom.barEnd !== undefined; } function barSign(size, vScale, actualBase) { - if (size !== 0) { - return sign(size); - } - return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); + if (size !== 0) { + return sign(size); + } + return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); } function borderProps(properties) { - let reverse, start, end, top, bottom; - if (properties.horizontal) { - reverse = properties.base > properties.x; - start = 'left'; - end = 'right'; - } else { - reverse = properties.base < properties.y; - start = 'bottom'; - end = 'top'; - } - if (reverse) { - top = 'end'; - bottom = 'start'; - } else { - top = 'start'; - bottom = 'end'; - } - return {start, end, reverse, top, bottom}; + let reverse, start, end, top, bottom; + if (properties.horizontal) { + reverse = properties.base > properties.x; + start = 'left'; + end = 'right'; + } else { + reverse = properties.base < properties.y; + start = 'bottom'; + end = 'top'; + } + if (reverse) { + top = 'end'; + bottom = 'start'; + } else { + top = 'start'; + bottom = 'end'; + } + return { + start, + end, + reverse, + top, + bottom + }; } function setBorderSkipped(properties, options, stack, index) { - let edge = options.borderSkipped; - const res = {}; - if (!edge) { - properties.borderSkipped = res; - return; - } - const {start, end, reverse, top, bottom} = borderProps(properties); - if (edge === 'middle' && stack) { - properties.enableBorderRadius = true; - if ((stack._top || 0) === index) { - edge = top; - } else if ((stack._bottom || 0) === index) { - edge = bottom; - } else { - res[parseEdge(bottom, start, end, reverse)] = true; - edge = top; + let edge = options.borderSkipped; + const res = {}; + if (!edge) { + properties.borderSkipped = res; + return; } - } - res[parseEdge(edge, start, end, reverse)] = true; - properties.borderSkipped = res; + if (edge === true) { + properties.borderSkipped = { + top: true, + right: true, + bottom: true, + left: true + }; + return; + } + const { start , end , reverse , top , bottom } = borderProps(properties); + if (edge === 'middle' && stack) { + properties.enableBorderRadius = true; + if ((stack._top || 0) === index) { + edge = top; + } else if ((stack._bottom || 0) === index) { + edge = bottom; + } else { + res[parseEdge(bottom, start, end, reverse)] = true; + edge = top; + } + } + res[parseEdge(edge, start, end, reverse)] = true; + properties.borderSkipped = res; } function parseEdge(edge, a, b, reverse) { - if (reverse) { - edge = swap(edge, a, b); - edge = startEnd(edge, b, a); - } else { - edge = startEnd(edge, a, b); - } - return edge; + if (reverse) { + edge = swap(edge, a, b); + edge = startEnd(edge, b, a); + } else { + edge = startEnd(edge, a, b); + } + return edge; } function swap(orig, v1, v2) { - return orig === v1 ? v2 : orig === v2 ? v1 : orig; + return orig === v1 ? v2 : orig === v2 ? v1 : orig; } function startEnd(v, start, end) { - return v === 'start' ? start : v === 'end' ? end : v; + return v === 'start' ? start : v === 'end' ? end : v; } -function setInflateAmount(properties, {inflateAmount}, ratio) { - properties.inflateAmount = inflateAmount === 'auto' - ? ratio === 1 ? 0.33 : 0 - : inflateAmount; +function setInflateAmount(properties, { inflateAmount }, ratio) { + properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount; } class BarController extends DatasetController { - parsePrimitiveData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseArrayData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseObjectData(meta, data, start, count) { - const {iScale, vScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; - const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; - const parsed = []; - let i, ilen, item, obj; - for (i = start, ilen = start + count; i < ilen; ++i) { - obj = data[i]; - item = {}; - item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); - parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); - } - return parsed; - } - updateRangeFromParsed(range, scale, parsed, stack) { - super.updateRangeFromParsed(range, scale, parsed, stack); - const custom = parsed._custom; - if (custom && scale === this._cachedMeta.vScale) { - range.min = Math.min(range.min, custom.min); - range.max = Math.max(range.max, custom.max); - } - } - getMaxOverflow() { - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {iScale, vScale} = meta; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const value = isFloatBar(custom) - ? '[' + custom.start + ', ' + custom.end + ']' - : '' + vScale.getLabelForValue(parsed[vScale.axis]); - return { - label: '' + iScale.getLabelForValue(parsed[iScale.axis]), - value - }; - } - initialize() { - this.enableOptionSharing = true; - super.initialize(); - const meta = this._cachedMeta; - meta.stack = this.getDataset().stack; - } - update(mode) { - const meta = this._cachedMeta; - this.updateElements(meta.data, 0, meta.data.length, mode); - } - updateElements(bars, start, count, mode) { - const reset = mode === 'reset'; - const {index, _cachedMeta: {vScale}} = this; - const base = vScale.getBasePixel(); - const horizontal = vScale.isHorizontal(); - const ruler = this._getRuler(); - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - this.updateSharedOptions(sharedOptions, mode, firstOpts); - for (let i = start; i < start + count; i++) { - const parsed = this.getParsed(i); - const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i); - const ipixels = this._calculateBarIndexPixels(i, ruler); - const stack = (parsed._stacks || {})[vScale.axis]; - const properties = { - horizontal, - base: vpixels.base, - enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom), - x: horizontal ? vpixels.head : ipixels.center, - y: horizontal ? ipixels.center : vpixels.head, - height: horizontal ? ipixels.size : Math.abs(vpixels.size), - width: horizontal ? Math.abs(vpixels.size) : ipixels.size - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); - } - const options = properties.options || bars[i].options; - setBorderSkipped(properties, options, stack, index); - setInflateAmount(properties, options, ruler.ratio); - this.updateElement(bars[i], i, properties, mode); - } - } - _getStacks(last, dataIndex) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const metasets = iScale.getMatchingVisibleMetas(this._type); - const stacked = iScale.options.stacked; - const ilen = metasets.length; - const stacks = []; - let i, item; - for (i = 0; i < ilen; ++i) { - item = metasets[i]; - if (!item.controller.options.grouped) { - continue; - } - if (typeof dataIndex !== 'undefined') { - const val = item.controller.getParsed(dataIndex)[ - item.controller._cachedMeta.vScale.axis - ]; - if (isNullOrUndef(val) || isNaN(val)) { - continue; + static id = 'bar'; + static defaults = { + datasetElementType: false, + dataElementType: 'bar', + categoryPercentage: 0.8, + barPercentage: 0.9, + grouped: true, + animations: { + numbers: { + type: 'number', + properties: [ + 'x', + 'y', + 'base', + 'width', + 'height' + ] + } } - } - if (stacked === false || stacks.indexOf(item.stack) === -1 || - (stacked === undefined && item.stack === undefined)) { - stacks.push(item.stack); - } - if (item.index === last) { - break; - } - } - if (!stacks.length) { - stacks.push(undefined); - } - return stacks; - } - _getStackCount(index) { - return this._getStacks(undefined, index).length; - } - _getStackIndex(datasetIndex, name, dataIndex) { - const stacks = this._getStacks(datasetIndex, dataIndex); - const index = (name !== undefined) - ? stacks.indexOf(name) - : -1; - return (index === -1) - ? stacks.length - 1 - : index; - } - _getRuler() { - const opts = this.options; - const meta = this._cachedMeta; - const iScale = meta.iScale; - const pixels = []; - let i, ilen; - for (i = 0, ilen = meta.data.length; i < ilen; ++i) { - pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); - } - const barThickness = opts.barThickness; - const min = barThickness || computeMinSampleSize(meta); - return { - min, - pixels, - start: iScale._startPixel, - end: iScale._endPixel, - stackCount: this._getStackCount(), - scale: iScale, - grouped: opts.grouped, - ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage }; - } - _calculateBarValuePixels(index) { - const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; - const actualBase = baseValue || 0; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const floating = isFloatBar(custom); - let value = parsed[vScale.axis]; - let start = 0; - let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; - let head, size; - if (length !== value) { - start = length - value; - length = value; - } - if (floating) { - value = custom.barStart; - length = custom.barEnd - custom.barStart; - if (value !== 0 && sign(value) !== sign(custom.barEnd)) { - start = 0; - } - start += value; - } - const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; - let base = vScale.getPixelForValue(startValue); - if (this.chart.getDataVisibility(index)) { - head = vScale.getPixelForValue(start + length); - } else { - head = base; - } - size = head - base; - if (Math.abs(size) < minBarLength) { - size = barSign(size, vScale, actualBase) * minBarLength; - if (value === actualBase) { - base -= size / 2; - } - head = base + size; - } - if (base === vScale.getPixelForValue(actualBase)) { - const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; - base += halfGrid; - size -= halfGrid; - } - return { - size, - base, - head, - center: head + size / 2 + static overrides = { + scales: { + _index_: { + type: 'category', + offset: true, + grid: { + offset: true + } + }, + _value_: { + type: 'linear', + beginAtZero: true + } + } }; - } - _calculateBarIndexPixels(index, ruler) { - const scale = ruler.scale; - const options = this.options; - const skipNull = options.skipNull; - const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); - let center, size; - if (ruler.grouped) { - const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; - const range = options.barThickness === 'flex' - ? computeFlexCategoryTraits(index, ruler, options, stackCount) - : computeFitCategoryTraits(index, ruler, options, stackCount); - const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); - center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); - size = Math.min(maxBarThickness, range.chunk * range.ratio); - } else { - center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); - size = Math.min(maxBarThickness, ruler.min * ruler.ratio); + parsePrimitiveData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); } - return { - base: center - size / 2, - head: center + size / 2, - center, - size - }; - } - draw() { - const meta = this._cachedMeta; - const vScale = meta.vScale; - const rects = meta.data; - const ilen = rects.length; - let i = 0; - for (; i < ilen; ++i) { - if (this.getParsed(i)[vScale.axis] !== null) { - rects[i].draw(this._ctx); - } + parseArrayData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseObjectData(meta, data, start, count) { + const { iScale , vScale } = meta; + const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; + const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; + const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; + const parsed = []; + let i, ilen, item, obj; + for(i = start, ilen = start + count; i < ilen; ++i){ + obj = data[i]; + item = {}; + item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); + parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); + } + return parsed; + } + updateRangeFromParsed(range, scale, parsed, stack) { + super.updateRangeFromParsed(range, scale, parsed, stack); + const custom = parsed._custom; + if (custom && scale === this._cachedMeta.vScale) { + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + getMaxOverflow() { + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const { iScale , vScale } = meta; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]); + return { + label: '' + iScale.getLabelForValue(parsed[iScale.axis]), + value + }; + } + initialize() { + this.enableOptionSharing = true; + super.initialize(); + const meta = this._cachedMeta; + meta.stack = this.getDataset().stack; + } + update(mode) { + const meta = this._cachedMeta; + this.updateElements(meta.data, 0, meta.data.length, mode); + } + updateElements(bars, start, count, mode) { + const reset = mode === 'reset'; + const { index , _cachedMeta: { vScale } } = this; + const base = vScale.getBasePixel(); + const horizontal = vScale.isHorizontal(); + const ruler = this._getRuler(); + const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); + for(let i = start; i < start + count; i++){ + const parsed = this.getParsed(i); + const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? { + base, + head: base + } : this._calculateBarValuePixels(i); + const ipixels = this._calculateBarIndexPixels(i, ruler); + const stack = (parsed._stacks || {})[vScale.axis]; + const properties = { + horizontal, + base: vpixels.base, + enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom, + x: horizontal ? vpixels.head : ipixels.center, + y: horizontal ? ipixels.center : vpixels.head, + height: horizontal ? ipixels.size : Math.abs(vpixels.size), + width: horizontal ? Math.abs(vpixels.size) : ipixels.size + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); + } + const options = properties.options || bars[i].options; + setBorderSkipped(properties, options, stack, index); + setInflateAmount(properties, options, ruler.ratio); + this.updateElement(bars[i], i, properties, mode); + } + } + _getStacks(last, dataIndex) { + const { iScale } = this._cachedMeta; + const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped); + const stacked = iScale.options.stacked; + const stacks = []; + const skipNull = (meta)=>{ + const parsed = meta.controller.getParsed(dataIndex); + const val = parsed && parsed[meta.vScale.axis]; + if (isNullOrUndef(val) || isNaN(val)) { + return true; + } + }; + for (const meta of metasets){ + if (dataIndex !== undefined && skipNull(meta)) { + continue; + } + if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) { + stacks.push(meta.stack); + } + if (meta.index === last) { + break; + } + } + if (!stacks.length) { + stacks.push(undefined); + } + return stacks; + } + _getStackCount(index) { + return this._getStacks(undefined, index).length; + } + _getStackIndex(datasetIndex, name, dataIndex) { + const stacks = this._getStacks(datasetIndex, dataIndex); + const index = name !== undefined ? stacks.indexOf(name) : -1; + return index === -1 ? stacks.length - 1 : index; + } + _getRuler() { + const opts = this.options; + const meta = this._cachedMeta; + const iScale = meta.iScale; + const pixels = []; + let i, ilen; + for(i = 0, ilen = meta.data.length; i < ilen; ++i){ + pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); + } + const barThickness = opts.barThickness; + const min = barThickness || computeMinSampleSize(meta); + return { + min, + pixels, + start: iScale._startPixel, + end: iScale._endPixel, + stackCount: this._getStackCount(), + scale: iScale, + grouped: opts.grouped, + ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage + }; + } + _calculateBarValuePixels(index) { + const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this; + const actualBase = baseValue || 0; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const floating = isFloatBar(custom); + let value = parsed[vScale.axis]; + let start = 0; + let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; + let head, size; + if (length !== value) { + start = length - value; + length = value; + } + if (floating) { + value = custom.barStart; + length = custom.barEnd - custom.barStart; + if (value !== 0 && sign(value) !== sign(custom.barEnd)) { + start = 0; + } + start += value; + } + const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; + let base = vScale.getPixelForValue(startValue); + if (this.chart.getDataVisibility(index)) { + head = vScale.getPixelForValue(start + length); + } else { + head = base; + } + size = head - base; + if (Math.abs(size) < minBarLength) { + size = barSign(size, vScale, actualBase) * minBarLength; + if (value === actualBase) { + base -= size / 2; + } + const startPixel = vScale.getPixelForDecimal(0); + const endPixel = vScale.getPixelForDecimal(1); + const min = Math.min(startPixel, endPixel); + const max = Math.max(startPixel, endPixel); + base = Math.max(Math.min(base, max), min); + head = base + size; + if (_stacked && !floating) { + parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base); + } + } + if (base === vScale.getPixelForValue(actualBase)) { + const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; + base += halfGrid; + size -= halfGrid; + } + return { + size, + base, + head, + center: head + size / 2 + }; + } + _calculateBarIndexPixels(index, ruler) { + const scale = ruler.scale; + const options = this.options; + const skipNull = options.skipNull; + const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); + let center, size; + if (ruler.grouped) { + const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; + const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount) : computeFitCategoryTraits(index, ruler, options, stackCount); + const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); + center = range.start + range.chunk * stackIndex + range.chunk / 2; + size = Math.min(maxBarThickness, range.chunk * range.ratio); + } else { + center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); + size = Math.min(maxBarThickness, ruler.min * ruler.ratio); + } + return { + base: center - size / 2, + head: center + size / 2, + center, + size + }; + } + draw() { + const meta = this._cachedMeta; + const vScale = meta.vScale; + const rects = meta.data; + const ilen = rects.length; + let i = 0; + for(; i < ilen; ++i){ + if (this.getParsed(i)[vScale.axis] !== null) { + rects[i].draw(this._ctx); + } + } } - } } -BarController.id = 'bar'; -BarController.defaults = { - datasetElementType: false, - dataElementType: 'bar', - categoryPercentage: 0.8, - barPercentage: 0.9, - grouped: true, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'base', 'width', 'height'] - } - } -}; -BarController.overrides = { - scales: { - _index_: { - type: 'category', - offset: true, - grid: { - offset: true - } - }, - _value_: { - type: 'linear', - beginAtZero: true, - } - } -}; class BubbleController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - parsePrimitiveData(meta, data, start, count) { - const parsed = super.parsePrimitiveData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const parsed = super.parseArrayData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const parsed = super.parseObjectData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - getMaxOverflow() { - const data = this._cachedMeta.data; - let max = 0; - for (let i = data.length - 1; i >= 0; --i) { - max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); - } - return max > 0 && max; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {xScale, yScale} = meta; - const parsed = this.getParsed(index); - const x = xScale.getLabelForValue(parsed.x); - const y = yScale.getLabelForValue(parsed.y); - const r = parsed._custom; - return { - label: meta.label, - value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + static id = 'bubble'; + static defaults = { + datasetElementType: false, + dataElementType: 'point', + animations: { + numbers: { + type: 'number', + properties: [ + 'x', + 'y', + 'borderWidth', + 'radius' + ] + } + } }; - } - update(mode) { - const points = this._cachedMeta.data; - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const parsed = !reset && this.getParsed(i); - const properties = {}; - const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); - const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); - properties.skip = isNaN(iPixel) || isNaN(vPixel); - if (includeOptions) { - properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - if (reset) { - properties.options.radius = 0; + static overrides = { + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } } - } - this.updateElement(point, i, properties, mode); + }; + initialize() { + this.enableOptionSharing = true; + super.initialize(); } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - resolveDataElementOptions(index, mode) { - const parsed = this.getParsed(index); - let values = super.resolveDataElementOptions(index, mode); - if (values.$shared) { - values = Object.assign({}, values, {$shared: false}); + parsePrimitiveData(meta, data, start, count) { + const parsed = super.parsePrimitiveData(meta, data, start, count); + for(let i = 0; i < parsed.length; i++){ + parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; + } + return parsed; } - const radius = values.radius; - if (mode !== 'active') { - values.radius = 0; + parseArrayData(meta, data, start, count) { + const parsed = super.parseArrayData(meta, data, start, count); + for(let i = 0; i < parsed.length; i++){ + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const parsed = super.parseObjectData(meta, data, start, count); + for(let i = 0; i < parsed.length; i++){ + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + getMaxOverflow() { + const data = this._cachedMeta.data; + let max = 0; + for(let i = data.length - 1; i >= 0; --i){ + max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); + } + return max > 0 && max; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const labels = this.chart.data.labels || []; + const { xScale , yScale } = meta; + const parsed = this.getParsed(index); + const x = xScale.getLabelForValue(parsed.x); + const y = yScale.getLabelForValue(parsed.y); + const r = parsed._custom; + return { + label: labels[index] || '', + value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + }; + } + update(mode) { + const points = this._cachedMeta.data; + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const { iScale , vScale } = this._cachedMeta; + const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + for(let i = start; i < start + count; i++){ + const point = points[i]; + const parsed = !reset && this.getParsed(i); + const properties = {}; + const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); + const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); + properties.skip = isNaN(iPixel) || isNaN(vPixel); + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); + if (reset) { + properties.options.radius = 0; + } + } + this.updateElement(point, i, properties, mode); + } + } + resolveDataElementOptions(index, mode) { + const parsed = this.getParsed(index); + let values = super.resolveDataElementOptions(index, mode); + if (values.$shared) { + values = Object.assign({}, values, { + $shared: false + }); + } + const radius = values.radius; + if (mode !== 'active') { + values.radius = 0; + } + values.radius += valueOrDefault(parsed && parsed._custom, radius); + return values; } - values.radius += valueOrDefault(parsed && parsed._custom, radius); - return values; - } } -BubbleController.id = 'bubble'; -BubbleController.defaults = { - datasetElementType: false, - dataElementType: 'point', - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'borderWidth', 'radius'] - } - } -}; -BubbleController.overrides = { - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' - } - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - } - } - } - } -}; function getRatioAndOffset(rotation, circumference, cutout) { - let ratioX = 1; - let ratioY = 1; - let offsetX = 0; - let offsetY = 0; - if (circumference < TAU) { - const startAngle = rotation; - const endAngle = startAngle + circumference; - const startX = Math.cos(startAngle); - const startY = Math.sin(startAngle); - const endX = Math.cos(endAngle); - const endY = Math.sin(endAngle); - const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); - const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); - const maxX = calcMax(0, startX, endX); - const maxY = calcMax(HALF_PI, startY, endY); - const minX = calcMin(PI, startX, endX); - const minY = calcMin(PI + HALF_PI, startY, endY); - ratioX = (maxX - minX) / 2; - ratioY = (maxY - minY) / 2; - offsetX = -(maxX + minX) / 2; - offsetY = -(maxY + minY) / 2; - } - return {ratioX, ratioY, offsetX, offsetY}; + let ratioX = 1; + let ratioY = 1; + let offsetX = 0; + let offsetY = 0; + if (circumference < TAU) { + const startAngle = rotation; + const endAngle = startAngle + circumference; + const startX = Math.cos(startAngle); + const startY = Math.sin(startAngle); + const endX = Math.cos(endAngle); + const endY = Math.sin(endAngle); + const calcMax = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); + const calcMin = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); + const maxX = calcMax(0, startX, endX); + const maxY = calcMax(HALF_PI, startY, endY); + const minX = calcMin(PI, startX, endX); + const minY = calcMin(PI + HALF_PI, startY, endY); + ratioX = (maxX - minX) / 2; + ratioY = (maxY - minY) / 2; + offsetX = -(maxX + minX) / 2; + offsetY = -(maxY + minY) / 2; + } + return { + ratioX, + ratioY, + offsetX, + offsetY + }; } class DoughnutController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.enableOptionSharing = true; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.offsetX = undefined; - this.offsetY = undefined; - } - linkScales() {} - parse(start, count) { - const data = this.getDataset().data; - const meta = this._cachedMeta; - if (this._parsing === false) { - meta._parsed = data; - } else { - let getter = (i) => +data[i]; - if (isObject(data[start])) { - const {key = 'value'} = this._parsing; - getter = (i) => +resolveObjectKey(data[i], key); - } - let i, ilen; - for (i = start, ilen = start + count; i < ilen; ++i) { - meta._parsed[i] = getter(i); - } - } - } - _getRotation() { - return toRadians(this.options.rotation - 90); - } - _getCircumference() { - return toRadians(this.options.circumference); - } - _getRotationExtents() { - let min = TAU; - let max = -TAU; - for (let i = 0; i < this.chart.data.datasets.length; ++i) { - if (this.chart.isDatasetVisible(i)) { - const controller = this.chart.getDatasetMeta(i).controller; - const rotation = controller._getRotation(); - const circumference = controller._getCircumference(); - min = Math.min(min, rotation); - max = Math.max(max, rotation + circumference); - } - } - return { - rotation: min, - circumference: max - min, - }; - } - update(mode) { - const chart = this.chart; - const {chartArea} = chart; - const meta = this._cachedMeta; - const arcs = meta.data; - const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; - const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); - const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); - const chartWeight = this._getRingWeight(this.index); - const {circumference, rotation} = this._getRotationExtents(); - const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout); - const maxWidth = (chartArea.width - spacing) / ratioX; - const maxHeight = (chartArea.height - spacing) / ratioY; - const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); - const outerRadius = toDimension(this.options.radius, maxRadius); - const innerRadius = Math.max(outerRadius * cutout, 0); - const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); - this.offsetX = offsetX * outerRadius; - this.offsetY = offsetY * outerRadius; - meta.total = this.calculateTotal(); - this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); - this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); - this.updateElements(arcs, 0, arcs.length, mode); - } - _circumference(i, reset) { - const opts = this.options; - const meta = this._cachedMeta; - const circumference = this._getCircumference(); - if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { - return 0; - } - return this.calculateCircumference(meta._parsed[i] * circumference / TAU); - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const animationOpts = opts.animation; - const centerX = (chartArea.left + chartArea.right) / 2; - const centerY = (chartArea.top + chartArea.bottom) / 2; - const animateScale = reset && animationOpts.animateScale; - const innerRadius = animateScale ? 0 : this.innerRadius; - const outerRadius = animateScale ? 0 : this.outerRadius; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - let startAngle = this._getRotation(); - let i; - for (i = 0; i < start; ++i) { - startAngle += this._circumference(i, reset); - } - for (i = start; i < start + count; ++i) { - const circumference = this._circumference(i, reset); - const arc = arcs[i]; - const properties = { - x: centerX + this.offsetX, - y: centerY + this.offsetY, - startAngle, - endAngle: startAngle + circumference, - circumference, - outerRadius, - innerRadius - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); - } - startAngle += circumference; - this.updateElement(arc, i, properties, mode); - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - calculateTotal() { - const meta = this._cachedMeta; - const metaData = meta.data; - let total = 0; - let i; - for (i = 0; i < metaData.length; i++) { - const value = meta._parsed[i]; - if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { - total += Math.abs(value); - } - } - return total; - } - calculateCircumference(value) { - const total = this._cachedMeta.total; - if (total > 0 && !isNaN(value)) { - return TAU * (Math.abs(value) / total); - } - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index], chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - getMaxBorderWidth(arcs) { - let max = 0; - const chart = this.chart; - let i, ilen, meta, controller, options; - if (!arcs) { - for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { - if (chart.isDatasetVisible(i)) { - meta = chart.getDatasetMeta(i); - arcs = meta.data; - controller = meta.controller; - break; - } - } - } - if (!arcs) { - return 0; - } - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - options = controller.resolveDataElementOptions(i); - if (options.borderAlign !== 'inner') { - max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); - } - } - return max; - } - getMaxOffset(arcs) { - let max = 0; - for (let i = 0, ilen = arcs.length; i < ilen; ++i) { - const options = this.resolveDataElementOptions(i); - max = Math.max(max, options.offset || 0, options.hoverOffset || 0); - } - return max; - } - _getRingWeightOffset(datasetIndex) { - let ringWeightOffset = 0; - for (let i = 0; i < datasetIndex; ++i) { - if (this.chart.isDatasetVisible(i)) { - ringWeightOffset += this._getRingWeight(i); - } - } - return ringWeightOffset; - } - _getRingWeight(datasetIndex) { - return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); - } - _getVisibleDatasetWeightTotal() { - return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; - } -} -DoughnutController.id = 'doughnut'; -DoughnutController.defaults = { - datasetElementType: false, - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: false - }, - animations: { - numbers: { - type: 'number', - properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing'] - }, - }, - cutout: '50%', - rotation: 0, - circumference: 360, - radius: '100%', - spacing: 0, - indexAxis: 'r', -}; -DoughnutController.descriptors = { - _scriptable: (name) => name !== 'spacing', - _indexable: (name) => name !== 'spacing', -}; -DoughnutController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; + static id = 'doughnut'; + static defaults = { + datasetElementType: false, + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: false }, - label(tooltipItem) { - let dataLabel = tooltipItem.label; - const value = ': ' + tooltipItem.formattedValue; - if (isArray(dataLabel)) { - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - return dataLabel; + animations: { + numbers: { + type: 'number', + properties: [ + 'circumference', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'startAngle', + 'x', + 'y', + 'offset', + 'borderWidth', + 'spacing' + ] + } + }, + cutout: '50%', + rotation: 0, + circumference: 360, + radius: '100%', + spacing: 0, + indexAxis: 'r' + }; + static descriptors = { + _scriptable: (name)=>name !== 'spacing', + _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash') + }; + static overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels (chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const { labels: { pointStyle , color } } = chart.legend.options; + return data.labels.map((label, i)=>{ + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + fontColor: color, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick (e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + } } - } + }; + constructor(chart, datasetIndex){ + super(chart, datasetIndex); + this.enableOptionSharing = true; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.offsetX = undefined; + this.offsetY = undefined; } - } -}; + linkScales() {} + parse(start, count) { + const data = this.getDataset().data; + const meta = this._cachedMeta; + if (this._parsing === false) { + meta._parsed = data; + } else { + let getter = (i)=>+data[i]; + if (isObject(data[start])) { + const { key ='value' } = this._parsing; + getter = (i)=>+resolveObjectKey(data[i], key); + } + let i, ilen; + for(i = start, ilen = start + count; i < ilen; ++i){ + meta._parsed[i] = getter(i); + } + } + } + _getRotation() { + return toRadians(this.options.rotation - 90); + } + _getCircumference() { + return toRadians(this.options.circumference); + } + _getRotationExtents() { + let min = TAU; + let max = -TAU; + for(let i = 0; i < this.chart.data.datasets.length; ++i){ + if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) { + const controller = this.chart.getDatasetMeta(i).controller; + const rotation = controller._getRotation(); + const circumference = controller._getCircumference(); + min = Math.min(min, rotation); + max = Math.max(max, rotation + circumference); + } + } + return { + rotation: min, + circumference: max - min + }; + } + update(mode) { + const chart = this.chart; + const { chartArea } = chart; + const meta = this._cachedMeta; + const arcs = meta.data; + const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; + const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); + const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); + const chartWeight = this._getRingWeight(this.index); + const { circumference , rotation } = this._getRotationExtents(); + const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout); + const maxWidth = (chartArea.width - spacing) / ratioX; + const maxHeight = (chartArea.height - spacing) / ratioY; + const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); + const outerRadius = toDimension(this.options.radius, maxRadius); + const innerRadius = Math.max(outerRadius * cutout, 0); + const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); + this.offsetX = offsetX * outerRadius; + this.offsetY = offsetY * outerRadius; + meta.total = this.calculateTotal(); + this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); + this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); + this.updateElements(arcs, 0, arcs.length, mode); + } + _circumference(i, reset) { + const opts = this.options; + const meta = this._cachedMeta; + const circumference = this._getCircumference(); + if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { + return 0; + } + return this.calculateCircumference(meta._parsed[i] * circumference / TAU); + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const animationOpts = opts.animation; + const centerX = (chartArea.left + chartArea.right) / 2; + const centerY = (chartArea.top + chartArea.bottom) / 2; + const animateScale = reset && animationOpts.animateScale; + const innerRadius = animateScale ? 0 : this.innerRadius; + const outerRadius = animateScale ? 0 : this.outerRadius; + const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); + let startAngle = this._getRotation(); + let i; + for(i = 0; i < start; ++i){ + startAngle += this._circumference(i, reset); + } + for(i = start; i < start + count; ++i){ + const circumference = this._circumference(i, reset); + const arc = arcs[i]; + const properties = { + x: centerX + this.offsetX, + y: centerY + this.offsetY, + startAngle, + endAngle: startAngle + circumference, + circumference, + outerRadius, + innerRadius + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); + } + startAngle += circumference; + this.updateElement(arc, i, properties, mode); + } + } + calculateTotal() { + const meta = this._cachedMeta; + const metaData = meta.data; + let total = 0; + let i; + for(i = 0; i < metaData.length; i++){ + const value = meta._parsed[i]; + if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { + total += Math.abs(value); + } + } + return total; + } + calculateCircumference(value) { + const total = this._cachedMeta.total; + if (total > 0 && !isNaN(value)) { + return TAU * (Math.abs(value) / total); + } + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index], chart.options.locale); + return { + label: labels[index] || '', + value + }; + } + getMaxBorderWidth(arcs) { + let max = 0; + const chart = this.chart; + let i, ilen, meta, controller, options; + if (!arcs) { + for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){ + if (chart.isDatasetVisible(i)) { + meta = chart.getDatasetMeta(i); + arcs = meta.data; + controller = meta.controller; + break; + } + } + } + if (!arcs) { + return 0; + } + for(i = 0, ilen = arcs.length; i < ilen; ++i){ + options = controller.resolveDataElementOptions(i); + if (options.borderAlign !== 'inner') { + max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); + } + } + return max; + } + getMaxOffset(arcs) { + let max = 0; + for(let i = 0, ilen = arcs.length; i < ilen; ++i){ + const options = this.resolveDataElementOptions(i); + max = Math.max(max, options.offset || 0, options.hoverOffset || 0); + } + return max; + } + _getRingWeightOffset(datasetIndex) { + let ringWeightOffset = 0; + for(let i = 0; i < datasetIndex; ++i){ + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + return ringWeightOffset; + } + _getRingWeight(datasetIndex) { + return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); + } + _getVisibleDatasetWeightTotal() { + return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; + } +} class LineController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - update(mode) { - const meta = this._cachedMeta; - const {dataset: line, data: points = [], _dataset} = meta; - const animationsDisabled = this.chart._animationsDisabled; - let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); - this._drawStart = start; - this._drawCount = count; - if (scaleRangesChanged(meta)) { - start = 0; - count = points.length; + static id = 'line'; + static defaults = { + datasetElementType: 'line', + dataElementType: 'point', + showLine: true, + spanGaps: false + }; + static overrides = { + scales: { + _index_: { + type: 'category' + }, + _value_: { + type: 'linear' + } + } + }; + initialize() { + this.enableOptionSharing = true; + this.supportsDecimation = true; + super.initialize(); } - line._chart = this.chart; - line._datasetIndex = this.index; - line._decimated = !!_dataset._decimated; - line.points = points; - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; + update(mode) { + const meta = this._cachedMeta; + const { dataset: line , data: points = [] , _dataset } = meta; + const animationsDisabled = this.chart._animationsDisabled; + let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); + this._drawStart = start; + this._drawCount = count; + if (_scaleRangesChanged(meta)) { + start = 0; + count = points.length; + } + line._chart = this.chart; + line._datasetIndex = this.index; + line._decimated = !!_dataset._decimated; + line.points = points; + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + options.segment = this.options.segment; + this.updateElement(line, undefined, { + animated: !animationsDisabled, + options + }, mode); + this.updateElements(points, start, count, mode); } - options.segment = this.options.segment; - this.updateElement(line, undefined, { - animated: !animationsDisabled, - options - }, mode); - this.updateElements(points, start, count, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale, _stacked, _dataset} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const {spanGaps, segment} = this.options; - const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; - const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; - let prevParsed = start > 0 && this.getParsed(start - 1); - for (let i = start; i < start + count; ++i) { - const point = points[i]; - const parsed = this.getParsed(i); - const properties = directUpdate ? point : {}; - const nullData = isNullOrUndef(parsed[vAxis]); - const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); - const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); - properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; - properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; - if (segment) { - properties.parsed = parsed; - properties.raw = _dataset.data[i]; - } - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); - } - if (!directUpdate) { - this.updateElement(point, i, properties, mode); - } - prevParsed = parsed; + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; + const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const { spanGaps , segment } = this.options; + const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; + const end = start + count; + const pointsCount = points.length; + let prevParsed = start > 0 && this.getParsed(start - 1); + for(let i = 0; i < pointsCount; ++i){ + const point = points[i]; + const properties = directUpdate ? point : {}; + if (i < start || i >= end) { + properties.skip = true; + continue; + } + const parsed = this.getParsed(i); + const nullData = isNullOrUndef(parsed[vAxis]); + const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); + const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); + properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; + properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; + if (segment) { + properties.parsed = parsed; + properties.raw = _dataset.data[i]; + } + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); + } + if (!directUpdate) { + this.updateElement(point, i, properties, mode); + } + prevParsed = parsed; + } } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - getMaxOverflow() { - const meta = this._cachedMeta; - const dataset = meta.dataset; - const border = dataset.options && dataset.options.borderWidth || 0; - const data = meta.data || []; - if (!data.length) { - return border; + getMaxOverflow() { + const meta = this._cachedMeta; + const dataset = meta.dataset; + const border = dataset.options && dataset.options.borderWidth || 0; + const data = meta.data || []; + if (!data.length) { + return border; + } + const firstPoint = data[0].size(this.resolveDataElementOptions(0)); + const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); + return Math.max(border, firstPoint, lastPoint) / 2; } - const firstPoint = data[0].size(this.resolveDataElementOptions(0)); - const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); - return Math.max(border, firstPoint, lastPoint) / 2; - } - draw() { - const meta = this._cachedMeta; - meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); - super.draw(); - } -} -LineController.id = 'line'; -LineController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - showLine: true, - spanGaps: false, -}; -LineController.overrides = { - scales: { - _index_: { - type: 'category', - }, - _value_: { - type: 'linear', - }, - } -}; -function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { - const pointCount = points.length; - let start = 0; - let count = pointCount; - if (meta._sorted) { - const {iScale, _parsed} = meta; - const axis = iScale.axis; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(Math.min( - _lookupByKey(_parsed, iScale.axis, min).lo, - animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), - 0, pointCount - 1); + draw() { + const meta = this._cachedMeta; + meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); + super.draw(); } - if (maxDefined) { - count = _limitValue(Math.max( - _lookupByKey(_parsed, iScale.axis, max).hi + 1, - animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), - start, pointCount) - start; - } else { - count = pointCount - start; - } - } - return {start, count}; -} -function scaleRangesChanged(meta) { - const {xScale, yScale, _scaleRanges} = meta; - const newRanges = { - xmin: xScale.min, - xmax: xScale.max, - ymin: yScale.min, - ymax: yScale.max - }; - if (!_scaleRanges) { - meta._scaleRanges = newRanges; - return true; - } - const changed = _scaleRanges.xmin !== xScale.min - || _scaleRanges.xmax !== xScale.max - || _scaleRanges.ymin !== yScale.min - || _scaleRanges.ymax !== yScale.max; - Object.assign(_scaleRanges, newRanges); - return changed; } class PolarAreaController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.innerRadius = undefined; - this.outerRadius = undefined; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index].r, chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - update(mode) { - const arcs = this._cachedMeta.data; - this._updateRadius(); - this.updateElements(arcs, 0, arcs.length, mode); - } - _updateRadius() { - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); - const outerRadius = Math.max(minSize / 2, 0); - const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); - const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); - this.outerRadius = outerRadius - (radiusLength * this.index); - this.innerRadius = this.outerRadius - radiusLength; - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const dataset = this.getDataset(); - const opts = chart.options; - const animationOpts = opts.animation; - const scale = this._cachedMeta.rScale; - const centerX = scale.xCenter; - const centerY = scale.yCenter; - const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; - let angle = datasetStartAngle; - let i; - const defaultAngle = 360 / this.countVisibleElements(); - for (i = 0; i < start; ++i) { - angle += this._computeAngle(i, mode, defaultAngle); - } - for (i = start; i < start + count; i++) { - const arc = arcs[i]; - let startAngle = angle; - let endAngle = angle + this._computeAngle(i, mode, defaultAngle); - let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; - angle = endAngle; - if (reset) { - if (animationOpts.animateScale) { - outerRadius = 0; - } - if (animationOpts.animateRotate) { - startAngle = endAngle = datasetStartAngle; - } - } - const properties = { - x: centerX, - y: centerY, - innerRadius: 0, - outerRadius, - startAngle, - endAngle, - options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) - }; - this.updateElement(arc, i, properties, mode); - } - } - countVisibleElements() { - const dataset = this.getDataset(); - const meta = this._cachedMeta; - let count = 0; - meta.data.forEach((element, index) => { - if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { - count++; - } - }); - return count; - } - _computeAngle(index, mode, defaultAngle) { - return this.chart.getDataVisibility(index) - ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) - : 0; - } -} -PolarAreaController.id = 'polarArea'; -PolarAreaController.defaults = { - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: true - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] - }, - }, - indexAxis: 'r', - startAngle: 0, -}; -PolarAreaController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; + static id = 'polarArea'; + static defaults = { + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: true }, - label(context) { - return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; + animations: { + numbers: { + type: 'number', + properties: [ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius' + ] + } + }, + indexAxis: 'r', + startAngle: 0 + }; + static overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels (chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const { labels: { pointStyle , color } } = chart.legend.options; + return data.labels.map((label, i)=>{ + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + fontColor: color, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick (e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + } + }, + scales: { + r: { + type: 'radialLinear', + angleLines: { + display: false + }, + beginAtZero: true, + grid: { + circular: true + }, + pointLabels: { + display: false + }, + startAngle: 0 + } } - } + }; + constructor(chart, datasetIndex){ + super(chart, datasetIndex); + this.innerRadius = undefined; + this.outerRadius = undefined; } - }, - scales: { - r: { - type: 'radialLinear', - angleLines: { - display: false - }, - beginAtZero: true, - grid: { - circular: true - }, - pointLabels: { - display: false - }, - startAngle: 0 + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index].r, chart.options.locale); + return { + label: labels[index] || '', + value + }; } - } -}; + parseObjectData(meta, data, start, count) { + return _parseObjectDataRadialScale.bind(this)(meta, data, start, count); + } + update(mode) { + const arcs = this._cachedMeta.data; + this._updateRadius(); + this.updateElements(arcs, 0, arcs.length, mode); + } + getMinMax() { + const meta = this._cachedMeta; + const range = { + min: Number.POSITIVE_INFINITY, + max: Number.NEGATIVE_INFINITY + }; + meta.data.forEach((element, index)=>{ + const parsed = this.getParsed(index).r; + if (!isNaN(parsed) && this.chart.getDataVisibility(index)) { + if (parsed < range.min) { + range.min = parsed; + } + if (parsed > range.max) { + range.max = parsed; + } + } + }); + return range; + } + _updateRadius() { + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + const outerRadius = Math.max(minSize / 2, 0); + const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0); + const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); + this.outerRadius = outerRadius - radiusLength * this.index; + this.innerRadius = this.outerRadius - radiusLength; + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const opts = chart.options; + const animationOpts = opts.animation; + const scale = this._cachedMeta.rScale; + const centerX = scale.xCenter; + const centerY = scale.yCenter; + const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; + let angle = datasetStartAngle; + let i; + const defaultAngle = 360 / this.countVisibleElements(); + for(i = 0; i < start; ++i){ + angle += this._computeAngle(i, mode, defaultAngle); + } + for(i = start; i < start + count; i++){ + const arc = arcs[i]; + let startAngle = angle; + let endAngle = angle + this._computeAngle(i, mode, defaultAngle); + let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0; + angle = endAngle; + if (reset) { + if (animationOpts.animateScale) { + outerRadius = 0; + } + if (animationOpts.animateRotate) { + startAngle = endAngle = datasetStartAngle; + } + } + const properties = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius, + startAngle, + endAngle, + options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) + }; + this.updateElement(arc, i, properties, mode); + } + } + countVisibleElements() { + const meta = this._cachedMeta; + let count = 0; + meta.data.forEach((element, index)=>{ + if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) { + count++; + } + }); + return count; + } + _computeAngle(index, mode, defaultAngle) { + return this.chart.getDataVisibility(index) ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0; + } +} class PieController extends DoughnutController { + static id = 'pie'; + static defaults = { + cutout: 0, + rotation: 0, + circumference: 360, + radius: '100%' + }; } -PieController.id = 'pie'; -PieController.defaults = { - cutout: 0, - rotation: 0, - circumference: 360, - radius: '100%' -}; class RadarController extends DatasetController { - getLabelAndValue(index) { - const vScale = this._cachedMeta.vScale; - const parsed = this.getParsed(index); - return { - label: vScale.getLabels()[index], - value: '' + vScale.getLabelForValue(parsed[vScale.axis]) - }; - } - update(mode) { - const meta = this._cachedMeta; - const line = meta.dataset; - const points = meta.data || []; - const labels = meta.iScale.getLabels(); - line.points = points; - if (mode !== 'resize') { - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; - } - const properties = { - _loop: true, - _fullLoop: labels.length === points.length, - options - }; - this.updateElement(line, undefined, properties, mode); - } - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const dataset = this.getDataset(); - const scale = this._cachedMeta.rScale; - const reset = mode === 'reset'; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); - const x = reset ? scale.xCenter : pointPosition.x; - const y = reset ? scale.yCenter : pointPosition.y; - const properties = { - x, - y, - angle: pointPosition.angle, - skip: isNaN(x) || isNaN(y), - options - }; - this.updateElement(point, i, properties, mode); - } - } -} -RadarController.id = 'radar'; -RadarController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - indexAxis: 'r', - showLine: true, - elements: { - line: { - fill: 'start' - } - }, -}; -RadarController.overrides = { - aspectRatio: 1, - scales: { - r: { - type: 'radialLinear', - } - } -}; - -class ScatterController extends LineController { -} -ScatterController.id = 'scatter'; -ScatterController.defaults = { - showLine: false, - fill: false -}; -ScatterController.overrides = { - interaction: { - mode: 'point' - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - }, - label(item) { - return '(' + item.label + ', ' + item.formattedValue + ')'; + static id = 'radar'; + static defaults = { + datasetElementType: 'line', + dataElementType: 'point', + indexAxis: 'r', + showLine: true, + elements: { + line: { + fill: 'start' + } } - } + }; + static overrides = { + aspectRatio: 1, + scales: { + r: { + type: 'radialLinear' + } + } + }; + getLabelAndValue(index) { + const vScale = this._cachedMeta.vScale; + const parsed = this.getParsed(index); + return { + label: vScale.getLabels()[index], + value: '' + vScale.getLabelForValue(parsed[vScale.axis]) + }; } - }, - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' + parseObjectData(meta, data, start, count) { + return _parseObjectDataRadialScale.bind(this)(meta, data, start, count); } - } -}; + update(mode) { + const meta = this._cachedMeta; + const line = meta.dataset; + const points = meta.data || []; + const labels = meta.iScale.getLabels(); + line.points = points; + if (mode !== 'resize') { + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + const properties = { + _loop: true, + _fullLoop: labels.length === points.length, + options + }; + this.updateElement(line, undefined, properties, mode); + } + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const scale = this._cachedMeta.rScale; + const reset = mode === 'reset'; + for(let i = start; i < start + count; i++){ + const point = points[i]; + const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); + const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r); + const x = reset ? scale.xCenter : pointPosition.x; + const y = reset ? scale.yCenter : pointPosition.y; + const properties = { + x, + y, + angle: pointPosition.angle, + skip: isNaN(x) || isNaN(y), + options + }; + this.updateElement(point, i, properties, mode); + } + } +} + +class ScatterController extends DatasetController { + static id = 'scatter'; + static defaults = { + datasetElementType: false, + dataElementType: 'point', + showLine: false, + fill: false + }; + static overrides = { + interaction: { + mode: 'point' + }, + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + } + }; + getLabelAndValue(index) { + const meta = this._cachedMeta; + const labels = this.chart.data.labels || []; + const { xScale , yScale } = meta; + const parsed = this.getParsed(index); + const x = xScale.getLabelForValue(parsed.x); + const y = yScale.getLabelForValue(parsed.y); + return { + label: labels[index] || '', + value: '(' + x + ', ' + y + ')' + }; + } + update(mode) { + const meta = this._cachedMeta; + const { data: points = [] } = meta; + const animationsDisabled = this.chart._animationsDisabled; + let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); + this._drawStart = start; + this._drawCount = count; + if (_scaleRangesChanged(meta)) { + start = 0; + count = points.length; + } + if (this.options.showLine) { + const { dataset: line , _dataset } = meta; + line._chart = this.chart; + line._datasetIndex = this.index; + line._decimated = !!_dataset._decimated; + line.points = points; + const options = this.resolveDatasetElementOptions(mode); + options.segment = this.options.segment; + this.updateElement(line, undefined, { + animated: !animationsDisabled, + options + }, mode); + } + this.updateElements(points, start, count, mode); + } + addElements() { + const { showLine } = this.options; + if (!this.datasetElementType && showLine) { + this.datasetElementType = this.chart.registry.getElement('line'); + } + super.addElements(); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const { spanGaps , segment } = this.options; + const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; + let prevParsed = start > 0 && this.getParsed(start - 1); + for(let i = start; i < start + count; ++i){ + const point = points[i]; + const parsed = this.getParsed(i); + const properties = directUpdate ? point : {}; + const nullData = isNullOrUndef(parsed[vAxis]); + const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); + const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); + properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; + properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; + if (segment) { + properties.parsed = parsed; + properties.raw = _dataset.data[i]; + } + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); + } + if (!directUpdate) { + this.updateElement(point, i, properties, mode); + } + prevParsed = parsed; + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + getMaxOverflow() { + const meta = this._cachedMeta; + const data = meta.data || []; + if (!this.options.showLine) { + let max = 0; + for(let i = data.length - 1; i >= 0; --i){ + max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); + } + return max > 0 && max; + } + const dataset = meta.dataset; + const border = dataset.options && dataset.options.borderWidth || 0; + if (!data.length) { + return border; + } + const firstPoint = data[0].size(this.resolveDataElementOptions(0)); + const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); + return Math.max(border, firstPoint, lastPoint) / 2; + } +} var controllers = /*#__PURE__*/Object.freeze({ __proto__: null, @@ -8772,4447 +2547,8861 @@ BarController: BarController, BubbleController: BubbleController, DoughnutController: DoughnutController, LineController: LineController, -PolarAreaController: PolarAreaController, PieController: PieController, +PolarAreaController: PolarAreaController, RadarController: RadarController, ScatterController: ScatterController }); -function clipArc(ctx, element, endAngle) { - const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; - let angleMargin = pixelMargin / outerRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); - if (innerRadius > pixelMargin) { - angleMargin = pixelMargin / innerRadius; - ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); - } else { - ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); - } - ctx.closePath(); - ctx.clip(); +/** + * @namespace Chart._adapters + * @since 2.8.0 + * @private + */ function abstract() { + throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); } -function toRadiusCorners(value) { - return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']); -} -function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { - const o = toRadiusCorners(arc.options.borderRadius); - const halfThickness = (outerRadius - innerRadius) / 2; - const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); - const computeOuterLimit = (val) => { - const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; - return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); - }; - return { - outerStart: computeOuterLimit(o.outerStart), - outerEnd: computeOuterLimit(o.outerEnd), - innerStart: _limitValue(o.innerStart, 0, innerLimit), - innerEnd: _limitValue(o.innerEnd, 0, innerLimit), - }; -} -function rThetaToXY(r, theta, x, y) { - return { - x: x + r * Math.cos(theta), - y: y + r * Math.sin(theta), - }; -} -function pathArc(ctx, element, offset, spacing, end) { - const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element; - const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); - const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; - let spacingOffset = 0; - const alpha = end - start; - if (spacing) { - const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; - const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; - const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; - const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha; - spacingOffset = (alpha - adjustedAngle) / 2; - } - const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; - const angleOffset = (alpha - beta) / 2; - const startAngle = start + angleOffset + spacingOffset; - const endAngle = end - angleOffset - spacingOffset; - const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); - const outerStartAdjustedRadius = outerRadius - outerStart; - const outerEndAdjustedRadius = outerRadius - outerEnd; - const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; - const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; - const innerStartAdjustedRadius = innerRadius + innerStart; - const innerEndAdjustedRadius = innerRadius + innerEnd; - const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; - const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle); - if (outerEnd > 0) { - const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); - } - const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); - ctx.lineTo(p4.x, p4.y); - if (innerEnd > 0) { - const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); - } - ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true); - if (innerStart > 0) { - const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); - } - const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); - ctx.lineTo(p8.x, p8.y); - if (outerStart > 0) { - const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); - } - ctx.closePath(); -} -function drawArc(ctx, element, offset, spacing) { - const {fullCircles, startAngle, circumference} = element; - let endAngle = element.endAngle; - if (fullCircles) { - pathArc(ctx, element, offset, spacing, startAngle + TAU); - for (let i = 0; i < fullCircles; ++i) { - ctx.fill(); +/** + * Date adapter (current used by the time scale) + * @namespace Chart._adapters._date + * @memberof Chart._adapters + * @private + */ class DateAdapterBase { + /** + * Override default date adapter methods. + * Accepts type parameter to define options type. + * @example + * Chart._adapters._date.override<{myAdapterOption: string}>({ + * init() { + * console.log(this.options.myAdapterOption); + * } + * }) + */ static override(members) { + Object.assign(DateAdapterBase.prototype, members); } - if (!isNaN(circumference)) { - endAngle = startAngle + circumference % TAU; - if (circumference % TAU === 0) { - endAngle += TAU; - } + options; + constructor(options){ + this.options = options || {}; } - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.fill(); - return endAngle; -} -function drawFullCircleBorders(ctx, element, inner) { - const {x, y, startAngle, pixelMargin, fullCircles} = element; - const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); - const innerRadius = element.innerRadius + pixelMargin; - let i; - if (inner) { - clipArc(ctx, element, startAngle + TAU); - } - ctx.beginPath(); - ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } -} -function drawBorder(ctx, element, offset, spacing, endAngle) { - const {options} = element; - const {borderWidth, borderJoinStyle} = options; - const inner = options.borderAlign === 'inner'; - if (!borderWidth) { - return; - } - if (inner) { - ctx.lineWidth = borderWidth * 2; - ctx.lineJoin = borderJoinStyle || 'round'; - } else { - ctx.lineWidth = borderWidth; - ctx.lineJoin = borderJoinStyle || 'bevel'; - } - if (element.fullCircles) { - drawFullCircleBorders(ctx, element, inner); - } - if (inner) { - clipArc(ctx, element, endAngle); - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.stroke(); -} -class ArcElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.circumference = undefined; - this.startAngle = undefined; - this.endAngle = undefined; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.pixelMargin = 0; - this.fullCircles = 0; - if (cfg) { - Object.assign(this, cfg); + // eslint-disable-next-line @typescript-eslint/no-empty-function + init() {} + formats() { + return abstract(); } - } - inRange(chartX, chartY, useFinalPosition) { - const point = this.getProps(['x', 'y'], useFinalPosition); - const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); - const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference' - ], useFinalPosition); - const rAdjust = this.options.spacing / 2; - const _circumference = valueOrDefault(circumference, endAngle - startAngle); - const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); - const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); - return (betweenAngles && withinRadius); - } - getCenterPoint(useFinalPosition) { - const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ - 'x', - 'y', - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference', - ], useFinalPosition); - const {offset, spacing} = this.options; - const halfAngle = (startAngle + endAngle) / 2; - const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; - return { - x: x + Math.cos(halfAngle) * halfRadius, - y: y + Math.sin(halfAngle) * halfRadius - }; - } - tooltipPosition(useFinalPosition) { - return this.getCenterPoint(useFinalPosition); - } - draw(ctx) { - const {options, circumference} = this; - const offset = (options.offset || 0) / 2; - const spacing = (options.spacing || 0) / 2; - this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; - this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; - if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { - return; + parse() { + return abstract(); } - ctx.save(); - let radiusOffset = 0; - if (offset) { - radiusOffset = offset / 2; - const halfAngle = (this.startAngle + this.endAngle) / 2; - ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset); - if (this.circumference >= PI) { - radiusOffset = offset; - } + format() { + return abstract(); + } + add() { + return abstract(); + } + diff() { + return abstract(); + } + startOf() { + return abstract(); + } + endOf() { + return abstract(); } - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - const endAngle = drawArc(ctx, this, radiusOffset, spacing); - drawBorder(ctx, this, radiusOffset, spacing, endAngle); - ctx.restore(); - } } -ArcElement.id = 'arc'; -ArcElement.defaults = { - borderAlign: 'center', - borderColor: '#fff', - borderJoinStyle: undefined, - borderRadius: 0, - borderWidth: 2, - offset: 0, - spacing: 0, - angle: undefined, -}; -ArcElement.defaultRoutes = { - backgroundColor: 'backgroundColor' +var adapters = { + _date: DateAdapterBase }; +function binarySearch(metaset, axis, value, intersect) { + const { controller , data , _sorted } = metaset; + const iScale = controller._cachedMeta.iScale; + if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { + const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; + if (!intersect) { + return lookupMethod(data, axis, value); + } else if (controller._sharedOptions) { + const el = data[0]; + const range = typeof el.getRange === 'function' && el.getRange(axis); + if (range) { + const start = lookupMethod(data, axis, value - range); + const end = lookupMethod(data, axis, value + range); + return { + lo: start.lo, + hi: end.hi + }; + } + } + } + return { + lo: 0, + hi: data.length - 1 + }; +} + function evaluateInteractionItems(chart, axis, position, handler, intersect) { + const metasets = chart.getSortedVisibleDatasetMetas(); + const value = position[axis]; + for(let i = 0, ilen = metasets.length; i < ilen; ++i){ + const { index , data } = metasets[i]; + const { lo , hi } = binarySearch(metasets[i], axis, value, intersect); + for(let j = lo; j <= hi; ++j){ + const element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} + function getDistanceMetricForAxis(axis) { + const useX = axis.indexOf('x') !== -1; + const useY = axis.indexOf('y') !== -1; + return function(pt1, pt2) { + const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} + function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) { + const items = []; + if (!includeInvisible && !chart.isPointInArea(position)) { + return items; + } + const evaluationFunc = function(element, datasetIndex, index) { + if (!includeInvisible && !_isPointInArea(element, chart.chartArea, 0)) { + return; + } + if (element.inRange(position.x, position.y, useFinalPosition)) { + items.push({ + element, + datasetIndex, + index + }); + } + }; + evaluateInteractionItems(chart, axis, position, evaluationFunc, true); + return items; +} + function getNearestRadialItems(chart, position, axis, useFinalPosition) { + let items = []; + function evaluationFunc(element, datasetIndex, index) { + const { startAngle , endAngle } = element.getProps([ + 'startAngle', + 'endAngle' + ], useFinalPosition); + const { angle } = getAngleFromPoint(element, { + x: position.x, + y: position.y + }); + if (_angleBetween(angle, startAngle, endAngle)) { + items.push({ + element, + datasetIndex, + index + }); + } + } + evaluateInteractionItems(chart, axis, position, evaluationFunc); + return items; +} + function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { + let items = []; + const distanceMetric = getDistanceMetricForAxis(axis); + let minDistance = Number.POSITIVE_INFINITY; + function evaluationFunc(element, datasetIndex, index) { + const inRange = element.inRange(position.x, position.y, useFinalPosition); + if (intersect && !inRange) { + return; + } + const center = element.getCenterPoint(useFinalPosition); + const pointInArea = !!includeInvisible || chart.isPointInArea(center); + if (!pointInArea && !inRange) { + return; + } + const distance = distanceMetric(position, center); + if (distance < minDistance) { + items = [ + { + element, + datasetIndex, + index + } + ]; + minDistance = distance; + } else if (distance === minDistance) { + items.push({ + element, + datasetIndex, + index + }); + } + } + evaluateInteractionItems(chart, axis, position, evaluationFunc); + return items; +} + function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { + if (!includeInvisible && !chart.isPointInArea(position)) { + return []; + } + return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible); +} + function getAxisItems(chart, position, axis, intersect, useFinalPosition) { + const items = []; + const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; + let intersectsItem = false; + evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{ + if (element[rangeMethod](position[axis], useFinalPosition)) { + items.push({ + element, + datasetIndex, + index + }); + intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition); + } + }); + if (intersect && !intersectsItem) { + return []; + } + return items; +} + var Interaction = { + evaluateInteractionItems, + modes: { + index (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'x'; + const includeInvisible = options.includeInvisible || false; + const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); + const elements = []; + if (!items.length) { + return []; + } + chart.getSortedVisibleDatasetMetas().forEach((meta)=>{ + const index = items[0].index; + const element = meta.data[index]; + if (element && !element.skip) { + elements.push({ + element, + datasetIndex: meta.index, + index + }); + } + }); + return elements; + }, + dataset (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + const includeInvisible = options.includeInvisible || false; + let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); + if (items.length > 0) { + const datasetIndex = items[0].datasetIndex; + const data = chart.getDatasetMeta(datasetIndex).data; + items = []; + for(let i = 0; i < data.length; ++i){ + items.push({ + element: data[i], + datasetIndex, + index: i + }); + } + } + return items; + }, + point (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + const includeInvisible = options.includeInvisible || false; + return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible); + }, + nearest (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + const includeInvisible = options.includeInvisible || false; + return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible); + }, + x (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition); + }, + y (chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition); + } + } +}; + +const STATIC_POSITIONS = [ + 'left', + 'top', + 'right', + 'bottom' +]; +function filterByPosition(array, position) { + return array.filter((v)=>v.pos === position); +} +function filterDynamicPositionByAxis(array, axis) { + return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); +} +function sortByWeight(array, reverse) { + return array.sort((a, b)=>{ + const v0 = reverse ? b : a; + const v1 = reverse ? a : b; + return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight; + }); +} +function wrapBoxes(boxes) { + const layoutBoxes = []; + let i, ilen, box, pos, stack, stackWeight; + for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){ + box = boxes[i]; + ({ position: pos , options: { stack , stackWeight =1 } } = box); + layoutBoxes.push({ + index: i, + box, + pos, + horizontal: box.isHorizontal(), + weight: box.weight, + stack: stack && pos + stack, + stackWeight + }); + } + return layoutBoxes; +} +function buildStacks(layouts) { + const stacks = {}; + for (const wrap of layouts){ + const { stack , pos , stackWeight } = wrap; + if (!stack || !STATIC_POSITIONS.includes(pos)) { + continue; + } + const _stack = stacks[stack] || (stacks[stack] = { + count: 0, + placed: 0, + weight: 0, + size: 0 + }); + _stack.count++; + _stack.weight += stackWeight; + } + return stacks; +} + function setLayoutDims(layouts, params) { + const stacks = buildStacks(layouts); + const { vBoxMaxWidth , hBoxMaxHeight } = params; + let i, ilen, layout; + for(i = 0, ilen = layouts.length; i < ilen; ++i){ + layout = layouts[i]; + const { fullSize } = layout.box; + const stack = stacks[layout.stack]; + const factor = stack && layout.stackWeight / stack.weight; + if (layout.horizontal) { + layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; + layout.height = hBoxMaxHeight; + } else { + layout.width = vBoxMaxWidth; + layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; + } + } + return stacks; +} +function buildLayoutBoxes(boxes) { + const layoutBoxes = wrapBoxes(boxes); + const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true); + const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); + const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); + const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); + const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); + const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); + const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); + return { + fullSize, + leftAndTop: left.concat(top), + rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), + chartArea: filterByPosition(layoutBoxes, 'chartArea'), + vertical: left.concat(right).concat(centerVertical), + horizontal: top.concat(bottom).concat(centerHorizontal) + }; +} +function getCombinedMax(maxPadding, chartArea, a, b) { + return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); +} +function updateMaxPadding(maxPadding, boxPadding) { + maxPadding.top = Math.max(maxPadding.top, boxPadding.top); + maxPadding.left = Math.max(maxPadding.left, boxPadding.left); + maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); + maxPadding.right = Math.max(maxPadding.right, boxPadding.right); +} +function updateDims(chartArea, params, layout, stacks) { + const { pos , box } = layout; + const maxPadding = chartArea.maxPadding; + if (!isObject(pos)) { + if (layout.size) { + chartArea[pos] -= layout.size; + } + const stack = stacks[layout.stack] || { + size: 0, + count: 1 + }; + stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); + layout.size = stack.size / stack.count; + chartArea[pos] += layout.size; + } + if (box.getPadding) { + updateMaxPadding(maxPadding, box.getPadding()); + } + const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); + const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); + const widthChanged = newWidth !== chartArea.w; + const heightChanged = newHeight !== chartArea.h; + chartArea.w = newWidth; + chartArea.h = newHeight; + return layout.horizontal ? { + same: widthChanged, + other: heightChanged + } : { + same: heightChanged, + other: widthChanged + }; +} +function handleMaxPadding(chartArea) { + const maxPadding = chartArea.maxPadding; + function updatePos(pos) { + const change = Math.max(maxPadding[pos] - chartArea[pos], 0); + chartArea[pos] += change; + return change; + } + chartArea.y += updatePos('top'); + chartArea.x += updatePos('left'); + updatePos('right'); + updatePos('bottom'); +} +function getMargins(horizontal, chartArea) { + const maxPadding = chartArea.maxPadding; + function marginForPositions(positions) { + const margin = { + left: 0, + top: 0, + right: 0, + bottom: 0 + }; + positions.forEach((pos)=>{ + margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); + }); + return margin; + } + return horizontal ? marginForPositions([ + 'left', + 'right' + ]) : marginForPositions([ + 'top', + 'bottom' + ]); +} +function fitBoxes(boxes, chartArea, params, stacks) { + const refitBoxes = []; + let i, ilen, layout, box, refit, changed; + for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){ + layout = boxes[i]; + box = layout.box; + box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea)); + const { same , other } = updateDims(chartArea, params, layout, stacks); + refit |= same && refitBoxes.length; + changed = changed || other; + if (!box.fullSize) { + refitBoxes.push(layout); + } + } + return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; +} +function setBoxDims(box, left, top, width, height) { + box.top = top; + box.left = left; + box.right = left + width; + box.bottom = top + height; + box.width = width; + box.height = height; +} +function placeBoxes(boxes, chartArea, params, stacks) { + const userPadding = params.padding; + let { x , y } = chartArea; + for (const layout of boxes){ + const box = layout.box; + const stack = stacks[layout.stack] || { + count: 1, + placed: 0, + weight: 1 + }; + const weight = layout.stackWeight / stack.weight || 1; + if (layout.horizontal) { + const width = chartArea.w * weight; + const height = stack.size || box.height; + if (defined(stack.start)) { + y = stack.start; + } + if (box.fullSize) { + setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); + } else { + setBoxDims(box, chartArea.left + stack.placed, y, width, height); + } + stack.start = y; + stack.placed += width; + y = box.bottom; + } else { + const height = chartArea.h * weight; + const width = stack.size || box.width; + if (defined(stack.start)) { + x = stack.start; + } + if (box.fullSize) { + setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); + } else { + setBoxDims(box, x, chartArea.top + stack.placed, width, height); + } + stack.start = x; + stack.placed += height; + x = box.right; + } + } + chartArea.x = x; + chartArea.y = y; +} +var layouts = { + addBox (chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + item.fullSize = item.fullSize || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + item._layers = item._layers || function() { + return [ + { + z: 0, + draw (chartArea) { + item.draw(chartArea); + } + } + ]; + }; + chart.boxes.push(item); + }, + removeBox (chart, layoutItem) { + const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + configure (chart, item, options) { + item.fullSize = options.fullSize; + item.position = options.position; + item.weight = options.weight; + }, + update (chart, width, height, minPadding) { + if (!chart) { + return; + } + const padding = toPadding(chart.options.layout.padding); + const availableWidth = Math.max(width - padding.width, 0); + const availableHeight = Math.max(height - padding.height, 0); + const boxes = buildLayoutBoxes(chart.boxes); + const verticalBoxes = boxes.vertical; + const horizontalBoxes = boxes.horizontal; + each(chart.boxes, (box)=>{ + if (typeof box.beforeLayout === 'function') { + box.beforeLayout(); + } + }); + const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; + const params = Object.freeze({ + outerWidth: width, + outerHeight: height, + padding, + availableWidth, + availableHeight, + vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, + hBoxMaxHeight: availableHeight / 2 + }); + const maxPadding = Object.assign({}, padding); + updateMaxPadding(maxPadding, toPadding(minPadding)); + const chartArea = Object.assign({ + maxPadding, + w: availableWidth, + h: availableHeight, + x: padding.left, + y: padding.top + }, padding); + const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); + fitBoxes(boxes.fullSize, chartArea, params, stacks); + fitBoxes(verticalBoxes, chartArea, params, stacks); + if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { + fitBoxes(verticalBoxes, chartArea, params, stacks); + } + handleMaxPadding(chartArea); + placeBoxes(boxes.leftAndTop, chartArea, params, stacks); + chartArea.x += chartArea.w; + chartArea.y += chartArea.h; + placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); + chart.chartArea = { + left: chartArea.left, + top: chartArea.top, + right: chartArea.left + chartArea.w, + bottom: chartArea.top + chartArea.h, + height: chartArea.h, + width: chartArea.w + }; + each(boxes.chartArea, (layout)=>{ + const box = layout.box; + Object.assign(box, chart.chartArea); + box.update(chartArea.w, chartArea.h, { + left: 0, + top: 0, + right: 0, + bottom: 0 + }); + }); + } +}; + +class BasePlatform { + acquireContext(canvas, aspectRatio) {} + releaseContext(context) { + return false; + } + addEventListener(chart, type, listener) {} + removeEventListener(chart, type, listener) {} + getDevicePixelRatio() { + return 1; + } + getMaximumSize(element, width, height, aspectRatio) { + width = Math.max(0, width || element.width); + height = height || element.height; + return { + width, + height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) + }; + } + isAttached(canvas) { + return true; + } + updateConfig(config) { + } +} + +class BasicPlatform extends BasePlatform { + acquireContext(item) { + return item && item.getContext && item.getContext('2d') || null; + } + updateConfig(config) { + config.options.animation = false; + } +} + +const EXPANDO_KEY = '$chartjs'; + const EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; +const isNullOrEmpty = (value)=>value === null || value === ''; + function initCanvas(canvas, aspectRatio) { + const style = canvas.style; + const renderHeight = canvas.getAttribute('height'); + const renderWidth = canvas.getAttribute('width'); + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + style.display = style.display || 'block'; + style.boxSizing = style.boxSizing || 'border-box'; + if (isNullOrEmpty(renderWidth)) { + const displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + if (isNullOrEmpty(renderHeight)) { + if (canvas.style.height === '') { + canvas.height = canvas.width / (aspectRatio || 2); + } else { + const displayHeight = readUsedSize(canvas, 'height'); + if (displayHeight !== undefined) { + canvas.height = displayHeight; + } + } + } + return canvas; +} +const eventListenerOptions = supportsEventListenerOptions ? { + passive: true +} : false; +function addListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} +function removeListener(chart, type, listener) { + chart.canvas.removeEventListener(type, listener, eventListenerOptions); +} +function fromNativeEvent(event, chart) { + const type = EVENT_TYPES[event.type] || event.type; + const { x , y } = getRelativePosition(event, chart); + return { + type, + chart, + native: event, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null + }; +} +function nodeListContains(nodeList, canvas) { + for (const node of nodeList){ + if (node === canvas || node.contains(canvas)) { + return true; + } + } +} +function createAttachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver((entries)=>{ + let trigger = false; + for (const entry of entries){ + trigger = trigger || nodeListContains(entry.addedNodes, canvas); + trigger = trigger && !nodeListContains(entry.removedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, { + childList: true, + subtree: true + }); + return observer; +} +function createDetachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver((entries)=>{ + let trigger = false; + for (const entry of entries){ + trigger = trigger || nodeListContains(entry.removedNodes, canvas); + trigger = trigger && !nodeListContains(entry.addedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, { + childList: true, + subtree: true + }); + return observer; +} +const drpListeningCharts = new Map(); +let oldDevicePixelRatio = 0; +function onWindowResize() { + const dpr = window.devicePixelRatio; + if (dpr === oldDevicePixelRatio) { + return; + } + oldDevicePixelRatio = dpr; + drpListeningCharts.forEach((resize, chart)=>{ + if (chart.currentDevicePixelRatio !== dpr) { + resize(); + } + }); +} +function listenDevicePixelRatioChanges(chart, resize) { + if (!drpListeningCharts.size) { + window.addEventListener('resize', onWindowResize); + } + drpListeningCharts.set(chart, resize); +} +function unlistenDevicePixelRatioChanges(chart) { + drpListeningCharts.delete(chart); + if (!drpListeningCharts.size) { + window.removeEventListener('resize', onWindowResize); + } +} +function createResizeObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + const resize = throttled((width, height)=>{ + const w = container.clientWidth; + listener(width, height); + if (w < container.clientWidth) { + listener(); + } + }, window); + const observer = new ResizeObserver((entries)=>{ + const entry = entries[0]; + const width = entry.contentRect.width; + const height = entry.contentRect.height; + if (width === 0 && height === 0) { + return; + } + resize(width, height); + }); + observer.observe(container); + listenDevicePixelRatioChanges(chart, resize); + return observer; +} +function releaseObserver(chart, type, observer) { + if (observer) { + observer.disconnect(); + } + if (type === 'resize') { + unlistenDevicePixelRatioChanges(chart); + } +} +function createProxyAndListen(chart, type, listener) { + const canvas = chart.canvas; + const proxy = throttled((event)=>{ + if (chart.ctx !== null) { + listener(fromNativeEvent(event, chart)); + } + }, chart); + addListener(canvas, type, proxy); + return proxy; +} + class DomPlatform extends BasePlatform { + acquireContext(canvas, aspectRatio) { + const context = canvas && canvas.getContext && canvas.getContext('2d'); + if (context && context.canvas === canvas) { + initCanvas(canvas, aspectRatio); + return context; + } + return null; + } + releaseContext(context) { + const canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return false; + } + const initial = canvas[EXPANDO_KEY].initial; + [ + 'height', + 'width' + ].forEach((prop)=>{ + const value = initial[prop]; + if (isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + const style = initial.style || {}; + Object.keys(style).forEach((key)=>{ + canvas.style[key] = style[key]; + }); + canvas.width = canvas.width; + delete canvas[EXPANDO_KEY]; + return true; + } + addEventListener(chart, type, listener) { + this.removeEventListener(chart, type); + const proxies = chart.$proxies || (chart.$proxies = {}); + const handlers = { + attach: createAttachObserver, + detach: createDetachObserver, + resize: createResizeObserver + }; + const handler = handlers[type] || createProxyAndListen; + proxies[type] = handler(chart, type, listener); + } + removeEventListener(chart, type) { + const proxies = chart.$proxies || (chart.$proxies = {}); + const proxy = proxies[type]; + if (!proxy) { + return; + } + const handlers = { + attach: releaseObserver, + detach: releaseObserver, + resize: releaseObserver + }; + const handler = handlers[type] || removeListener; + handler(chart, type, proxy); + proxies[type] = undefined; + } + getDevicePixelRatio() { + return window.devicePixelRatio; + } + getMaximumSize(canvas, width, height, aspectRatio) { + return getMaximumSize(canvas, width, height, aspectRatio); + } + isAttached(canvas) { + const container = _getParentNode(canvas); + return !!(container && container.isConnected); + } +} + +function _detectPlatform(canvas) { + if (!_isDomSupported() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) { + return BasicPlatform; + } + return DomPlatform; +} + +class Element { + static defaults = {}; + static defaultRoutes = undefined; + x; + y; + active = false; + options; + $animations; + tooltipPosition(useFinalPosition) { + const { x , y } = this.getProps([ + 'x', + 'y' + ], useFinalPosition); + return { + x, + y + }; + } + hasValue() { + return isNumber(this.x) && isNumber(this.y); + } + getProps(props, final) { + const anims = this.$animations; + if (!final || !anims) { + // let's not create an object, if not needed + return this; + } + const ret = {}; + props.forEach((prop)=>{ + ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; + }); + return ret; + } +} + +function autoSkip(scale, ticks) { + const tickOpts = scale.options.ticks; + const determinedMaxTicks = determineMaxTicks(scale); + const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks); + const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; + const numMajorIndices = majorIndices.length; + const first = majorIndices[0]; + const last = majorIndices[numMajorIndices - 1]; + const newTicks = []; + if (numMajorIndices > ticksLimit) { + skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); + return newTicks; + } + const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); + if (numMajorIndices > 0) { + let i, ilen; + const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; + skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); + for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){ + skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); + } + skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); + return newTicks; + } + skip(ticks, newTicks, spacing); + return newTicks; +} +function determineMaxTicks(scale) { + const offset = scale.options.offset; + const tickLength = scale._tickSize(); + const maxScale = scale._length / tickLength + (offset ? 0 : 1); + const maxChart = scale._maxLength / tickLength; + return Math.floor(Math.min(maxScale, maxChart)); +} + function calculateSpacing(majorIndices, ticks, ticksLimit) { + const evenMajorSpacing = getEvenSpacing(majorIndices); + const spacing = ticks.length / ticksLimit; + if (!evenMajorSpacing) { + return Math.max(spacing, 1); + } + const factors = _factorize(evenMajorSpacing); + for(let i = 0, ilen = factors.length - 1; i < ilen; i++){ + const factor = factors[i]; + if (factor > spacing) { + return factor; + } + } + return Math.max(spacing, 1); +} + function getMajorIndices(ticks) { + const result = []; + let i, ilen; + for(i = 0, ilen = ticks.length; i < ilen; i++){ + if (ticks[i].major) { + result.push(i); + } + } + return result; +} + function skipMajors(ticks, newTicks, majorIndices, spacing) { + let count = 0; + let next = majorIndices[0]; + let i; + spacing = Math.ceil(spacing); + for(i = 0; i < ticks.length; i++){ + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = majorIndices[count * spacing]; + } + } +} + function skip(ticks, newTicks, spacing, majorStart, majorEnd) { + const start = valueOrDefault(majorStart, 0); + const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); + let count = 0; + let length, i, next; + spacing = Math.ceil(spacing); + if (majorEnd) { + length = majorEnd - majorStart; + spacing = length / Math.floor(length / spacing); + } + next = start; + while(next < 0){ + count++; + next = Math.round(start + count * spacing); + } + for(i = Math.max(start, 0); i < end; i++){ + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = Math.round(start + count * spacing); + } + } +} + function getEvenSpacing(arr) { + const len = arr.length; + let i, diff; + if (len < 2) { + return false; + } + for(diff = arr[0], i = 1; i < len; ++i){ + if (arr[i] - arr[i - 1] !== diff) { + return false; + } + } + return diff; +} + +const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align; +const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; +const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength); + function sample(arr, numItems) { + const result = []; + const increment = arr.length / numItems; + const len = arr.length; + let i = 0; + for(; i < len; i += increment){ + result.push(arr[Math.floor(i)]); + } + return result; +} + function getPixelForGridLine(scale, index, offsetGridLines) { + const length = scale.ticks.length; + const validIndex = Math.min(index, length - 1); + const start = scale._startPixel; + const end = scale._endPixel; + const epsilon = 1e-6; + let lineValue = scale.getPixelForTick(validIndex); + let offset; + if (offsetGridLines) { + if (length === 1) { + offset = Math.max(lineValue - start, end - lineValue); + } else if (index === 0) { + offset = (scale.getPixelForTick(1) - lineValue) / 2; + } else { + offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; + } + lineValue += validIndex < index ? offset : -offset; + if (lineValue < start - epsilon || lineValue > end + epsilon) { + return; + } + } + return lineValue; +} + function garbageCollect(caches, length) { + each(caches, (cache)=>{ + const gc = cache.gc; + const gcLen = gc.length / 2; + let i; + if (gcLen > length) { + for(i = 0; i < gcLen; ++i){ + delete cache.data[gc[i]]; + } + gc.splice(0, gcLen); + } + }); +} + function getTickMarkLength(options) { + return options.drawTicks ? options.tickLength : 0; +} + function getTitleHeight(options, fallback) { + if (!options.display) { + return 0; + } + const font = toFont(options.font, fallback); + const padding = toPadding(options.padding); + const lines = isArray(options.text) ? options.text.length : 1; + return lines * font.lineHeight + padding.height; +} +function createScaleContext(parent, scale) { + return createContext(parent, { + scale, + type: 'scale' + }); +} +function createTickContext(parent, index, tick) { + return createContext(parent, { + tick, + index, + type: 'tick' + }); +} +function titleAlign(align, position, reverse) { + let ret = _toLeftRightCenter(align); + if (reverse && position !== 'right' || !reverse && position === 'right') { + ret = reverseAlign(ret); + } + return ret; +} +function titleArgs(scale, offset, position, align) { + const { top , left , bottom , right , chart } = scale; + const { chartArea , scales } = chart; + let rotation = 0; + let maxWidth, titleX, titleY; + const height = bottom - top; + const width = right - left; + if (scale.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; + } else if (position === 'center') { + titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; + } else { + titleY = offsetFromEdge(scale, position, offset); + } + maxWidth = right - left; + } else { + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; + } else if (position === 'center') { + titleX = (chartArea.left + chartArea.right) / 2 - width + offset; + } else { + titleX = offsetFromEdge(scale, position, offset); + } + titleY = _alignStartEnd(align, bottom, top); + rotation = position === 'left' ? -HALF_PI : HALF_PI; + } + return { + titleX, + titleY, + maxWidth, + rotation + }; +} +class Scale extends Element { + constructor(cfg){ + super(); + this.id = cfg.id; + this.type = cfg.type; + this.options = undefined; + this.ctx = cfg.ctx; + this.chart = cfg.chart; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this._margins = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + this.maxWidth = undefined; + this.maxHeight = undefined; + this.paddingTop = undefined; + this.paddingBottom = undefined; + this.paddingLeft = undefined; + this.paddingRight = undefined; + this.axis = undefined; + this.labelRotation = undefined; + this.min = undefined; + this.max = undefined; + this._range = undefined; + this.ticks = []; + this._gridLineItems = null; + this._labelItems = null; + this._labelSizes = null; + this._length = 0; + this._maxLength = 0; + this._longestTextCache = {}; + this._startPixel = undefined; + this._endPixel = undefined; + this._reversePixels = false; + this._userMax = undefined; + this._userMin = undefined; + this._suggestedMax = undefined; + this._suggestedMin = undefined; + this._ticksLength = 0; + this._borderValue = 0; + this._cache = {}; + this._dataLimitsCached = false; + this.$context = undefined; + } + init(options) { + this.options = options.setContext(this.getContext()); + this.axis = options.axis; + this._userMin = this.parse(options.min); + this._userMax = this.parse(options.max); + this._suggestedMin = this.parse(options.suggestedMin); + this._suggestedMax = this.parse(options.suggestedMax); + } + parse(raw, index) { + return raw; + } + getUserBounds() { + let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this; + _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); + _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); + _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); + _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); + return { + min: finiteOrDefault(_userMin, _suggestedMin), + max: finiteOrDefault(_userMax, _suggestedMax), + minDefined: isNumberFinite(_userMin), + maxDefined: isNumberFinite(_userMax) + }; + } + getMinMax(canStack) { + let { min , max , minDefined , maxDefined } = this.getUserBounds(); + let range; + if (minDefined && maxDefined) { + return { + min, + max + }; + } + const metas = this.getMatchingVisibleMetas(); + for(let i = 0, ilen = metas.length; i < ilen; ++i){ + range = metas[i].controller.getMinMax(this, canStack); + if (!minDefined) { + min = Math.min(min, range.min); + } + if (!maxDefined) { + max = Math.max(max, range.max); + } + } + min = maxDefined && min > max ? max : min; + max = minDefined && min > max ? min : max; + return { + min: finiteOrDefault(min, finiteOrDefault(max, min)), + max: finiteOrDefault(max, finiteOrDefault(min, max)) + }; + } + getPadding() { + return { + left: this.paddingLeft || 0, + top: this.paddingTop || 0, + right: this.paddingRight || 0, + bottom: this.paddingBottom || 0 + }; + } + getTicks() { + return this.ticks; + } + getLabels() { + const data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; + } + getLabelItems(chartArea = this.chart.chartArea) { + const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); + return items; + } + beforeLayout() { + this._cache = {}; + this._dataLimitsCached = false; + } + beforeUpdate() { + callback(this.options.beforeUpdate, [ + this + ]); + } + update(maxWidth, maxHeight, margins) { + const { beginAtZero , grace , ticks: tickOpts } = this.options; + const sampleSize = tickOpts.sampleSize; + this.beforeUpdate(); + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins = Object.assign({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + this.ticks = null; + this._labelSizes = null; + this._gridLineItems = null; + this._labelItems = null; + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom; + if (!this._dataLimitsCached) { + this.beforeDataLimits(); + this.determineDataLimits(); + this.afterDataLimits(); + this._range = _addGrace(this, grace, beginAtZero); + this._dataLimitsCached = true; + } + this.beforeBuildTicks(); + this.ticks = this.buildTicks() || []; + this.afterBuildTicks(); + const samplingEnabled = sampleSize < this.ticks.length; + this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); + this.configure(); + this.beforeCalculateLabelRotation(); + this.calculateLabelRotation(); + this.afterCalculateLabelRotation(); + if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { + this.ticks = autoSkip(this, this.ticks); + this._labelSizes = null; + this.afterAutoSkip(); + } + if (samplingEnabled) { + this._convertTicksToLabels(this.ticks); + } + this.beforeFit(); + this.fit(); + this.afterFit(); + this.afterUpdate(); + } + configure() { + let reversePixels = this.options.reverse; + let startPixel, endPixel; + if (this.isHorizontal()) { + startPixel = this.left; + endPixel = this.right; + } else { + startPixel = this.top; + endPixel = this.bottom; + reversePixels = !reversePixels; + } + this._startPixel = startPixel; + this._endPixel = endPixel; + this._reversePixels = reversePixels; + this._length = endPixel - startPixel; + this._alignToPixels = this.options.alignToPixels; + } + afterUpdate() { + callback(this.options.afterUpdate, [ + this + ]); + } + beforeSetDimensions() { + callback(this.options.beforeSetDimensions, [ + this + ]); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = 0; + this.bottom = this.height; + } + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + } + afterSetDimensions() { + callback(this.options.afterSetDimensions, [ + this + ]); + } + _callHooks(name) { + this.chart.notifyPlugins(name, this.getContext()); + callback(this.options[name], [ + this + ]); + } + beforeDataLimits() { + this._callHooks('beforeDataLimits'); + } + determineDataLimits() {} + afterDataLimits() { + this._callHooks('afterDataLimits'); + } + beforeBuildTicks() { + this._callHooks('beforeBuildTicks'); + } + buildTicks() { + return []; + } + afterBuildTicks() { + this._callHooks('afterBuildTicks'); + } + beforeTickToLabelConversion() { + callback(this.options.beforeTickToLabelConversion, [ + this + ]); + } + generateTickLabels(ticks) { + const tickOpts = this.options.ticks; + let i, ilen, tick; + for(i = 0, ilen = ticks.length; i < ilen; i++){ + tick = ticks[i]; + tick.label = callback(tickOpts.callback, [ + tick.value, + i, + ticks + ], this); + } + } + afterTickToLabelConversion() { + callback(this.options.afterTickToLabelConversion, [ + this + ]); + } + beforeCalculateLabelRotation() { + callback(this.options.beforeCalculateLabelRotation, [ + this + ]); + } + calculateLabelRotation() { + const options = this.options; + const tickOpts = options.ticks; + const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit); + const minRotation = tickOpts.minRotation || 0; + const maxRotation = tickOpts.maxRotation; + let labelRotation = minRotation; + let tickWidth, maxHeight, maxLabelDiagonal; + if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { + this.labelRotation = minRotation; + return; + } + const labelSizes = this._getLabelSizes(); + const maxLabelWidth = labelSizes.widest.width; + const maxLabelHeight = labelSizes.highest.height; + const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); + tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); + if (maxLabelWidth + 6 > tickWidth) { + tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); + maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); + maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); + labelRotation = toDegrees(Math.min(Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)))); + labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); + } + this.labelRotation = labelRotation; + } + afterCalculateLabelRotation() { + callback(this.options.afterCalculateLabelRotation, [ + this + ]); + } + afterAutoSkip() {} + beforeFit() { + callback(this.options.beforeFit, [ + this + ]); + } + fit() { + const minSize = { + width: 0, + height: 0 + }; + const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this; + const display = this._isVisible(); + const isHorizontal = this.isHorizontal(); + if (display) { + const titleHeight = getTitleHeight(titleOpts, chart.options.font); + if (isHorizontal) { + minSize.width = this.maxWidth; + minSize.height = getTickMarkLength(gridOpts) + titleHeight; + } else { + minSize.height = this.maxHeight; + minSize.width = getTickMarkLength(gridOpts) + titleHeight; + } + if (tickOpts.display && this.ticks.length) { + const { first , last , widest , highest } = this._getLabelSizes(); + const tickPadding = tickOpts.padding * 2; + const angleRadians = toRadians(this.labelRotation); + const cos = Math.cos(angleRadians); + const sin = Math.sin(angleRadians); + if (isHorizontal) { + const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; + minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); + } else { + const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; + minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); + } + this._calculatePadding(first, last, sin, cos); + } + } + this._handleMargins(); + if (isHorizontal) { + this.width = this._length = chart.width - this._margins.left - this._margins.right; + this.height = minSize.height; + } else { + this.width = minSize.width; + this.height = this._length = chart.height - this._margins.top - this._margins.bottom; + } + } + _calculatePadding(first, last, sin, cos) { + const { ticks: { align , padding } , position } = this.options; + const isRotated = this.labelRotation !== 0; + const labelsBelowTicks = position !== 'top' && this.axis === 'x'; + if (this.isHorizontal()) { + const offsetLeft = this.getPixelForTick(0) - this.left; + const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); + let paddingLeft = 0; + let paddingRight = 0; + if (isRotated) { + if (labelsBelowTicks) { + paddingLeft = cos * first.width; + paddingRight = sin * last.height; + } else { + paddingLeft = sin * first.height; + paddingRight = cos * last.width; + } + } else if (align === 'start') { + paddingRight = last.width; + } else if (align === 'end') { + paddingLeft = first.width; + } else if (align !== 'inner') { + paddingLeft = first.width / 2; + paddingRight = last.width / 2; + } + this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); + this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); + } else { + let paddingTop = last.height / 2; + let paddingBottom = first.height / 2; + if (align === 'start') { + paddingTop = 0; + paddingBottom = first.height; + } else if (align === 'end') { + paddingTop = last.height; + paddingBottom = 0; + } + this.paddingTop = paddingTop + padding; + this.paddingBottom = paddingBottom + padding; + } + } + _handleMargins() { + if (this._margins) { + this._margins.left = Math.max(this.paddingLeft, this._margins.left); + this._margins.top = Math.max(this.paddingTop, this._margins.top); + this._margins.right = Math.max(this.paddingRight, this._margins.right); + this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); + } + } + afterFit() { + callback(this.options.afterFit, [ + this + ]); + } + isHorizontal() { + const { axis , position } = this.options; + return position === 'top' || position === 'bottom' || axis === 'x'; + } + isFullSize() { + return this.options.fullSize; + } + _convertTicksToLabels(ticks) { + this.beforeTickToLabelConversion(); + this.generateTickLabels(ticks); + let i, ilen; + for(i = 0, ilen = ticks.length; i < ilen; i++){ + if (isNullOrUndef(ticks[i].label)) { + ticks.splice(i, 1); + ilen--; + i--; + } + } + this.afterTickToLabelConversion(); + } + _getLabelSizes() { + let labelSizes = this._labelSizes; + if (!labelSizes) { + const sampleSize = this.options.ticks.sampleSize; + let ticks = this.ticks; + if (sampleSize < ticks.length) { + ticks = sample(ticks, sampleSize); + } + this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit); + } + return labelSizes; + } + _computeLabelSizes(ticks, length, maxTicksLimit) { + const { ctx , _longestTextCache: caches } = this; + const widths = []; + const heights = []; + const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit)); + let widestLabelSize = 0; + let highestLabelSize = 0; + let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; + for(i = 0; i < length; i += increment){ + label = ticks[i].label; + tickFont = this._resolveTickFontOptions(i); + ctx.font = fontString = tickFont.string; + cache = caches[fontString] = caches[fontString] || { + data: {}, + gc: [] + }; + lineHeight = tickFont.lineHeight; + width = height = 0; + if (!isNullOrUndef(label) && !isArray(label)) { + width = _measureText(ctx, cache.data, cache.gc, width, label); + height = lineHeight; + } else if (isArray(label)) { + for(j = 0, jlen = label.length; j < jlen; ++j){ + nestedLabel = label[j]; + if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { + width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); + height += lineHeight; + } + } + } + widths.push(width); + heights.push(height); + widestLabelSize = Math.max(width, widestLabelSize); + highestLabelSize = Math.max(height, highestLabelSize); + } + garbageCollect(caches, length); + const widest = widths.indexOf(widestLabelSize); + const highest = heights.indexOf(highestLabelSize); + const valueAt = (idx)=>({ + width: widths[idx] || 0, + height: heights[idx] || 0 + }); + return { + first: valueAt(0), + last: valueAt(length - 1), + widest: valueAt(widest), + highest: valueAt(highest), + widths, + heights + }; + } + getLabelForValue(value) { + return value; + } + getPixelForValue(value, index) { + return NaN; + } + getValueForPixel(pixel) {} + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getPixelForDecimal(decimal) { + if (this._reversePixels) { + decimal = 1 - decimal; + } + const pixel = this._startPixel + decimal * this._length; + return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); + } + getDecimalForPixel(pixel) { + const decimal = (pixel - this._startPixel) / this._length; + return this._reversePixels ? 1 - decimal : decimal; + } + getBasePixel() { + return this.getPixelForValue(this.getBaseValue()); + } + getBaseValue() { + const { min , max } = this; + return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0; + } + getContext(index) { + const ticks = this.ticks || []; + if (index >= 0 && index < ticks.length) { + const tick = ticks[index]; + return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick)); + } + return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this)); + } + _tickSize() { + const optionTicks = this.options.ticks; + const rot = toRadians(this.labelRotation); + const cos = Math.abs(Math.cos(rot)); + const sin = Math.abs(Math.sin(rot)); + const labelSizes = this._getLabelSizes(); + const padding = optionTicks.autoSkipPadding || 0; + const w = labelSizes ? labelSizes.widest.width + padding : 0; + const h = labelSizes ? labelSizes.highest.height + padding : 0; + return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin; + } + _isVisible() { + const display = this.options.display; + if (display !== 'auto') { + return !!display; + } + return this.getMatchingVisibleMetas().length > 0; + } + _computeGridLineItems(chartArea) { + const axis = this.axis; + const chart = this.chart; + const options = this.options; + const { grid , position , border } = options; + const offset = grid.offset; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const ticksLength = ticks.length + (offset ? 1 : 0); + const tl = getTickMarkLength(grid); + const items = []; + const borderOpts = border.setContext(this.getContext()); + const axisWidth = borderOpts.display ? borderOpts.width : 0; + const axisHalfWidth = axisWidth / 2; + const alignBorderValue = function(pixel) { + return _alignPixel(chart, pixel, axisWidth); + }; + let borderValue, i, lineValue, alignedLineValue; + let tx1, ty1, tx2, ty2, x1, y1, x2, y2; + if (position === 'top') { + borderValue = alignBorderValue(this.bottom); + ty1 = this.bottom - tl; + ty2 = borderValue - axisHalfWidth; + y1 = alignBorderValue(chartArea.top) + axisHalfWidth; + y2 = chartArea.bottom; + } else if (position === 'bottom') { + borderValue = alignBorderValue(this.top); + y1 = chartArea.top; + y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; + ty1 = borderValue + axisHalfWidth; + ty2 = this.top + tl; + } else if (position === 'left') { + borderValue = alignBorderValue(this.right); + tx1 = this.right - tl; + tx2 = borderValue - axisHalfWidth; + x1 = alignBorderValue(chartArea.left) + axisHalfWidth; + x2 = chartArea.right; + } else if (position === 'right') { + borderValue = alignBorderValue(this.left); + x1 = chartArea.left; + x2 = alignBorderValue(chartArea.right) - axisHalfWidth; + tx1 = borderValue + axisHalfWidth; + tx2 = this.left + tl; + } else if (axis === 'x') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + y1 = chartArea.top; + y2 = chartArea.bottom; + ty1 = borderValue + axisHalfWidth; + ty2 = ty1 + tl; + } else if (axis === 'y') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + tx1 = borderValue - axisHalfWidth; + tx2 = tx1 - tl; + x1 = chartArea.left; + x2 = chartArea.right; + } + const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); + const step = Math.max(1, Math.ceil(ticksLength / limit)); + for(i = 0; i < ticksLength; i += step){ + const context = this.getContext(i); + const optsAtIndex = grid.setContext(context); + const optsAtIndexBorder = border.setContext(context); + const lineWidth = optsAtIndex.lineWidth; + const lineColor = optsAtIndex.color; + const borderDash = optsAtIndexBorder.dash || []; + const borderDashOffset = optsAtIndexBorder.dashOffset; + const tickWidth = optsAtIndex.tickWidth; + const tickColor = optsAtIndex.tickColor; + const tickBorderDash = optsAtIndex.tickBorderDash || []; + const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; + lineValue = getPixelForGridLine(this, i, offset); + if (lineValue === undefined) { + continue; + } + alignedLineValue = _alignPixel(chart, lineValue, lineWidth); + if (isHorizontal) { + tx1 = tx2 = x1 = x2 = alignedLineValue; + } else { + ty1 = ty2 = y1 = y2 = alignedLineValue; + } + items.push({ + tx1, + ty1, + tx2, + ty2, + x1, + y1, + x2, + y2, + width: lineWidth, + color: lineColor, + borderDash, + borderDashOffset, + tickWidth, + tickColor, + tickBorderDash, + tickBorderDashOffset + }); + } + this._ticksLength = ticksLength; + this._borderValue = borderValue; + return items; + } + _computeLabelItems(chartArea) { + const axis = this.axis; + const options = this.options; + const { position , ticks: optionTicks } = options; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const { align , crossAlign , padding , mirror } = optionTicks; + const tl = getTickMarkLength(options.grid); + const tickAndPadding = tl + padding; + const hTickAndPadding = mirror ? -padding : tickAndPadding; + const rotation = -toRadians(this.labelRotation); + const items = []; + let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; + let textBaseline = 'middle'; + if (position === 'top') { + y = this.bottom - hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'bottom') { + y = this.top + hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'left') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (position === 'right') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (axis === 'x') { + if (position === 'center') { + y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; + } + textAlign = this._getXAxisLabelAlignment(); + } else if (axis === 'y') { + if (position === 'center') { + x = (chartArea.left + chartArea.right) / 2 - tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + x = this.chart.scales[positionAxisID].getPixelForValue(value); + } + textAlign = this._getYAxisLabelAlignment(tl).textAlign; + } + if (axis === 'y') { + if (align === 'start') { + textBaseline = 'top'; + } else if (align === 'end') { + textBaseline = 'bottom'; + } + } + const labelSizes = this._getLabelSizes(); + for(i = 0, ilen = ticks.length; i < ilen; ++i){ + tick = ticks[i]; + label = tick.label; + const optsAtIndex = optionTicks.setContext(this.getContext(i)); + pixel = this.getPixelForTick(i) + optionTicks.labelOffset; + font = this._resolveTickFontOptions(i); + lineHeight = font.lineHeight; + lineCount = isArray(label) ? label.length : 1; + const halfCount = lineCount / 2; + const color = optsAtIndex.color; + const strokeColor = optsAtIndex.textStrokeColor; + const strokeWidth = optsAtIndex.textStrokeWidth; + let tickTextAlign = textAlign; + if (isHorizontal) { + x = pixel; + if (textAlign === 'inner') { + if (i === ilen - 1) { + tickTextAlign = !this.options.reverse ? 'right' : 'left'; + } else if (i === 0) { + tickTextAlign = !this.options.reverse ? 'left' : 'right'; + } else { + tickTextAlign = 'center'; + } + } + if (position === 'top') { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = -lineCount * lineHeight + lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; + } else { + textOffset = -labelSizes.highest.height + lineHeight / 2; + } + } else { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; + } else { + textOffset = labelSizes.highest.height - lineCount * lineHeight; + } + } + if (mirror) { + textOffset *= -1; + } + if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) { + x += lineHeight / 2 * Math.sin(rotation); + } + } else { + y = pixel; + textOffset = (1 - lineCount) * lineHeight / 2; + } + let backdrop; + if (optsAtIndex.showLabelBackdrop) { + const labelPadding = toPadding(optsAtIndex.backdropPadding); + const height = labelSizes.heights[i]; + const width = labelSizes.widths[i]; + let top = textOffset - labelPadding.top; + let left = 0 - labelPadding.left; + switch(textBaseline){ + case 'middle': + top -= height / 2; + break; + case 'bottom': + top -= height; + break; + } + switch(textAlign){ + case 'center': + left -= width / 2; + break; + case 'right': + left -= width; + break; + } + backdrop = { + left, + top, + width: width + labelPadding.width, + height: height + labelPadding.height, + color: optsAtIndex.backdropColor + }; + } + items.push({ + label, + font, + textOffset, + options: { + rotation, + color, + strokeColor, + strokeWidth, + textAlign: tickTextAlign, + textBaseline, + translation: [ + x, + y + ], + backdrop + } + }); + } + return items; + } + _getXAxisLabelAlignment() { + const { position , ticks } = this.options; + const rotation = -toRadians(this.labelRotation); + if (rotation) { + return position === 'top' ? 'left' : 'right'; + } + let align = 'center'; + if (ticks.align === 'start') { + align = 'left'; + } else if (ticks.align === 'end') { + align = 'right'; + } else if (ticks.align === 'inner') { + align = 'inner'; + } + return align; + } + _getYAxisLabelAlignment(tl) { + const { position , ticks: { crossAlign , mirror , padding } } = this.options; + const labelSizes = this._getLabelSizes(); + const tickAndPadding = tl + padding; + const widest = labelSizes.widest.width; + let textAlign; + let x; + if (position === 'left') { + if (mirror) { + x = this.right + padding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += widest / 2; + } else { + textAlign = 'right'; + x += widest; + } + } else { + x = this.right - tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= widest / 2; + } else { + textAlign = 'left'; + x = this.left; + } + } + } else if (position === 'right') { + if (mirror) { + x = this.left + padding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= widest / 2; + } else { + textAlign = 'left'; + x -= widest; + } + } else { + x = this.left + tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += widest / 2; + } else { + textAlign = 'right'; + x = this.right; + } + } + } else { + textAlign = 'right'; + } + return { + textAlign, + x + }; + } + _computeLabelArea() { + if (this.options.ticks.mirror) { + return; + } + const chart = this.chart; + const position = this.options.position; + if (position === 'left' || position === 'right') { + return { + top: 0, + left: this.left, + bottom: chart.height, + right: this.right + }; + } + if (position === 'top' || position === 'bottom') { + return { + top: this.top, + left: 0, + bottom: this.bottom, + right: chart.width + }; + } + } + drawBackground() { + const { ctx , options: { backgroundColor } , left , top , width , height } = this; + if (backgroundColor) { + ctx.save(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(left, top, width, height); + ctx.restore(); + } + } + getLineWidthForValue(value) { + const grid = this.options.grid; + if (!this._isVisible() || !grid.display) { + return 0; + } + const ticks = this.ticks; + const index = ticks.findIndex((t)=>t.value === value); + if (index >= 0) { + const opts = grid.setContext(this.getContext(index)); + return opts.lineWidth; + } + return 0; + } + drawGrid(chartArea) { + const grid = this.options.grid; + const ctx = this.ctx; + const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); + let i, ilen; + const drawLine = (p1, p2, style)=>{ + if (!style.width || !style.color) { + return; + } + ctx.save(); + ctx.lineWidth = style.width; + ctx.strokeStyle = style.color; + ctx.setLineDash(style.borderDash || []); + ctx.lineDashOffset = style.borderDashOffset; + ctx.beginPath(); + ctx.moveTo(p1.x, p1.y); + ctx.lineTo(p2.x, p2.y); + ctx.stroke(); + ctx.restore(); + }; + if (grid.display) { + for(i = 0, ilen = items.length; i < ilen; ++i){ + const item = items[i]; + if (grid.drawOnChartArea) { + drawLine({ + x: item.x1, + y: item.y1 + }, { + x: item.x2, + y: item.y2 + }, item); + } + if (grid.drawTicks) { + drawLine({ + x: item.tx1, + y: item.ty1 + }, { + x: item.tx2, + y: item.ty2 + }, { + color: item.tickColor, + width: item.tickWidth, + borderDash: item.tickBorderDash, + borderDashOffset: item.tickBorderDashOffset + }); + } + } + } + } + drawBorder() { + const { chart , ctx , options: { border , grid } } = this; + const borderOpts = border.setContext(this.getContext()); + const axisWidth = border.display ? borderOpts.width : 0; + if (!axisWidth) { + return; + } + const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; + const borderValue = this._borderValue; + let x1, x2, y1, y2; + if (this.isHorizontal()) { + x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; + x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; + y1 = y2 = borderValue; + } else { + y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; + y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; + x1 = x2 = borderValue; + } + ctx.save(); + ctx.lineWidth = borderOpts.width; + ctx.strokeStyle = borderOpts.color; + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + ctx.restore(); + } + drawLabels(chartArea) { + const optionTicks = this.options.ticks; + if (!optionTicks.display) { + return; + } + const ctx = this.ctx; + const area = this._computeLabelArea(); + if (area) { + clipArea(ctx, area); + } + const items = this.getLabelItems(chartArea); + for (const item of items){ + const renderTextOptions = item.options; + const tickFont = item.font; + const label = item.label; + const y = item.textOffset; + renderText(ctx, label, 0, y, tickFont, renderTextOptions); + } + if (area) { + unclipArea(ctx); + } + } + drawTitle() { + const { ctx , options: { position , title , reverse } } = this; + if (!title.display) { + return; + } + const font = toFont(title.font); + const padding = toPadding(title.padding); + const align = title.align; + let offset = font.lineHeight / 2; + if (position === 'bottom' || position === 'center' || isObject(position)) { + offset += padding.bottom; + if (isArray(title.text)) { + offset += font.lineHeight * (title.text.length - 1); + } + } else { + offset += padding.top; + } + const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align); + renderText(ctx, title.text, 0, 0, font, { + color: title.color, + maxWidth, + rotation, + textAlign: titleAlign(align, position, reverse), + textBaseline: 'middle', + translation: [ + titleX, + titleY + ] + }); + } + draw(chartArea) { + if (!this._isVisible()) { + return; + } + this.drawBackground(); + this.drawGrid(chartArea); + this.drawBorder(); + this.drawTitle(); + this.drawLabels(chartArea); + } + _layers() { + const opts = this.options; + const tz = opts.ticks && opts.ticks.z || 0; + const gz = valueOrDefault(opts.grid && opts.grid.z, -1); + const bz = valueOrDefault(opts.border && opts.border.z, 0); + if (!this._isVisible() || this.draw !== Scale.prototype.draw) { + return [ + { + z: tz, + draw: (chartArea)=>{ + this.draw(chartArea); + } + } + ]; + } + return [ + { + z: gz, + draw: (chartArea)=>{ + this.drawBackground(); + this.drawGrid(chartArea); + this.drawTitle(); + } + }, + { + z: bz, + draw: ()=>{ + this.drawBorder(); + } + }, + { + z: tz, + draw: (chartArea)=>{ + this.drawLabels(chartArea); + } + } + ]; + } + getMatchingVisibleMetas(type) { + const metas = this.chart.getSortedVisibleDatasetMetas(); + const axisID = this.axis + 'AxisID'; + const result = []; + let i, ilen; + for(i = 0, ilen = metas.length; i < ilen; ++i){ + const meta = metas[i]; + if (meta[axisID] === this.id && (!type || meta.type === type)) { + result.push(meta); + } + } + return result; + } + _resolveTickFontOptions(index) { + const opts = this.options.ticks.setContext(this.getContext(index)); + return toFont(opts.font); + } + _maxDigits() { + const fontSize = this._resolveTickFontOptions(0).lineHeight; + return (this.isHorizontal() ? this.width : this.height) / fontSize; + } +} + +class TypedRegistry { + constructor(type, scope, override){ + this.type = type; + this.scope = scope; + this.override = override; + this.items = Object.create(null); + } + isForType(type) { + return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); + } + register(item) { + const proto = Object.getPrototypeOf(item); + let parentScope; + if (isIChartComponent(proto)) { + parentScope = this.register(proto); + } + const items = this.items; + const id = item.id; + const scope = this.scope + '.' + id; + if (!id) { + throw new Error('class does not have id: ' + item); + } + if (id in items) { + return scope; + } + items[id] = item; + registerDefaults(item, scope, parentScope); + if (this.override) { + defaults.override(item.id, item.overrides); + } + return scope; + } + get(id) { + return this.items[id]; + } + unregister(item) { + const items = this.items; + const id = item.id; + const scope = this.scope; + if (id in items) { + delete items[id]; + } + if (scope && id in defaults[scope]) { + delete defaults[scope][id]; + if (this.override) { + delete overrides[id]; + } + } + } +} +function registerDefaults(item, scope, parentScope) { + const itemDefaults = merge(Object.create(null), [ + parentScope ? defaults.get(parentScope) : {}, + defaults.get(scope), + item.defaults + ]); + defaults.set(scope, itemDefaults); + if (item.defaultRoutes) { + routeDefaults(scope, item.defaultRoutes); + } + if (item.descriptors) { + defaults.describe(scope, item.descriptors); + } +} +function routeDefaults(scope, routes) { + Object.keys(routes).forEach((property)=>{ + const propertyParts = property.split('.'); + const sourceName = propertyParts.pop(); + const sourceScope = [ + scope + ].concat(propertyParts).join('.'); + const parts = routes[property].split('.'); + const targetName = parts.pop(); + const targetScope = parts.join('.'); + defaults.route(sourceScope, sourceName, targetScope, targetName); + }); +} +function isIChartComponent(proto) { + return 'id' in proto && 'defaults' in proto; +} + +class Registry { + constructor(){ + this.controllers = new TypedRegistry(DatasetController, 'datasets', true); + this.elements = new TypedRegistry(Element, 'elements'); + this.plugins = new TypedRegistry(Object, 'plugins'); + this.scales = new TypedRegistry(Scale, 'scales'); + this._typedRegistries = [ + this.controllers, + this.scales, + this.elements + ]; + } + add(...args) { + this._each('register', args); + } + remove(...args) { + this._each('unregister', args); + } + addControllers(...args) { + this._each('register', args, this.controllers); + } + addElements(...args) { + this._each('register', args, this.elements); + } + addPlugins(...args) { + this._each('register', args, this.plugins); + } + addScales(...args) { + this._each('register', args, this.scales); + } + getController(id) { + return this._get(id, this.controllers, 'controller'); + } + getElement(id) { + return this._get(id, this.elements, 'element'); + } + getPlugin(id) { + return this._get(id, this.plugins, 'plugin'); + } + getScale(id) { + return this._get(id, this.scales, 'scale'); + } + removeControllers(...args) { + this._each('unregister', args, this.controllers); + } + removeElements(...args) { + this._each('unregister', args, this.elements); + } + removePlugins(...args) { + this._each('unregister', args, this.plugins); + } + removeScales(...args) { + this._each('unregister', args, this.scales); + } + _each(method, args, typedRegistry) { + [ + ...args + ].forEach((arg)=>{ + const reg = typedRegistry || this._getRegistryForType(arg); + if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) { + this._exec(method, reg, arg); + } else { + each(arg, (item)=>{ + const itemReg = typedRegistry || this._getRegistryForType(item); + this._exec(method, itemReg, item); + }); + } + }); + } + _exec(method, registry, component) { + const camelMethod = _capitalize(method); + callback(component['before' + camelMethod], [], component); + registry[method](component); + callback(component['after' + camelMethod], [], component); + } + _getRegistryForType(type) { + for(let i = 0; i < this._typedRegistries.length; i++){ + const reg = this._typedRegistries[i]; + if (reg.isForType(type)) { + return reg; + } + } + return this.plugins; + } + _get(id, typedRegistry, type) { + const item = typedRegistry.get(id); + if (item === undefined) { + throw new Error('"' + id + '" is not a registered ' + type + '.'); + } + return item; + } +} +var registry = /* #__PURE__ */ new Registry(); + +class PluginService { + constructor(){ + this._init = []; + } + notify(chart, hook, args, filter) { + if (hook === 'beforeInit') { + this._init = this._createDescriptors(chart, true); + this._notify(this._init, chart, 'install'); + } + const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); + const result = this._notify(descriptors, chart, hook, args); + if (hook === 'afterDestroy') { + this._notify(descriptors, chart, 'stop'); + this._notify(this._init, chart, 'uninstall'); + } + return result; + } + _notify(descriptors, chart, hook, args) { + args = args || {}; + for (const descriptor of descriptors){ + const plugin = descriptor.plugin; + const method = plugin[hook]; + const params = [ + chart, + args, + descriptor.options + ]; + if (callback(method, params, plugin) === false && args.cancelable) { + return false; + } + } + return true; + } + invalidate() { + if (!isNullOrUndef(this._cache)) { + this._oldCache = this._cache; + this._cache = undefined; + } + } + _descriptors(chart) { + if (this._cache) { + return this._cache; + } + const descriptors = this._cache = this._createDescriptors(chart); + this._notifyStateChanges(chart); + return descriptors; + } + _createDescriptors(chart, all) { + const config = chart && chart.config; + const options = valueOrDefault(config.options && config.options.plugins, {}); + const plugins = allPlugins(config); + return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); + } + _notifyStateChanges(chart) { + const previousDescriptors = this._oldCache || []; + const descriptors = this._cache; + const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id)); + this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); + this._notify(diff(descriptors, previousDescriptors), chart, 'start'); + } +} + function allPlugins(config) { + const localIds = {}; + const plugins = []; + const keys = Object.keys(registry.plugins.items); + for(let i = 0; i < keys.length; i++){ + plugins.push(registry.getPlugin(keys[i])); + } + const local = config.plugins || []; + for(let i = 0; i < local.length; i++){ + const plugin = local[i]; + if (plugins.indexOf(plugin) === -1) { + plugins.push(plugin); + localIds[plugin.id] = true; + } + } + return { + plugins, + localIds + }; +} +function getOpts(options, all) { + if (!all && options === false) { + return null; + } + if (options === true) { + return {}; + } + return options; +} +function createDescriptors(chart, { plugins , localIds }, options, all) { + const result = []; + const context = chart.getContext(); + for (const plugin of plugins){ + const id = plugin.id; + const opts = getOpts(options[id], all); + if (opts === null) { + continue; + } + result.push({ + plugin, + options: pluginOpts(chart.config, { + plugin, + local: localIds[id] + }, opts, context) + }); + } + return result; +} +function pluginOpts(config, { plugin , local }, opts, context) { + const keys = config.pluginScopeKeys(plugin); + const scopes = config.getOptionScopes(opts, keys); + if (local && plugin.defaults) { + scopes.push(plugin.defaults); + } + return config.createResolver(scopes, context, [ + '' + ], { + scriptable: false, + indexable: false, + allKeys: true + }); +} + +function getIndexAxis(type, options) { + const datasetDefaults = defaults.datasets[type] || {}; + const datasetOptions = (options.datasets || {})[type] || {}; + return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; +} +function getAxisFromDefaultScaleID(id, indexAxis) { + let axis = id; + if (id === '_index_') { + axis = indexAxis; + } else if (id === '_value_') { + axis = indexAxis === 'x' ? 'y' : 'x'; + } + return axis; +} +function getDefaultScaleIDFromAxis(axis, indexAxis) { + return axis === indexAxis ? '_index_' : '_value_'; +} +function idMatchesAxis(id) { + if (id === 'x' || id === 'y' || id === 'r') { + return id; + } +} +function axisFromPosition(position) { + if (position === 'top' || position === 'bottom') { + return 'x'; + } + if (position === 'left' || position === 'right') { + return 'y'; + } +} +function determineAxis(id, ...scaleOptions) { + if (idMatchesAxis(id)) { + return id; + } + for (const opts of scaleOptions){ + const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase()); + if (axis) { + return axis; + } + } + throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`); +} +function getAxisFromDataset(id, axis, dataset) { + if (dataset[axis + 'AxisID'] === id) { + return { + axis + }; + } +} +function retrieveAxisFromDatasets(id, config) { + if (config.data && config.data.datasets) { + const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id); + if (boundDs.length) { + return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]); + } + } + return {}; +} +function mergeScaleConfig(config, options) { + const chartDefaults = overrides[config.type] || { + scales: {} + }; + const configScales = options.scales || {}; + const chartIndexAxis = getIndexAxis(config.type, options); + const scales = Object.create(null); + Object.keys(configScales).forEach((id)=>{ + const scaleConf = configScales[id]; + if (!isObject(scaleConf)) { + return console.error(`Invalid scale configuration for scale: ${id}`); + } + if (scaleConf._proxy) { + return console.warn(`Ignoring resolver passed as options for scale: ${id}`); + } + const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), defaults.scales[scaleConf.type]); + const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); + const defaultScaleOptions = chartDefaults.scales || {}; + scales[id] = mergeIf(Object.create(null), [ + { + axis + }, + scaleConf, + defaultScaleOptions[axis], + defaultScaleOptions[defaultId] + ]); + }); + config.data.datasets.forEach((dataset)=>{ + const type = dataset.type || config.type; + const indexAxis = dataset.indexAxis || getIndexAxis(type, options); + const datasetDefaults = overrides[type] || {}; + const defaultScaleOptions = datasetDefaults.scales || {}; + Object.keys(defaultScaleOptions).forEach((defaultID)=>{ + const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); + const id = dataset[axis + 'AxisID'] || axis; + scales[id] = scales[id] || Object.create(null); + mergeIf(scales[id], [ + { + axis + }, + configScales[id], + defaultScaleOptions[defaultID] + ]); + }); + }); + Object.keys(scales).forEach((key)=>{ + const scale = scales[key]; + mergeIf(scale, [ + defaults.scales[scale.type], + defaults.scale + ]); + }); + return scales; +} +function initOptions(config) { + const options = config.options || (config.options = {}); + options.plugins = valueOrDefault(options.plugins, {}); + options.scales = mergeScaleConfig(config, options); +} +function initData(data) { + data = data || {}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + return data; +} +function initConfig(config) { + config = config || {}; + config.data = initData(config.data); + initOptions(config); + return config; +} +const keyCache = new Map(); +const keysCached = new Set(); +function cachedKeys(cacheKey, generate) { + let keys = keyCache.get(cacheKey); + if (!keys) { + keys = generate(); + keyCache.set(cacheKey, keys); + keysCached.add(keys); + } + return keys; +} +const addIfFound = (set, obj, key)=>{ + const opts = resolveObjectKey(obj, key); + if (opts !== undefined) { + set.add(opts); + } +}; +class Config { + constructor(config){ + this._config = initConfig(config); + this._scopeCache = new Map(); + this._resolverCache = new Map(); + } + get platform() { + return this._config.platform; + } + get type() { + return this._config.type; + } + set type(type) { + this._config.type = type; + } + get data() { + return this._config.data; + } + set data(data) { + this._config.data = initData(data); + } + get options() { + return this._config.options; + } + set options(options) { + this._config.options = options; + } + get plugins() { + return this._config.plugins; + } + update() { + const config = this._config; + this.clearCache(); + initOptions(config); + } + clearCache() { + this._scopeCache.clear(); + this._resolverCache.clear(); + } + datasetScopeKeys(datasetType) { + return cachedKeys(datasetType, ()=>[ + [ + `datasets.${datasetType}`, + '' + ] + ]); + } + datasetAnimationScopeKeys(datasetType, transition) { + return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[ + [ + `datasets.${datasetType}.transitions.${transition}`, + `transitions.${transition}` + ], + [ + `datasets.${datasetType}`, + '' + ] + ]); + } + datasetElementScopeKeys(datasetType, elementType) { + return cachedKeys(`${datasetType}-${elementType}`, ()=>[ + [ + `datasets.${datasetType}.elements.${elementType}`, + `datasets.${datasetType}`, + `elements.${elementType}`, + '' + ] + ]); + } + pluginScopeKeys(plugin) { + const id = plugin.id; + const type = this.type; + return cachedKeys(`${type}-plugin-${id}`, ()=>[ + [ + `plugins.${id}`, + ...plugin.additionalOptionScopes || [] + ] + ]); + } + _cachedScopes(mainScope, resetCache) { + const _scopeCache = this._scopeCache; + let cache = _scopeCache.get(mainScope); + if (!cache || resetCache) { + cache = new Map(); + _scopeCache.set(mainScope, cache); + } + return cache; + } + getOptionScopes(mainScope, keyLists, resetCache) { + const { options , type } = this; + const cache = this._cachedScopes(mainScope, resetCache); + const cached = cache.get(keyLists); + if (cached) { + return cached; + } + const scopes = new Set(); + keyLists.forEach((keys)=>{ + if (mainScope) { + scopes.add(mainScope); + keys.forEach((key)=>addIfFound(scopes, mainScope, key)); + } + keys.forEach((key)=>addIfFound(scopes, options, key)); + keys.forEach((key)=>addIfFound(scopes, overrides[type] || {}, key)); + keys.forEach((key)=>addIfFound(scopes, defaults, key)); + keys.forEach((key)=>addIfFound(scopes, descriptors, key)); + }); + const array = Array.from(scopes); + if (array.length === 0) { + array.push(Object.create(null)); + } + if (keysCached.has(keyLists)) { + cache.set(keyLists, array); + } + return array; + } + chartOptionScopes() { + const { options , type } = this; + return [ + options, + overrides[type] || {}, + defaults.datasets[type] || {}, + { + type + }, + defaults, + descriptors + ]; + } + resolveNamedOptions(scopes, names, context, prefixes = [ + '' + ]) { + const result = { + $shared: true + }; + const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes); + let options = resolver; + if (needContext(resolver, names)) { + result.$shared = false; + context = isFunction(context) ? context() : context; + const subResolver = this.createResolver(scopes, context, subPrefixes); + options = _attachContext(resolver, context, subResolver); + } + for (const prop of names){ + result[prop] = options[prop]; + } + return result; + } + createResolver(scopes, context, prefixes = [ + '' + ], descriptorDefaults) { + const { resolver } = getResolver(this._resolverCache, scopes, prefixes); + return isObject(context) ? _attachContext(resolver, context, undefined, descriptorDefaults) : resolver; + } +} +function getResolver(resolverCache, scopes, prefixes) { + let cache = resolverCache.get(scopes); + if (!cache) { + cache = new Map(); + resolverCache.set(scopes, cache); + } + const cacheKey = prefixes.join(); + let cached = cache.get(cacheKey); + if (!cached) { + const resolver = _createResolver(scopes, prefixes); + cached = { + resolver, + subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover')) + }; + cache.set(cacheKey, cached); + } + return cached; +} +const hasFunction = (value)=>isObject(value) && Object.getOwnPropertyNames(value).reduce((acc, key)=>acc || isFunction(value[key]), false); +function needContext(proxy, names) { + const { isScriptable , isIndexable } = _descriptors(proxy); + for (const prop of names){ + const scriptable = isScriptable(prop); + const indexable = isIndexable(prop); + const value = (indexable || scriptable) && proxy[prop]; + if (scriptable && (isFunction(value) || hasFunction(value)) || indexable && isArray(value)) { + return true; + } + } + return false; +} + +var version = "4.3.0"; + +const KNOWN_POSITIONS = [ + 'top', + 'bottom', + 'left', + 'right', + 'chartArea' +]; +function positionIsHorizontal(position, axis) { + return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'; +} +function compare2Level(l1, l2) { + return function(a, b) { + return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1]; + }; +} +function onAnimationsComplete(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + chart.notifyPlugins('afterRender'); + callback(animationOptions && animationOptions.onComplete, [ + context + ], chart); +} +function onAnimationProgress(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + callback(animationOptions && animationOptions.onProgress, [ + context + ], chart); +} + function getCanvas(item) { + if (_isDomSupported() && typeof item === 'string') { + item = document.getElementById(item); + } else if (item && item.length) { + item = item[0]; + } + if (item && item.canvas) { + item = item.canvas; + } + return item; +} +const instances = {}; +const getChart = (key)=>{ + const canvas = getCanvas(key); + return Object.values(instances).filter((c)=>c.canvas === canvas).pop(); +}; +function moveNumericKeys(obj, start, move) { + const keys = Object.keys(obj); + for (const key of keys){ + const intKey = +key; + if (intKey >= start) { + const value = obj[key]; + delete obj[key]; + if (move > 0 || intKey > start) { + obj[intKey + move] = value; + } + } + } +} + function determineLastEvent(e, lastEvent, inChartArea, isClick) { + if (!inChartArea || e.type === 'mouseout') { + return null; + } + if (isClick) { + return lastEvent; + } + return e; +} +function getDatasetArea(meta) { + const { xScale , yScale } = meta; + if (xScale && yScale) { + return { + left: xScale.left, + right: xScale.right, + top: yScale.top, + bottom: yScale.bottom + }; + } +} +class Chart { + static defaults = defaults; + static instances = instances; + static overrides = overrides; + static registry = registry; + static version = version; + static getChart = getChart; + static register(...items) { + registry.add(...items); + invalidatePlugins(); + } + static unregister(...items) { + registry.remove(...items); + invalidatePlugins(); + } + constructor(item, userConfig){ + const config = this.config = new Config(userConfig); + const initialCanvas = getCanvas(item); + const existingChart = getChart(initialCanvas); + if (existingChart) { + throw new Error('Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + ' must be destroyed before the canvas with ID \'' + existingChart.canvas.id + '\' can be reused.'); + } + const options = config.createResolver(config.chartOptionScopes(), this.getContext()); + this.platform = new (config.platform || _detectPlatform(initialCanvas))(); + this.platform.updateConfig(config); + const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); + const canvas = context && context.canvas; + const height = canvas && canvas.height; + const width = canvas && canvas.width; + this.id = uid(); + this.ctx = context; + this.canvas = canvas; + this.width = width; + this.height = height; + this._options = options; + this._aspectRatio = this.aspectRatio; + this._layers = []; + this._metasets = []; + this._stacks = undefined; + this.boxes = []; + this.currentDevicePixelRatio = undefined; + this.chartArea = undefined; + this._active = []; + this._lastEvent = undefined; + this._listeners = {}; + this._responsiveListeners = undefined; + this._sortedMetasets = []; + this.scales = {}; + this._plugins = new PluginService(); + this.$proxies = {}; + this._hiddenIndices = {}; + this.attached = false; + this._animationsDisabled = undefined; + this.$context = undefined; + this._doResize = debounce((mode)=>this.update(mode), options.resizeDelay || 0); + this._dataChanges = []; + instances[this.id] = this; + if (!context || !canvas) { + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + animator.listen(this, 'complete', onAnimationsComplete); + animator.listen(this, 'progress', onAnimationProgress); + this._initialize(); + if (this.attached) { + this.update(); + } + } + get aspectRatio() { + const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this; + if (!isNullOrUndef(aspectRatio)) { + return aspectRatio; + } + if (maintainAspectRatio && _aspectRatio) { + return _aspectRatio; + } + return height ? width / height : null; + } + get data() { + return this.config.data; + } + set data(data) { + this.config.data = data; + } + get options() { + return this._options; + } + set options(options) { + this.config.options = options; + } + get registry() { + return registry; + } + _initialize() { + this.notifyPlugins('beforeInit'); + if (this.options.responsive) { + this.resize(); + } else { + retinaScale(this, this.options.devicePixelRatio); + } + this.bindEvents(); + this.notifyPlugins('afterInit'); + return this; + } + clear() { + clearCanvas(this.canvas, this.ctx); + return this; + } + stop() { + animator.stop(this); + return this; + } + resize(width, height) { + if (!animator.running(this)) { + this._resize(width, height); + } else { + this._resizeBeforeDraw = { + width, + height + }; + } + } + _resize(width, height) { + const options = this.options; + const canvas = this.canvas; + const aspectRatio = options.maintainAspectRatio && this.aspectRatio; + const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); + const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); + const mode = this.width ? 'resize' : 'attach'; + this.width = newSize.width; + this.height = newSize.height; + this._aspectRatio = this.aspectRatio; + if (!retinaScale(this, newRatio, true)) { + return; + } + this.notifyPlugins('resize', { + size: newSize + }); + callback(options.onResize, [ + this, + newSize + ], this); + if (this.attached) { + if (this._doResize(mode)) { + this.render(); + } + } + } + ensureScalesHaveIDs() { + const options = this.options; + const scalesOptions = options.scales || {}; + each(scalesOptions, (axisOptions, axisID)=>{ + axisOptions.id = axisID; + }); + } + buildOrUpdateScales() { + const options = this.options; + const scaleOpts = options.scales; + const scales = this.scales; + const updated = Object.keys(scales).reduce((obj, id)=>{ + obj[id] = false; + return obj; + }, {}); + let items = []; + if (scaleOpts) { + items = items.concat(Object.keys(scaleOpts).map((id)=>{ + const scaleOptions = scaleOpts[id]; + const axis = determineAxis(id, scaleOptions); + const isRadial = axis === 'r'; + const isHorizontal = axis === 'x'; + return { + options: scaleOptions, + dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', + dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' + }; + })); + } + each(items, (item)=>{ + const scaleOptions = item.options; + const id = scaleOptions.id; + const axis = determineAxis(id, scaleOptions); + const scaleType = valueOrDefault(scaleOptions.type, item.dtype); + if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + updated[id] = true; + let scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + } else { + const scaleClass = registry.getScale(scaleType); + scale = new scaleClass({ + id, + type: scaleType, + ctx: this.ctx, + chart: this + }); + scales[scale.id] = scale; + } + scale.init(scaleOptions, options); + }); + each(updated, (hasUpdated, id)=>{ + if (!hasUpdated) { + delete scales[id]; + } + }); + each(scales, (scale)=>{ + layouts.configure(this, scale, scale.options); + layouts.addBox(this, scale); + }); + } + _updateMetasets() { + const metasets = this._metasets; + const numData = this.data.datasets.length; + const numMeta = metasets.length; + metasets.sort((a, b)=>a.index - b.index); + if (numMeta > numData) { + for(let i = numData; i < numMeta; ++i){ + this._destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + } + _removeUnreferencedMetasets() { + const { _metasets: metasets , data: { datasets } } = this; + if (metasets.length > datasets.length) { + delete this._stacks; + } + metasets.forEach((meta, index)=>{ + if (datasets.filter((x)=>x === meta._dataset).length === 0) { + this._destroyDatasetMeta(index); + } + }); + } + buildOrUpdateControllers() { + const newControllers = []; + const datasets = this.data.datasets; + let i, ilen; + this._removeUnreferencedMetasets(); + for(i = 0, ilen = datasets.length; i < ilen; i++){ + const dataset = datasets[i]; + let meta = this.getDatasetMeta(i); + const type = dataset.type || this.config.type; + if (meta.type && meta.type !== type) { + this._destroyDatasetMeta(i); + meta = this.getDatasetMeta(i); + } + meta.type = type; + meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); + meta.order = dataset.order || 0; + meta.index = i; + meta.label = '' + dataset.label; + meta.visible = this.isDatasetVisible(i); + if (meta.controller) { + meta.controller.updateIndex(i); + meta.controller.linkScales(); + } else { + const ControllerClass = registry.getController(type); + const { datasetElementType , dataElementType } = defaults.datasets[type]; + Object.assign(ControllerClass, { + dataElementType: registry.getElement(dataElementType), + datasetElementType: datasetElementType && registry.getElement(datasetElementType) + }); + meta.controller = new ControllerClass(this, i); + newControllers.push(meta.controller); + } + } + this._updateMetasets(); + return newControllers; + } + _resetElements() { + each(this.data.datasets, (dataset, datasetIndex)=>{ + this.getDatasetMeta(datasetIndex).controller.reset(); + }, this); + } + reset() { + this._resetElements(); + this.notifyPlugins('reset'); + } + update(mode) { + const config = this.config; + config.update(); + const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); + const animsDisabled = this._animationsDisabled = !options.animation; + this._updateScales(); + this._checkEventBindings(); + this._updateHiddenIndices(); + this._plugins.invalidate(); + if (this.notifyPlugins('beforeUpdate', { + mode, + cancelable: true + }) === false) { + return; + } + const newControllers = this.buildOrUpdateControllers(); + this.notifyPlugins('beforeElementsUpdate'); + let minPadding = 0; + for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){ + const { controller } = this.getDatasetMeta(i); + const reset = !animsDisabled && newControllers.indexOf(controller) === -1; + controller.buildOrUpdateElements(reset); + minPadding = Math.max(+controller.getMaxOverflow(), minPadding); + } + minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; + this._updateLayout(minPadding); + if (!animsDisabled) { + each(newControllers, (controller)=>{ + controller.reset(); + }); + } + this._updateDatasets(mode); + this.notifyPlugins('afterUpdate', { + mode + }); + this._layers.sort(compare2Level('z', '_idx')); + const { _active , _lastEvent } = this; + if (_lastEvent) { + this._eventHandler(_lastEvent, true); + } else if (_active.length) { + this._updateHoverStyles(_active, _active, true); + } + this.render(); + } + _updateScales() { + each(this.scales, (scale)=>{ + layouts.removeBox(this, scale); + }); + this.ensureScalesHaveIDs(); + this.buildOrUpdateScales(); + } + _checkEventBindings() { + const options = this.options; + const existingEvents = new Set(Object.keys(this._listeners)); + const newEvents = new Set(options.events); + if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { + this.unbindEvents(); + this.bindEvents(); + } + } + _updateHiddenIndices() { + const { _hiddenIndices } = this; + const changes = this._getUniformDataChanges() || []; + for (const { method , start , count } of changes){ + const move = method === '_removeElements' ? -count : count; + moveNumericKeys(_hiddenIndices, start, move); + } + } + _getUniformDataChanges() { + const _dataChanges = this._dataChanges; + if (!_dataChanges || !_dataChanges.length) { + return; + } + this._dataChanges = []; + const datasetCount = this.data.datasets.length; + const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(','))); + const changeSet = makeSet(0); + for(let i = 1; i < datasetCount; i++){ + if (!setsEqual(changeSet, makeSet(i))) { + return; + } + } + return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({ + method: a[1], + start: +a[2], + count: +a[3] + })); + } + _updateLayout(minPadding) { + if (this.notifyPlugins('beforeLayout', { + cancelable: true + }) === false) { + return; + } + layouts.update(this, this.width, this.height, minPadding); + const area = this.chartArea; + const noArea = area.width <= 0 || area.height <= 0; + this._layers = []; + each(this.boxes, (box)=>{ + if (noArea && box.position === 'chartArea') { + return; + } + if (box.configure) { + box.configure(); + } + this._layers.push(...box._layers()); + }, this); + this._layers.forEach((item, index)=>{ + item._idx = index; + }); + this.notifyPlugins('afterLayout'); + } + _updateDatasets(mode) { + if (this.notifyPlugins('beforeDatasetsUpdate', { + mode, + cancelable: true + }) === false) { + return; + } + for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ + this.getDatasetMeta(i).controller.configure(); + } + for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ + this._updateDataset(i, isFunction(mode) ? mode({ + datasetIndex: i + }) : mode); + } + this.notifyPlugins('afterDatasetsUpdate', { + mode + }); + } + _updateDataset(index, mode) { + const meta = this.getDatasetMeta(index); + const args = { + meta, + index, + mode, + cancelable: true + }; + if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { + return; + } + meta.controller._update(mode); + args.cancelable = false; + this.notifyPlugins('afterDatasetUpdate', args); + } + render() { + if (this.notifyPlugins('beforeRender', { + cancelable: true + }) === false) { + return; + } + if (animator.has(this)) { + if (this.attached && !animator.running(this)) { + animator.start(this); + } + } else { + this.draw(); + onAnimationsComplete({ + chart: this + }); + } + } + draw() { + let i; + if (this._resizeBeforeDraw) { + const { width , height } = this._resizeBeforeDraw; + this._resize(width, height); + this._resizeBeforeDraw = null; + } + this.clear(); + if (this.width <= 0 || this.height <= 0) { + return; + } + if (this.notifyPlugins('beforeDraw', { + cancelable: true + }) === false) { + return; + } + const layers = this._layers; + for(i = 0; i < layers.length && layers[i].z <= 0; ++i){ + layers[i].draw(this.chartArea); + } + this._drawDatasets(); + for(; i < layers.length; ++i){ + layers[i].draw(this.chartArea); + } + this.notifyPlugins('afterDraw'); + } + _getSortedDatasetMetas(filterVisible) { + const metasets = this._sortedMetasets; + const result = []; + let i, ilen; + for(i = 0, ilen = metasets.length; i < ilen; ++i){ + const meta = metasets[i]; + if (!filterVisible || meta.visible) { + result.push(meta); + } + } + return result; + } + getSortedVisibleDatasetMetas() { + return this._getSortedDatasetMetas(true); + } + _drawDatasets() { + if (this.notifyPlugins('beforeDatasetsDraw', { + cancelable: true + }) === false) { + return; + } + const metasets = this.getSortedVisibleDatasetMetas(); + for(let i = metasets.length - 1; i >= 0; --i){ + this._drawDataset(metasets[i]); + } + this.notifyPlugins('afterDatasetsDraw'); + } + _drawDataset(meta) { + const ctx = this.ctx; + const clip = meta._clip; + const useClip = !clip.disabled; + const area = getDatasetArea(meta) || this.chartArea; + const args = { + meta, + index: meta.index, + cancelable: true + }; + if (this.notifyPlugins('beforeDatasetDraw', args) === false) { + return; + } + if (useClip) { + clipArea(ctx, { + left: clip.left === false ? 0 : area.left - clip.left, + right: clip.right === false ? this.width : area.right + clip.right, + top: clip.top === false ? 0 : area.top - clip.top, + bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom + }); + } + meta.controller.draw(); + if (useClip) { + unclipArea(ctx); + } + args.cancelable = false; + this.notifyPlugins('afterDatasetDraw', args); + } + isPointInArea(point) { + return _isPointInArea(point, this.chartArea, this._minPadding); + } + getElementsAtEventForMode(e, mode, options, useFinalPosition) { + const method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options, useFinalPosition); + } + return []; + } + getDatasetMeta(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + const metasets = this._metasets; + let meta = metasets.filter((x)=>x && x._dataset === dataset).pop(); + if (!meta) { + meta = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, + xAxisID: null, + yAxisID: null, + order: dataset && dataset.order || 0, + index: datasetIndex, + _dataset: dataset, + _parsed: [], + _sorted: false + }; + metasets.push(meta); + } + return meta; + } + getContext() { + return this.$context || (this.$context = createContext(null, { + chart: this, + type: 'chart' + })); + } + getVisibleDatasetCount() { + return this.getSortedVisibleDatasetMetas().length; + } + isDatasetVisible(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + if (!dataset) { + return false; + } + const meta = this.getDatasetMeta(datasetIndex); + return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; + } + setDatasetVisibility(datasetIndex, visible) { + const meta = this.getDatasetMeta(datasetIndex); + meta.hidden = !visible; + } + toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + } + getDataVisibility(index) { + return !this._hiddenIndices[index]; + } + _updateVisibility(datasetIndex, dataIndex, visible) { + const mode = visible ? 'show' : 'hide'; + const meta = this.getDatasetMeta(datasetIndex); + const anims = meta.controller._resolveAnimations(undefined, mode); + if (defined(dataIndex)) { + meta.data[dataIndex].hidden = !visible; + this.update(); + } else { + this.setDatasetVisibility(datasetIndex, visible); + anims.update(meta, { + visible + }); + this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined); + } + } + hide(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, false); + } + show(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, true); + } + _destroyDatasetMeta(datasetIndex) { + const meta = this._metasets[datasetIndex]; + if (meta && meta.controller) { + meta.controller._destroy(); + } + delete this._metasets[datasetIndex]; + } + _stop() { + let i, ilen; + this.stop(); + animator.remove(this); + for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ + this._destroyDatasetMeta(i); + } + } + destroy() { + this.notifyPlugins('beforeDestroy'); + const { canvas , ctx } = this; + this._stop(); + this.config.clearCache(); + if (canvas) { + this.unbindEvents(); + clearCanvas(canvas, ctx); + this.platform.releaseContext(ctx); + this.canvas = null; + this.ctx = null; + } + delete instances[this.id]; + this.notifyPlugins('afterDestroy'); + } + toBase64Image(...args) { + return this.canvas.toDataURL(...args); + } + bindEvents() { + this.bindUserEvents(); + if (this.options.responsive) { + this.bindResponsiveEvents(); + } else { + this.attached = true; + } + } + bindUserEvents() { + const listeners = this._listeners; + const platform = this.platform; + const _add = (type, listener)=>{ + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const listener = (e, x, y)=>{ + e.offsetX = x; + e.offsetY = y; + this._eventHandler(e); + }; + each(this.options.events, (type)=>_add(type, listener)); + } + bindResponsiveEvents() { + if (!this._responsiveListeners) { + this._responsiveListeners = {}; + } + const listeners = this._responsiveListeners; + const platform = this.platform; + const _add = (type, listener)=>{ + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const _remove = (type, listener)=>{ + if (listeners[type]) { + platform.removeEventListener(this, type, listener); + delete listeners[type]; + } + }; + const listener = (width, height)=>{ + if (this.canvas) { + this.resize(width, height); + } + }; + let detached; + const attached = ()=>{ + _remove('attach', attached); + this.attached = true; + this.resize(); + _add('resize', listener); + _add('detach', detached); + }; + detached = ()=>{ + this.attached = false; + _remove('resize', listener); + this._stop(); + this._resize(0, 0); + _add('attach', attached); + }; + if (platform.isAttached(this.canvas)) { + attached(); + } else { + detached(); + } + } + unbindEvents() { + each(this._listeners, (listener, type)=>{ + this.platform.removeEventListener(this, type, listener); + }); + this._listeners = {}; + each(this._responsiveListeners, (listener, type)=>{ + this.platform.removeEventListener(this, type, listener); + }); + this._responsiveListeners = undefined; + } + updateHoverStyle(items, mode, enabled) { + const prefix = enabled ? 'set' : 'remove'; + let meta, item, i, ilen; + if (mode === 'dataset') { + meta = this.getDatasetMeta(items[0].datasetIndex); + meta.controller['_' + prefix + 'DatasetHoverStyle'](); + } + for(i = 0, ilen = items.length; i < ilen; ++i){ + item = items[i]; + const controller = item && this.getDatasetMeta(item.datasetIndex).controller; + if (controller) { + controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); + } + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements) { + const lastActive = this._active || []; + const active = activeElements.map(({ datasetIndex , index })=>{ + const meta = this.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('No dataset found at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index + }; + }); + const changed = !_elementsEqual(active, lastActive); + if (changed) { + this._active = active; + this._lastEvent = null; + this._updateHoverStyles(active, lastActive); + } + } + notifyPlugins(hook, args, filter) { + return this._plugins.notify(this, hook, args, filter); + } + isPluginEnabled(pluginId) { + return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1; + } + _updateHoverStyles(active, lastActive, replay) { + const hoverOptions = this.options.hover; + const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index)); + const deactivated = diff(lastActive, active); + const activated = replay ? active : diff(active, lastActive); + if (deactivated.length) { + this.updateHoverStyle(deactivated, hoverOptions.mode, false); + } + if (activated.length && hoverOptions.mode) { + this.updateHoverStyle(activated, hoverOptions.mode, true); + } + } + _eventHandler(e, replay) { + const args = { + event: e, + replay, + cancelable: true, + inChartArea: this.isPointInArea(e) + }; + const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type); + if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { + return; + } + const changed = this._handleEvent(e, replay, args.inChartArea); + args.cancelable = false; + this.notifyPlugins('afterEvent', args, eventFilter); + if (changed || args.changed) { + this.render(); + } + return this; + } + _handleEvent(e, replay, inChartArea) { + const { _active: lastActive = [] , options } = this; + const useFinalPosition = replay; + const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); + const isClick = _isClickEvent(e); + const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); + if (inChartArea) { + this._lastEvent = null; + callback(options.onHover, [ + e, + active, + this + ], this); + if (isClick) { + callback(options.onClick, [ + e, + active, + this + ], this); + } + } + const changed = !_elementsEqual(active, lastActive); + if (changed || replay) { + this._active = active; + this._updateHoverStyles(active, lastActive, replay); + } + this._lastEvent = lastEvent; + return changed; + } + _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const hoverOptions = this.options.hover; + return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); + } +} +function invalidatePlugins() { + return each(Chart.instances, (chart)=>chart._plugins.invalidate()); +} + +function clipArc(ctx, element, endAngle) { + const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element; + let angleMargin = pixelMargin / outerRadius; + // Draw an inner border by clipping the arc and drawing a double-width border + // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (innerRadius > pixelMargin) { + angleMargin = pixelMargin / innerRadius; + ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); + } + ctx.closePath(); + ctx.clip(); +} +function toRadiusCorners(value) { + return _readValueToProps(value, [ + 'outerStart', + 'outerEnd', + 'innerStart', + 'innerEnd' + ]); +} +/** + * Parse border radius from the provided options + */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { + const o = toRadiusCorners(arc.options.borderRadius); + const halfThickness = (outerRadius - innerRadius) / 2; + const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); + // Outer limits are complicated. We want to compute the available angular distance at + // a radius of outerRadius - borderRadius because for small angular distances, this term limits. + // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners. + // + // If the borderRadius is large, that value can become negative. + // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius + // we know that the thickness term will dominate and compute the limits at that point + const computeOuterLimit = (val)=>{ + const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; + return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); + }; + return { + outerStart: computeOuterLimit(o.outerStart), + outerEnd: computeOuterLimit(o.outerEnd), + innerStart: _limitValue(o.innerStart, 0, innerLimit), + innerEnd: _limitValue(o.innerEnd, 0, innerLimit) + }; +} +/** + * Convert (r, 𝜃) to (x, y) + */ function rThetaToXY(r, theta, x, y) { + return { + x: x + r * Math.cos(theta), + y: y + r * Math.sin(theta) + }; +} +/** + * Path the arc, respecting border radius by separating into left and right halves. + * + * Start End + * + * 1--->a--->2 Outer + * / \ + * 8 3 + * | | + * | | + * 7 4 + * \ / + * 6<---b<---5 Inner + */ function pathArc(ctx, element, offset, spacing, end, circular) { + const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element; + const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); + const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; + let spacingOffset = 0; + const alpha = end - start; + if (spacing) { + // When spacing is present, it is the same for all items + // So we adjust the start and end angle of the arc such that + // the distance is the same as it would be without the spacing + const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; + const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; + const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; + const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha; + spacingOffset = (alpha - adjustedAngle) / 2; + } + const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; + const angleOffset = (alpha - beta) / 2; + const startAngle = start + angleOffset + spacingOffset; + const endAngle = end - angleOffset - spacingOffset; + const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); + const outerStartAdjustedRadius = outerRadius - outerStart; + const outerEndAdjustedRadius = outerRadius - outerEnd; + const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; + const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; + const innerStartAdjustedRadius = innerRadius + innerStart; + const innerEndAdjustedRadius = innerRadius + innerEnd; + const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; + const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; + ctx.beginPath(); + if (circular) { + // The first arc segments from point 1 to point a to point 2 + const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2; + ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle); + ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle); + // The corner segment from point 2 to point 3 + if (outerEnd > 0) { + const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); + } + // The line from point 3 to point 4 + const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); + ctx.lineTo(p4.x, p4.y); + // The corner segment from point 4 to point 5 + if (innerEnd > 0) { + const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); + } + // The inner arc from point 5 to point b to point 6 + const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2; + ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true); + ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true); + // The corner segment from point 6 to point 7 + if (innerStart > 0) { + const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); + } + // The line from point 7 to point 8 + const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); + ctx.lineTo(p8.x, p8.y); + // The corner segment from point 8 to point 1 + if (outerStart > 0) { + const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); + } + } else { + ctx.moveTo(x, y); + const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x; + const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y; + ctx.lineTo(outerStartX, outerStartY); + const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x; + const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y; + ctx.lineTo(outerEndX, outerEndY); + } + ctx.closePath(); +} +function drawArc(ctx, element, offset, spacing, circular) { + const { fullCircles , startAngle , circumference } = element; + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + for(let i = 0; i < fullCircles; ++i){ + ctx.fill(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + (circumference % TAU || TAU); + } + } + pathArc(ctx, element, offset, spacing, endAngle, circular); + ctx.fill(); + return endAngle; +} +function drawBorder(ctx, element, offset, spacing, circular) { + const { fullCircles , startAngle , circumference , options } = element; + const { borderWidth , borderJoinStyle , borderDash , borderDashOffset } = options; + const inner = options.borderAlign === 'inner'; + if (!borderWidth) { + return; + } + ctx.setLineDash(borderDash || []); + ctx.lineDashOffset = borderDashOffset; + if (inner) { + ctx.lineWidth = borderWidth * 2; + ctx.lineJoin = borderJoinStyle || 'round'; + } else { + ctx.lineWidth = borderWidth; + ctx.lineJoin = borderJoinStyle || 'bevel'; + } + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + for(let i = 0; i < fullCircles; ++i){ + ctx.stroke(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + (circumference % TAU || TAU); + } + } + if (inner) { + clipArc(ctx, element, endAngle); + } + if (!fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + ctx.stroke(); + } +} +class ArcElement extends Element { + static id = 'arc'; + static defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: undefined, + borderRadius: 0, + borderWidth: 2, + offset: 0, + spacing: 0, + angle: undefined, + circular: true + }; + static defaultRoutes = { + backgroundColor: 'backgroundColor' + }; + static descriptors = { + _scriptable: true, + _indexable: (name)=>name !== 'borderDash' + }; + circumference; + endAngle; + fullCircles; + innerRadius; + outerRadius; + pixelMargin; + startAngle; + constructor(cfg){ + super(); + this.options = undefined; + this.circumference = undefined; + this.startAngle = undefined; + this.endAngle = undefined; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.pixelMargin = 0; + this.fullCircles = 0; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(chartX, chartY, useFinalPosition) { + const point = this.getProps([ + 'x', + 'y' + ], useFinalPosition); + const { angle , distance } = getAngleFromPoint(point, { + x: chartX, + y: chartY + }); + const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([ + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference' + ], useFinalPosition); + const rAdjust = (this.options.spacing + this.options.borderWidth) / 2; + const _circumference = valueOrDefault(circumference, endAngle - startAngle); + const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); + const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); + return betweenAngles && withinRadius; + } + getCenterPoint(useFinalPosition) { + const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius' + ], useFinalPosition); + const { offset , spacing } = this.options; + const halfAngle = (startAngle + endAngle) / 2; + const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + } + draw(ctx) { + const { options , circumference } = this; + const offset = (options.offset || 0) / 4; + const spacing = (options.spacing || 0) / 2; + const circular = options.circular; + this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0; + this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; + if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { + return; + } + ctx.save(); + const halfAngle = (this.startAngle + this.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); + const fix = 1 - Math.sin(Math.min(PI, circumference || 0)); + const radiusOffset = offset * fix; + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + drawArc(ctx, this, radiusOffset, spacing, circular); + drawBorder(ctx, this, radiusOffset, spacing, circular); + ctx.restore(); + } +} + function setStyle(ctx, options, style = options) { - ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); - ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); - ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); - ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); - ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); - ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); + ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); + ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); + ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); + ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); + ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); + ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); } function lineTo(ctx, previous, target) { - ctx.lineTo(target.x, target.y); + ctx.lineTo(target.x, target.y); } -function getLineMethod(options) { - if (options.stepped) { - return _steppedLineTo; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierCurveTo; - } - return lineTo; + function getLineMethod(options) { + if (options.stepped) { + return _steppedLineTo; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierCurveTo; + } + return lineTo; } function pathVars(points, segment, params = {}) { - const count = points.length; - const {start: paramsStart = 0, end: paramsEnd = count - 1} = params; - const {start: segmentStart, end: segmentEnd} = segment; - const start = Math.max(paramsStart, segmentStart); - const end = Math.min(paramsEnd, segmentEnd); - const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; - return { - count, - start, - loop: segment.loop, - ilen: end < start && !outside ? count + end - start : end - start - }; + const count = points.length; + const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params; + const { start: segmentStart , end: segmentEnd } = segment; + const start = Math.max(paramsStart, segmentStart); + const end = Math.min(paramsEnd, segmentEnd); + const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; + return { + count, + start, + loop: segment.loop, + ilen: end < start && !outside ? count + end - start : end - start + }; } -function pathSegment(ctx, line, segment, params) { - const {points, options} = line; - const {count, start, loop, ilen} = pathVars(points, segment, params); - const lineMethod = getLineMethod(options); - let {move = true, reverse} = params || {}; - let i, point, prev; - for (i = 0; i <= ilen; ++i) { - point = points[(start + (reverse ? ilen - i : i)) % count]; - if (point.skip) { - continue; - } else if (move) { - ctx.moveTo(point.x, point.y); - move = false; - } else { - lineMethod(ctx, prev, point, reverse, options.stepped); + function pathSegment(ctx, line, segment, params) { + const { points , options } = line; + const { count , start , loop , ilen } = pathVars(points, segment, params); + const lineMethod = getLineMethod(options); + let { move =true , reverse } = params || {}; + let i, point, prev; + for(i = 0; i <= ilen; ++i){ + point = points[(start + (reverse ? ilen - i : i)) % count]; + if (point.skip) { + continue; + } else if (move) { + ctx.moveTo(point.x, point.y); + move = false; + } else { + lineMethod(ctx, prev, point, reverse, options.stepped); + } + prev = point; } - prev = point; - } - if (loop) { - point = points[(start + (reverse ? ilen : 0)) % count]; - lineMethod(ctx, prev, point, reverse, options.stepped); - } - return !!loop; + if (loop) { + point = points[(start + (reverse ? ilen : 0)) % count]; + lineMethod(ctx, prev, point, reverse, options.stepped); + } + return !!loop; } -function fastPathSegment(ctx, line, segment, params) { - const points = line.points; - const {count, start, ilen} = pathVars(points, segment, params); - const {move = true, reverse} = params || {}; - let avgX = 0; - let countX = 0; - let i, point, prevX, minY, maxY, lastY; - const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; - const drawX = () => { - if (minY !== maxY) { - ctx.lineTo(avgX, maxY); - ctx.lineTo(avgX, minY); - ctx.lineTo(avgX, lastY); + function fastPathSegment(ctx, line, segment, params) { + const points = line.points; + const { count , start , ilen } = pathVars(points, segment, params); + const { move =true , reverse } = params || {}; + let avgX = 0; + let countX = 0; + let i, point, prevX, minY, maxY, lastY; + const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count; + const drawX = ()=>{ + if (minY !== maxY) { + ctx.lineTo(avgX, maxY); + ctx.lineTo(avgX, minY); + ctx.lineTo(avgX, lastY); + } + }; + if (move) { + point = points[pointIndex(0)]; + ctx.moveTo(point.x, point.y); } - }; - if (move) { - point = points[pointIndex(0)]; - ctx.moveTo(point.x, point.y); - } - for (i = 0; i <= ilen; ++i) { - point = points[pointIndex(i)]; - if (point.skip) { - continue; + for(i = 0; i <= ilen; ++i){ + point = points[pointIndex(i)]; + if (point.skip) { + continue; + } + const x = point.x; + const y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + avgX = (countX * avgX + x) / ++countX; + } else { + drawX(); + ctx.lineTo(x, y); + prevX = truncX; + countX = 0; + minY = maxY = y; + } + lastY = y; } - const x = point.x; - const y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - } else if (y > maxY) { - maxY = y; - } - avgX = (countX * avgX + x) / ++countX; - } else { - drawX(); - ctx.lineTo(x, y); - prevX = truncX; - countX = 0; - minY = maxY = y; - } - lastY = y; - } - drawX(); + drawX(); } -function _getSegmentMethod(line) { - const opts = line.options; - const borderDash = opts.borderDash && opts.borderDash.length; - const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; - return useFastPath ? fastPathSegment : pathSegment; + function _getSegmentMethod(line) { + const opts = line.options; + const borderDash = opts.borderDash && opts.borderDash.length; + const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; + return useFastPath ? fastPathSegment : pathSegment; } -function _getInterpolationMethod(options) { - if (options.stepped) { - return _steppedInterpolation; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierInterpolation; - } - return _pointInLine; + function _getInterpolationMethod(options) { + if (options.stepped) { + return _steppedInterpolation; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierInterpolation; + } + return _pointInLine; } function strokePathWithCache(ctx, line, start, count) { - let path = line._path; - if (!path) { - path = line._path = new Path2D(); - if (line.path(path, start, count)) { - path.closePath(); + let path = line._path; + if (!path) { + path = line._path = new Path2D(); + if (line.path(path, start, count)) { + path.closePath(); + } } - } - setStyle(ctx, line.options); - ctx.stroke(path); + setStyle(ctx, line.options); + ctx.stroke(path); } function strokePathDirect(ctx, line, start, count) { - const {segments, options} = line; - const segmentMethod = _getSegmentMethod(line); - for (const segment of segments) { - setStyle(ctx, options, segment.style); - ctx.beginPath(); - if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) { - ctx.closePath(); + const { segments , options } = line; + const segmentMethod = _getSegmentMethod(line); + for (const segment of segments){ + setStyle(ctx, options, segment.style); + ctx.beginPath(); + if (segmentMethod(ctx, line, segment, { + start, + end: start + count - 1 + })) { + ctx.closePath(); + } + ctx.stroke(); } - ctx.stroke(); - } } const usePath2D = typeof Path2D === 'function'; function draw(ctx, line, start, count) { - if (usePath2D && !line.options.segment) { - strokePathWithCache(ctx, line, start, count); - } else { - strokePathDirect(ctx, line, start, count); - } + if (usePath2D && !line.options.segment) { + strokePathWithCache(ctx, line, start, count); + } else { + strokePathDirect(ctx, line, start, count); + } } class LineElement extends Element { - constructor(cfg) { - super(); - this.animated = true; - this.options = undefined; - this._chart = undefined; - this._loop = undefined; - this._fullLoop = undefined; - this._path = undefined; - this._points = undefined; - this._segments = undefined; - this._decimated = false; - this._pointsUpdated = false; - this._datasetIndex = undefined; - if (cfg) { - Object.assign(this, cfg); + static id = 'line'; + static defaults = { + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: 'miter', + borderWidth: 3, + capBezierPoints: true, + cubicInterpolationMode: 'default', + fill: false, + spanGaps: false, + stepped: false, + tension: 0 + }; + static defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' + }; + static descriptors = { + _scriptable: true, + _indexable: (name)=>name !== 'borderDash' && name !== 'fill' + }; + constructor(cfg){ + super(); + this.animated = true; + this.options = undefined; + this._chart = undefined; + this._loop = undefined; + this._fullLoop = undefined; + this._path = undefined; + this._points = undefined; + this._segments = undefined; + this._decimated = false; + this._pointsUpdated = false; + this._datasetIndex = undefined; + if (cfg) { + Object.assign(this, cfg); + } } - } - updateControlPoints(chartArea, indexAxis) { - const options = this.options; - if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { - const loop = options.spanGaps ? this._loop : this._fullLoop; - _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); - this._pointsUpdated = true; + updateControlPoints(chartArea, indexAxis) { + const options = this.options; + if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { + const loop = options.spanGaps ? this._loop : this._fullLoop; + _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); + this._pointsUpdated = true; + } } - } - set points(points) { - this._points = points; - delete this._segments; - delete this._path; - this._pointsUpdated = false; - } - get points() { - return this._points; - } - get segments() { - return this._segments || (this._segments = _computeSegments(this, this.options.segment)); - } - first() { - const segments = this.segments; - const points = this.points; - return segments.length && points[segments[0].start]; - } - last() { - const segments = this.segments; - const points = this.points; - const count = segments.length; - return count && points[segments[count - 1].end]; - } - interpolate(point, property) { - const options = this.options; - const value = point[property]; - const points = this.points; - const segments = _boundSegments(this, {property, start: value, end: value}); - if (!segments.length) { - return; + set points(points) { + this._points = points; + delete this._segments; + delete this._path; + this._pointsUpdated = false; } - const result = []; - const _interpolate = _getInterpolationMethod(options); - let i, ilen; - for (i = 0, ilen = segments.length; i < ilen; ++i) { - const {start, end} = segments[i]; - const p1 = points[start]; - const p2 = points[end]; - if (p1 === p2) { - result.push(p1); - continue; - } - const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); - const interpolated = _interpolate(p1, p2, t, options.stepped); - interpolated[property] = point[property]; - result.push(interpolated); + get points() { + return this._points; } - return result.length === 1 ? result[0] : result; - } - pathSegment(ctx, segment, params) { - const segmentMethod = _getSegmentMethod(this); - return segmentMethod(ctx, this, segment, params); - } - path(ctx, start, count) { - const segments = this.segments; - const segmentMethod = _getSegmentMethod(this); - let loop = this._loop; - start = start || 0; - count = count || (this.points.length - start); - for (const segment of segments) { - loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1}); + get segments() { + return this._segments || (this._segments = _computeSegments(this, this.options.segment)); } - return !!loop; - } - draw(ctx, chartArea, start, count) { - const options = this.options || {}; - const points = this.points || []; - if (points.length && options.borderWidth) { - ctx.save(); - draw(ctx, this, start, count); - ctx.restore(); + first() { + const segments = this.segments; + const points = this.points; + return segments.length && points[segments[0].start]; } - if (this.animated) { - this._pointsUpdated = false; - this._path = undefined; + last() { + const segments = this.segments; + const points = this.points; + const count = segments.length; + return count && points[segments[count - 1].end]; + } + interpolate(point, property) { + const options = this.options; + const value = point[property]; + const points = this.points; + const segments = _boundSegments(this, { + property, + start: value, + end: value + }); + if (!segments.length) { + return; + } + const result = []; + const _interpolate = _getInterpolationMethod(options); + let i, ilen; + for(i = 0, ilen = segments.length; i < ilen; ++i){ + const { start , end } = segments[i]; + const p1 = points[start]; + const p2 = points[end]; + if (p1 === p2) { + result.push(p1); + continue; + } + const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); + const interpolated = _interpolate(p1, p2, t, options.stepped); + interpolated[property] = point[property]; + result.push(interpolated); + } + return result.length === 1 ? result[0] : result; + } + pathSegment(ctx, segment, params) { + const segmentMethod = _getSegmentMethod(this); + return segmentMethod(ctx, this, segment, params); + } + path(ctx, start, count) { + const segments = this.segments; + const segmentMethod = _getSegmentMethod(this); + let loop = this._loop; + start = start || 0; + count = count || this.points.length - start; + for (const segment of segments){ + loop &= segmentMethod(ctx, this, segment, { + start, + end: start + count - 1 + }); + } + return !!loop; + } + draw(ctx, chartArea, start, count) { + const options = this.options || {}; + const points = this.points || []; + if (points.length && options.borderWidth) { + ctx.save(); + draw(ctx, this, start, count); + ctx.restore(); + } + if (this.animated) { + this._pointsUpdated = false; + this._path = undefined; + } } - } } -LineElement.id = 'line'; -LineElement.defaults = { - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0, - borderJoinStyle: 'miter', - borderWidth: 3, - capBezierPoints: true, - cubicInterpolationMode: 'default', - fill: false, - spanGaps: false, - stepped: false, - tension: 0, -}; -LineElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; -LineElement.descriptors = { - _scriptable: true, - _indexable: (name) => name !== 'borderDash' && name !== 'fill', -}; function inRange$1(el, pos, axis, useFinalPosition) { - const options = el.options; - const {[axis]: value} = el.getProps([axis], useFinalPosition); - return (Math.abs(pos - value) < options.radius + options.hitRadius); + const options = el.options; + const { [axis]: value } = el.getProps([ + axis + ], useFinalPosition); + return Math.abs(pos - value) < options.radius + options.hitRadius; } class PointElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.parsed = undefined; - this.skip = undefined; - this.stop = undefined; - if (cfg) { - Object.assign(this, cfg); + static id = 'point'; + parsed; + skip; + stop; + /** + * @type {any} + */ static defaults = { + borderWidth: 1, + hitRadius: 1, + hoverBorderWidth: 1, + hoverRadius: 4, + pointStyle: 'circle', + radius: 3, + rotation: 0 + }; + /** + * @type {any} + */ static defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' + }; + constructor(cfg){ + super(); + this.options = undefined; + this.parsed = undefined; + this.skip = undefined; + this.stop = undefined; + if (cfg) { + Object.assign(this, cfg); + } } - } - inRange(mouseX, mouseY, useFinalPosition) { - const options = this.options; - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); - } - inXRange(mouseX, useFinalPosition) { - return inRange$1(this, mouseX, 'x', useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange$1(this, mouseY, 'y', useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - size(options) { - options = options || this.options || {}; - let radius = options.radius || 0; - radius = Math.max(radius, radius && options.hoverRadius || 0); - const borderWidth = radius && options.borderWidth || 0; - return (radius + borderWidth) * 2; - } - draw(ctx, area) { - const options = this.options; - if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { - return; + inRange(mouseX, mouseY, useFinalPosition) { + const options = this.options; + const { x , y } = this.getProps([ + 'x', + 'y' + ], useFinalPosition); + return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2); + } + inXRange(mouseX, useFinalPosition) { + return inRange$1(this, mouseX, 'x', useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange$1(this, mouseY, 'y', useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const { x , y } = this.getProps([ + 'x', + 'y' + ], useFinalPosition); + return { + x, + y + }; + } + size(options) { + options = options || this.options || {}; + let radius = options.radius || 0; + radius = Math.max(radius, radius && options.hoverRadius || 0); + const borderWidth = radius && options.borderWidth || 0; + return (radius + borderWidth) * 2; + } + draw(ctx, area) { + const options = this.options; + if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { + return; + } + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.fillStyle = options.backgroundColor; + drawPoint(ctx, options, this.x, this.y); + } + getRange() { + const options = this.options || {}; + // @ts-expect-error Fallbacks should never be hit in practice + return options.radius + options.hitRadius; } - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.fillStyle = options.backgroundColor; - drawPoint(ctx, options, this.x, this.y); - } - getRange() { - const options = this.options || {}; - return options.radius + options.hitRadius; - } } -PointElement.id = 'point'; -PointElement.defaults = { - borderWidth: 1, - hitRadius: 1, - hoverBorderWidth: 1, - hoverRadius: 4, - pointStyle: 'circle', - radius: 3, - rotation: 0 -}; -PointElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; function getBarBounds(bar, useFinalPosition) { - const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); - let left, right, top, bottom, half; - if (bar.horizontal) { - half = height / 2; - left = Math.min(x, base); - right = Math.max(x, base); - top = y - half; - bottom = y + half; - } else { - half = width / 2; - left = x - half; - right = x + half; - top = Math.min(y, base); - bottom = Math.max(y, base); - } - return {left, top, right, bottom}; + const { x , y , base , width , height } = bar.getProps([ + 'x', + 'y', + 'base', + 'width', + 'height' + ], useFinalPosition); + let left, right, top, bottom, half; + if (bar.horizontal) { + half = height / 2; + left = Math.min(x, base); + right = Math.max(x, base); + top = y - half; + bottom = y + half; + } else { + half = width / 2; + left = x - half; + right = x + half; + top = Math.min(y, base); + bottom = Math.max(y, base); + } + return { + left, + top, + right, + bottom + }; } function skipOrLimit(skip, value, min, max) { - return skip ? 0 : _limitValue(value, min, max); + return skip ? 0 : _limitValue(value, min, max); } function parseBorderWidth(bar, maxW, maxH) { - const value = bar.options.borderWidth; - const skip = bar.borderSkipped; - const o = toTRBL(value); - return { - t: skipOrLimit(skip.top, o.top, 0, maxH), - r: skipOrLimit(skip.right, o.right, 0, maxW), - b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), - l: skipOrLimit(skip.left, o.left, 0, maxW) - }; + const value = bar.options.borderWidth; + const skip = bar.borderSkipped; + const o = toTRBL(value); + return { + t: skipOrLimit(skip.top, o.top, 0, maxH), + r: skipOrLimit(skip.right, o.right, 0, maxW), + b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), + l: skipOrLimit(skip.left, o.left, 0, maxW) + }; } function parseBorderRadius(bar, maxW, maxH) { - const {enableBorderRadius} = bar.getProps(['enableBorderRadius']); - const value = bar.options.borderRadius; - const o = toTRBLCorners(value); - const maxR = Math.min(maxW, maxH); - const skip = bar.borderSkipped; - const enableBorder = enableBorderRadius || isObject(value); - return { - topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), - topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), - bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), - bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) - }; + const { enableBorderRadius } = bar.getProps([ + 'enableBorderRadius' + ]); + const value = bar.options.borderRadius; + const o = toTRBLCorners(value); + const maxR = Math.min(maxW, maxH); + const skip = bar.borderSkipped; + const enableBorder = enableBorderRadius || isObject(value); + return { + topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), + topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), + bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), + bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) + }; } function boundingRects(bar) { - const bounds = getBarBounds(bar); - const width = bounds.right - bounds.left; - const height = bounds.bottom - bounds.top; - const border = parseBorderWidth(bar, width / 2, height / 2); - const radius = parseBorderRadius(bar, width / 2, height / 2); - return { - outer: { - x: bounds.left, - y: bounds.top, - w: width, - h: height, - radius - }, - inner: { - x: bounds.left + border.l, - y: bounds.top + border.t, - w: width - border.l - border.r, - h: height - border.t - border.b, - radius: { - topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), - topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), - bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), - bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)), - } - } - }; + const bounds = getBarBounds(bar); + const width = bounds.right - bounds.left; + const height = bounds.bottom - bounds.top; + const border = parseBorderWidth(bar, width / 2, height / 2); + const radius = parseBorderRadius(bar, width / 2, height / 2); + return { + outer: { + x: bounds.left, + y: bounds.top, + w: width, + h: height, + radius + }, + inner: { + x: bounds.left + border.l, + y: bounds.top + border.t, + w: width - border.l - border.r, + h: height - border.t - border.b, + radius: { + topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), + topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), + bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), + bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)) + } + } + }; } function inRange(bar, x, y, useFinalPosition) { - const skipX = x === null; - const skipY = y === null; - const skipBoth = skipX && skipY; - const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); - return bounds - && (skipX || _isBetween(x, bounds.left, bounds.right)) - && (skipY || _isBetween(y, bounds.top, bounds.bottom)); + const skipX = x === null; + const skipY = y === null; + const skipBoth = skipX && skipY; + const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); + return bounds && (skipX || _isBetween(x, bounds.left, bounds.right)) && (skipY || _isBetween(y, bounds.top, bounds.bottom)); } function hasRadius(radius) { - return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; + return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; } -function addNormalRectPath(ctx, rect) { - ctx.rect(rect.x, rect.y, rect.w, rect.h); + function addNormalRectPath(ctx, rect) { + ctx.rect(rect.x, rect.y, rect.w, rect.h); } function inflateRect(rect, amount, refRect = {}) { - const x = rect.x !== refRect.x ? -amount : 0; - const y = rect.y !== refRect.y ? -amount : 0; - const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; - const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; - return { - x: rect.x + x, - y: rect.y + y, - w: rect.w + w, - h: rect.h + h, - radius: rect.radius - }; + const x = rect.x !== refRect.x ? -amount : 0; + const y = rect.y !== refRect.y ? -amount : 0; + const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; + const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; + return { + x: rect.x + x, + y: rect.y + y, + w: rect.w + w, + h: rect.h + h, + radius: rect.radius + }; } class BarElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.horizontal = undefined; - this.base = undefined; - this.width = undefined; - this.height = undefined; - this.inflateAmount = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - draw(ctx) { - const {inflateAmount, options: {borderColor, backgroundColor}} = this; - const {inner, outer} = boundingRects(this); - const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; - ctx.save(); - if (outer.w !== inner.w || outer.h !== inner.h) { - ctx.beginPath(); - addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); - ctx.clip(); - addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); - ctx.fillStyle = borderColor; - ctx.fill('evenodd'); - } - ctx.beginPath(); - addRectPath(ctx, inflateRect(inner, inflateAmount)); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - inRange(mouseX, mouseY, useFinalPosition) { - return inRange(this, mouseX, mouseY, useFinalPosition); - } - inXRange(mouseX, useFinalPosition) { - return inRange(this, mouseX, null, useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange(this, null, mouseY, useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); - return { - x: horizontal ? (x + base) / 2 : x, - y: horizontal ? y : (y + base) / 2 + static id = 'bar'; + static defaults = { + borderSkipped: 'start', + borderWidth: 0, + borderRadius: 0, + inflateAmount: 'auto', + pointStyle: undefined }; - } - getRange(axis) { - return axis === 'x' ? this.width / 2 : this.height / 2; - } + static defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' + }; + constructor(cfg){ + super(); + this.options = undefined; + this.horizontal = undefined; + this.base = undefined; + this.width = undefined; + this.height = undefined; + this.inflateAmount = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + draw(ctx) { + const { inflateAmount , options: { borderColor , backgroundColor } } = this; + const { inner , outer } = boundingRects(this); + const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; + ctx.save(); + if (outer.w !== inner.w || outer.h !== inner.h) { + ctx.beginPath(); + addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); + ctx.clip(); + addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); + ctx.fillStyle = borderColor; + ctx.fill('evenodd'); + } + ctx.beginPath(); + addRectPath(ctx, inflateRect(inner, inflateAmount)); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + inRange(mouseX, mouseY, useFinalPosition) { + return inRange(this, mouseX, mouseY, useFinalPosition); + } + inXRange(mouseX, useFinalPosition) { + return inRange(this, mouseX, null, useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange(this, null, mouseY, useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const { x , y , base , horizontal } = this.getProps([ + 'x', + 'y', + 'base', + 'horizontal' + ], useFinalPosition); + return { + x: horizontal ? (x + base) / 2 : x, + y: horizontal ? y : (y + base) / 2 + }; + } + getRange(axis) { + return axis === 'x' ? this.width / 2 : this.height / 2; + } } -BarElement.id = 'bar'; -BarElement.defaults = { - borderSkipped: 'start', - borderWidth: 0, - borderRadius: 0, - inflateAmount: 'auto', - pointStyle: undefined -}; -BarElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; var elements = /*#__PURE__*/Object.freeze({ __proto__: null, ArcElement: ArcElement, +BarElement: BarElement, LineElement: LineElement, -PointElement: PointElement, -BarElement: BarElement +PointElement: PointElement }); +const BORDER_COLORS = [ + 'rgb(54, 162, 235)', + 'rgb(255, 99, 132)', + 'rgb(255, 159, 64)', + 'rgb(255, 205, 86)', + 'rgb(75, 192, 192)', + 'rgb(153, 102, 255)', + 'rgb(201, 203, 207)' // grey +]; +// Border colors with 50% transparency +const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)')); +function getBorderColor(i) { + return BORDER_COLORS[i % BORDER_COLORS.length]; +} +function getBackgroundColor(i) { + return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length]; +} +function colorizeDefaultDataset(dataset, i) { + dataset.borderColor = getBorderColor(i); + dataset.backgroundColor = getBackgroundColor(i); + return ++i; +} +function colorizeDoughnutDataset(dataset, i) { + dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++)); + return i; +} +function colorizePolarAreaDataset(dataset, i) { + dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++)); + return i; +} +function getColorizer(chart) { + let i = 0; + return (dataset, datasetIndex)=>{ + const controller = chart.getDatasetMeta(datasetIndex).controller; + if (controller instanceof DoughnutController) { + i = colorizeDoughnutDataset(dataset, i); + } else if (controller instanceof PolarAreaController) { + i = colorizePolarAreaDataset(dataset, i); + } else if (controller) { + i = colorizeDefaultDataset(dataset, i); + } + }; +} +function containsColorsDefinitions(descriptors) { + let k; + for(k in descriptors){ + if (descriptors[k].borderColor || descriptors[k].backgroundColor) { + return true; + } + } + return false; +} +function containsColorsDefinition(descriptor) { + return descriptor && (descriptor.borderColor || descriptor.backgroundColor); +} +var plugin_colors = { + id: 'colors', + defaults: { + enabled: true, + forceOverride: false + }, + beforeLayout (chart, _args, options) { + if (!options.enabled) { + return; + } + const { data: { datasets } , options: chartOptions } = chart.config; + const { elements } = chartOptions; + if (!options.forceOverride && (containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements))) { + return; + } + const colorizer = getColorizer(chart); + datasets.forEach(colorizer); + } +}; + function lttbDecimation(data, start, count, availableWidth, options) { - const samples = options.samples || availableWidth; - if (samples >= count) { - return data.slice(start, start + count); - } - const decimated = []; - const bucketWidth = (count - 2) / (samples - 2); - let sampledIndex = 0; - const endIndex = start + count - 1; - let a = start; - let i, maxAreaPoint, maxArea, area, nextA; - decimated[sampledIndex++] = data[a]; - for (i = 0; i < samples - 2; i++) { - let avgX = 0; - let avgY = 0; - let j; - const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; - const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; - const avgRangeLength = avgRangeEnd - avgRangeStart; - for (j = avgRangeStart; j < avgRangeEnd; j++) { - avgX += data[j].x; - avgY += data[j].y; + const samples = options.samples || availableWidth; + if (samples >= count) { + return data.slice(start, start + count); } - avgX /= avgRangeLength; - avgY /= avgRangeLength; - const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; - const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; - const {x: pointAx, y: pointAy} = data[a]; - maxArea = area = -1; - for (j = rangeOffs; j < rangeTo; j++) { - area = 0.5 * Math.abs( - (pointAx - avgX) * (data[j].y - pointAy) - - (pointAx - data[j].x) * (avgY - pointAy) - ); - if (area > maxArea) { - maxArea = area; - maxAreaPoint = data[j]; - nextA = j; - } + const decimated = []; + const bucketWidth = (count - 2) / (samples - 2); + let sampledIndex = 0; + const endIndex = start + count - 1; + let a = start; + let i, maxAreaPoint, maxArea, area, nextA; + decimated[sampledIndex++] = data[a]; + for(i = 0; i < samples - 2; i++){ + let avgX = 0; + let avgY = 0; + let j; + const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; + const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; + const avgRangeLength = avgRangeEnd - avgRangeStart; + for(j = avgRangeStart; j < avgRangeEnd; j++){ + avgX += data[j].x; + avgY += data[j].y; + } + avgX /= avgRangeLength; + avgY /= avgRangeLength; + const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; + const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; + const { x: pointAx , y: pointAy } = data[a]; + maxArea = area = -1; + for(j = rangeOffs; j < rangeTo; j++){ + area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy)); + if (area > maxArea) { + maxArea = area; + maxAreaPoint = data[j]; + nextA = j; + } + } + decimated[sampledIndex++] = maxAreaPoint; + a = nextA; } - decimated[sampledIndex++] = maxAreaPoint; - a = nextA; - } - decimated[sampledIndex++] = data[endIndex]; - return decimated; + decimated[sampledIndex++] = data[endIndex]; + return decimated; } function minMaxDecimation(data, start, count, availableWidth) { - let avgX = 0; - let countX = 0; - let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; - const decimated = []; - const endIndex = start + count - 1; - const xMin = data[start].x; - const xMax = data[endIndex].x; - const dx = xMax - xMin; - for (i = start; i < start + count; ++i) { - point = data[i]; - x = (point.x - xMin) / dx * availableWidth; - y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - minIndex = i; - } else if (y > maxY) { - maxY = y; - maxIndex = i; - } - avgX = (countX * avgX + point.x) / ++countX; - } else { - const lastIndex = i - 1; - if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { - const intermediateIndex1 = Math.min(minIndex, maxIndex); - const intermediateIndex2 = Math.max(minIndex, maxIndex); - if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex1], - x: avgX, - }); + let avgX = 0; + let countX = 0; + let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; + const decimated = []; + const endIndex = start + count - 1; + const xMin = data[start].x; + const xMax = data[endIndex].x; + const dx = xMax - xMin; + for(i = start; i < start + count; ++i){ + point = data[i]; + x = (point.x - xMin) / dx * availableWidth; + y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + minIndex = i; + } else if (y > maxY) { + maxY = y; + maxIndex = i; + } + avgX = (countX * avgX + point.x) / ++countX; + } else { + const lastIndex = i - 1; + if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { + const intermediateIndex1 = Math.min(minIndex, maxIndex); + const intermediateIndex2 = Math.max(minIndex, maxIndex); + if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex1], + x: avgX + }); + } + if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex2], + x: avgX + }); + } + } + if (i > 0 && lastIndex !== startIndex) { + decimated.push(data[lastIndex]); + } + decimated.push(point); + prevX = truncX; + countX = 0; + minY = maxY = y; + minIndex = maxIndex = startIndex = i; } - if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex2], - x: avgX - }); - } - } - if (i > 0 && lastIndex !== startIndex) { - decimated.push(data[lastIndex]); - } - decimated.push(point); - prevX = truncX; - countX = 0; - minY = maxY = y; - minIndex = maxIndex = startIndex = i; } - } - return decimated; + return decimated; } function cleanDecimatedDataset(dataset) { - if (dataset._decimated) { - const data = dataset._data; - delete dataset._decimated; - delete dataset._data; - Object.defineProperty(dataset, 'data', {value: data}); - } + if (dataset._decimated) { + const data = dataset._data; + delete dataset._decimated; + delete dataset._data; + Object.defineProperty(dataset, 'data', { + configurable: true, + enumerable: true, + writable: true, + value: data + }); + } } function cleanDecimatedData(chart) { - chart.data.datasets.forEach((dataset) => { - cleanDecimatedDataset(dataset); - }); + chart.data.datasets.forEach((dataset)=>{ + cleanDecimatedDataset(dataset); + }); } function getStartAndCountOfVisiblePointsSimplified(meta, points) { - const pointCount = points.length; - let start = 0; - let count; - const {iScale} = meta; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); - } - if (maxDefined) { - count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; - } else { - count = pointCount - start; - } - return {start, count}; + const pointCount = points.length; + let start = 0; + let count; + const { iScale } = meta; + const { min , max , minDefined , maxDefined } = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; + } else { + count = pointCount - start; + } + return { + start, + count + }; } var plugin_decimation = { - id: 'decimation', - defaults: { - algorithm: 'min-max', - enabled: false, - }, - beforeElementsUpdate: (chart, args, options) => { - if (!options.enabled) { - cleanDecimatedData(chart); - return; - } - const availableWidth = chart.width; - chart.data.datasets.forEach((dataset, datasetIndex) => { - const {_data, indexAxis} = dataset; - const meta = chart.getDatasetMeta(datasetIndex); - const data = _data || dataset.data; - if (resolve([indexAxis, chart.options.indexAxis]) === 'y') { - return; - } - if (meta.type !== 'line') { - return; - } - const xAxis = chart.scales[meta.xAxisID]; - if (xAxis.type !== 'linear' && xAxis.type !== 'time') { - return; - } - if (chart.options.parsing) { - return; - } - let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data); - const threshold = options.threshold || 4 * availableWidth; - if (count <= threshold) { - cleanDecimatedDataset(dataset); - return; - } - if (isNullOrUndef(_data)) { - dataset._data = data; - delete dataset.data; - Object.defineProperty(dataset, 'data', { - configurable: true, - enumerable: true, - get: function() { - return this._decimated; - }, - set: function(d) { - this._data = d; - } + id: 'decimation', + defaults: { + algorithm: 'min-max', + enabled: false + }, + beforeElementsUpdate: (chart, args, options)=>{ + if (!options.enabled) { + cleanDecimatedData(chart); + return; + } + const availableWidth = chart.width; + chart.data.datasets.forEach((dataset, datasetIndex)=>{ + const { _data , indexAxis } = dataset; + const meta = chart.getDatasetMeta(datasetIndex); + const data = _data || dataset.data; + if (resolve([ + indexAxis, + chart.options.indexAxis + ]) === 'y') { + return; + } + if (!meta.controller.supportsDecimation) { + return; + } + const xAxis = chart.scales[meta.xAxisID]; + if (xAxis.type !== 'linear' && xAxis.type !== 'time') { + return; + } + if (chart.options.parsing) { + return; + } + let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data); + const threshold = options.threshold || 4 * availableWidth; + if (count <= threshold) { + cleanDecimatedDataset(dataset); + return; + } + if (isNullOrUndef(_data)) { + dataset._data = data; + delete dataset.data; + Object.defineProperty(dataset, 'data', { + configurable: true, + enumerable: true, + get: function() { + return this._decimated; + }, + set: function(d) { + this._data = d; + } + }); + } + let decimated; + switch(options.algorithm){ + case 'lttb': + decimated = lttbDecimation(data, start, count, availableWidth, options); + break; + case 'min-max': + decimated = minMaxDecimation(data, start, count, availableWidth); + break; + default: + throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); + } + dataset._decimated = decimated; }); - } - let decimated; - switch (options.algorithm) { - case 'lttb': - decimated = lttbDecimation(data, start, count, availableWidth, options); - break; - case 'min-max': - decimated = minMaxDecimation(data, start, count, availableWidth); - break; - default: - throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); - } - dataset._decimated = decimated; - }); - }, - destroy(chart) { - cleanDecimatedData(chart); - } + }, + destroy (chart) { + cleanDecimatedData(chart); + } }; -function getLineByIndex(chart, index) { - const meta = chart.getDatasetMeta(index); - const visible = meta && chart.isDatasetVisible(index); - return visible ? meta.dataset : null; -} -function parseFillOption(line) { - const options = line.options; - const fillOption = options.fill; - let fill = valueOrDefault(fillOption && fillOption.target, fillOption); - if (fill === undefined) { - fill = !!options.backgroundColor; - } - if (fill === false || fill === null) { - return false; - } - if (fill === true) { - return 'origin'; - } - return fill; -} -function decodeFill(line, index, count) { - const fill = parseFillOption(line); - if (isObject(fill)) { - return isNaN(fill.value) ? false : fill; - } - let target = parseFloat(fill); - if (isNumberFinite(target) && Math.floor(target) === target) { - if (fill[0] === '-' || fill[0] === '+') { - target = index + target; +function _segments(line, target, property) { + const segments = line.segments; + const points = line.points; + const tpoints = target.points; + const parts = []; + for (const segment of segments){ + let { start , end } = segment; + end = _findSegmentEnd(start, end, points); + const bounds = _getBounds(property, points[start], points[end], segment.loop); + if (!target.segments) { + parts.push({ + source: segment, + target: bounds, + start: points[start], + end: points[end] + }); + continue; + } + const targetSegments = _boundSegments(target, bounds); + for (const tgt of targetSegments){ + const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); + const fillSources = _boundSegment(segment, points, subBounds); + for (const fillSource of fillSources){ + parts.push({ + source: fillSource, + target: tgt, + start: { + [property]: _getEdge(bounds, subBounds, 'start', Math.max) + }, + end: { + [property]: _getEdge(bounds, subBounds, 'end', Math.min) + } + }); + } + } } - if (target === index || target < 0 || target >= count) { - return false; + return parts; +} +function _getBounds(property, first, last, loop) { + if (loop) { + return; + } + let start = first[property]; + let end = last[property]; + if (property === 'angle') { + start = _normalizeAngle(start); + end = _normalizeAngle(end); } - return target; - } - return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill; -} -function computeLinearBoundary(source) { - const {scale = {}, fill} = source; - let target = null; - let horizontal; - if (fill === 'start') { - target = scale.bottom; - } else if (fill === 'end') { - target = scale.top; - } else if (isObject(fill)) { - target = scale.getPixelForValue(fill.value); - } else if (scale.getBasePixel) { - target = scale.getBasePixel(); - } - if (isNumberFinite(target)) { - horizontal = scale.isHorizontal(); return { - x: horizontal ? target : null, - y: horizontal ? null : target + property, + start, + end }; - } - return null; } -class simpleArc { - constructor(opts) { - this.x = opts.x; - this.y = opts.y; - this.radius = opts.radius; - } - pathSegment(ctx, bounds, opts) { - const {x, y, radius} = this; - bounds = bounds || {start: 0, end: TAU}; - ctx.arc(x, y, radius, bounds.end, bounds.start, true); - return !opts.bounds; - } - interpolate(point) { - const {x, y, radius} = this; - const angle = point.angle; - return { - x: x + Math.cos(angle) * radius, - y: y + Math.sin(angle) * radius, - angle - }; - } -} -function computeCircularBoundary(source) { - const {scale, fill} = source; - const options = scale.options; - const length = scale.getLabels().length; - const target = []; - const start = options.reverse ? scale.max : scale.min; - const end = options.reverse ? scale.min : scale.max; - let i, center, value; - if (fill === 'start') { - value = start; - } else if (fill === 'end') { - value = end; - } else if (isObject(fill)) { - value = fill.value; - } else { - value = scale.getBaseValue(); - } - if (options.grid.circular) { - center = scale.getPointPositionForValue(0, start); - return new simpleArc({ - x: center.x, - y: center.y, - radius: scale.getDistanceFromCenterForValue(value) +function _pointsFromSegments(boundary, line) { + const { x =null , y =null } = boundary || {}; + const linePoints = line.points; + const points = []; + line.segments.forEach(({ start , end })=>{ + end = _findSegmentEnd(start, end, linePoints); + const first = linePoints[start]; + const last = linePoints[end]; + if (y !== null) { + points.push({ + x: first.x, + y + }); + points.push({ + x: last.x, + y + }); + } else if (x !== null) { + points.push({ + x, + y: first.y + }); + points.push({ + x, + y: last.y + }); + } }); - } - for (i = 0; i < length; ++i) { - target.push(scale.getPointPositionForValue(i, value)); - } - return target; + return points; } -function computeBoundary(source) { - const scale = source.scale || {}; - if (scale.getPointPositionForValue) { - return computeCircularBoundary(source); - } - return computeLinearBoundary(source); -} -function findSegmentEnd(start, end, points) { - for (;end > start; end--) { - const point = points[end]; - if (!isNaN(point.x) && !isNaN(point.y)) { - break; +function _findSegmentEnd(start, end, points) { + for(; end > start; end--){ + const point = points[end]; + if (!isNaN(point.x) && !isNaN(point.y)) { + break; + } } - } - return end; -} -function pointsFromSegments(boundary, line) { - const {x = null, y = null} = boundary || {}; - const linePoints = line.points; - const points = []; - line.segments.forEach(({start, end}) => { - end = findSegmentEnd(start, end, linePoints); - const first = linePoints[start]; - const last = linePoints[end]; - if (y !== null) { - points.push({x: first.x, y}); - points.push({x: last.x, y}); - } else if (x !== null) { - points.push({x, y: first.y}); - points.push({x, y: last.y}); - } - }); - return points; -} -function buildStackLine(source) { - const {scale, index, line} = source; - const points = []; - const segments = line.segments; - const sourcePoints = line.points; - const linesBelow = getLinesBelow(scale, index); - linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - for (let j = segment.start; j <= segment.end; j++) { - addPointsBelow(points, sourcePoints[j], linesBelow); - } - } - return new LineElement({points, options: {}}); -} -function getLinesBelow(scale, index) { - const below = []; - const metas = scale.getMatchingVisibleMetas('line'); - for (let i = 0; i < metas.length; i++) { - const meta = metas[i]; - if (meta.index === index) { - break; - } - if (!meta.hidden) { - below.unshift(meta.dataset); - } - } - return below; -} -function addPointsBelow(points, sourcePoint, linesBelow) { - const postponed = []; - for (let j = 0; j < linesBelow.length; j++) { - const line = linesBelow[j]; - const {first, last, point} = findPoint(line, sourcePoint, 'x'); - if (!point || (first && last)) { - continue; - } - if (first) { - postponed.unshift(point); - } else { - points.push(point); - if (!last) { - break; - } - } - } - points.push(...postponed); -} -function findPoint(line, sourcePoint, property) { - const point = line.interpolate(sourcePoint, property); - if (!point) { - return {}; - } - const pointValue = point[property]; - const segments = line.segments; - const linePoints = line.points; - let first = false; - let last = false; - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - const firstValue = linePoints[segment.start][property]; - const lastValue = linePoints[segment.end][property]; - if (_isBetween(pointValue, firstValue, lastValue)) { - first = pointValue === firstValue; - last = pointValue === lastValue; - break; - } - } - return {first, last, point}; -} -function getTarget(source) { - const {chart, fill, line} = source; - if (isNumberFinite(fill)) { - return getLineByIndex(chart, fill); - } - if (fill === 'stack') { - return buildStackLine(source); - } - if (fill === 'shape') { - return true; - } - const boundary = computeBoundary(source); - if (boundary instanceof simpleArc) { - return boundary; - } - return createBoundaryLine(boundary, line); -} -function createBoundaryLine(boundary, line) { - let points = []; - let _loop = false; - if (isArray(boundary)) { - _loop = true; - points = boundary; - } else { - points = pointsFromSegments(boundary, line); - } - return points.length ? new LineElement({ - points, - options: {tension: 0}, - _loop, - _fullLoop: _loop - }) : null; -} -function resolveTarget(sources, index, propagate) { - const source = sources[index]; - let fill = source.fill; - const visited = [index]; - let target; - if (!propagate) { - return fill; - } - while (fill !== false && visited.indexOf(fill) === -1) { - if (!isNumberFinite(fill)) { - return fill; - } - target = sources[fill]; - if (!target) { - return false; - } - if (target.visible) { - return fill; - } - visited.push(fill); - fill = target.fill; - } - return false; -} -function _clip(ctx, target, clipY) { - ctx.beginPath(); - target.path(ctx); - ctx.lineTo(target.last().x, clipY); - ctx.lineTo(target.first().x, clipY); - ctx.closePath(); - ctx.clip(); -} -function getBounds(property, first, last, loop) { - if (loop) { - return; - } - let start = first[property]; - let end = last[property]; - if (property === 'angle') { - start = _normalizeAngle(start); - end = _normalizeAngle(end); - } - return {property, start, end}; + return end; } function _getEdge(a, b, prop, fn) { - if (a && b) { - return fn(a[prop], b[prop]); - } - return a ? a[prop] : b ? b[prop] : 0; + if (a && b) { + return fn(a[prop], b[prop]); + } + return a ? a[prop] : b ? b[prop] : 0; } -function _segments(line, target, property) { - const segments = line.segments; - const points = line.points; - const tpoints = target.points; - const parts = []; - for (const segment of segments) { - let {start, end} = segment; - end = findSegmentEnd(start, end, points); - const bounds = getBounds(property, points[start], points[end], segment.loop); - if (!target.segments) { - parts.push({ - source: segment, - target: bounds, - start: points[start], - end: points[end] - }); - continue; - } - const targetSegments = _boundSegments(target, bounds); - for (const tgt of targetSegments) { - const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); - const fillSources = _boundSegment(segment, points, subBounds); - for (const fillSource of fillSources) { - parts.push({ - source: fillSource, - target: tgt, - start: { - [property]: _getEdge(bounds, subBounds, 'start', Math.max) - }, - end: { - [property]: _getEdge(bounds, subBounds, 'end', Math.min) - } - }); - } - } - } - return parts; -} -function clipBounds(ctx, scale, bounds) { - const {top, bottom} = scale.chart.chartArea; - const {property, start, end} = bounds || {}; - if (property === 'x') { - ctx.beginPath(); - ctx.rect(start, top, end - start, bottom - top); - ctx.clip(); - } -} -function interpolatedLineTo(ctx, target, point, property) { - const interpolatedPoint = target.interpolate(point, property); - if (interpolatedPoint) { - ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); - } -} -function _fill(ctx, cfg) { - const {line, target, property, color, scale} = cfg; - const segments = _segments(line, target, property); - for (const {source: src, target: tgt, start, end} of segments) { - const {style: {backgroundColor = color} = {}} = src; - const notShape = target !== true; - ctx.save(); - ctx.fillStyle = backgroundColor; - clipBounds(ctx, scale, notShape && getBounds(property, start, end)); - ctx.beginPath(); - const lineLoop = !!line.pathSegment(ctx, src); - let loop; - if (notShape) { - if (lineLoop) { - ctx.closePath(); - } else { - interpolatedLineTo(ctx, target, end, property); - } - const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); - loop = lineLoop && targetLoop; - if (!loop) { - interpolatedLineTo(ctx, target, start, property); - } - } - ctx.closePath(); - ctx.fill(loop ? 'evenodd' : 'nonzero'); - ctx.restore(); - } -} -function doFill(ctx, cfg) { - const {line, target, above, below, area, scale} = cfg; - const property = line._loop ? 'angle' : cfg.axis; - ctx.save(); - if (property === 'x' && below !== above) { - _clip(ctx, target, area.top); - _fill(ctx, {line, target, color: above, scale, property}); - ctx.restore(); - ctx.save(); - _clip(ctx, target, area.bottom); - } - _fill(ctx, {line, target, color: below, scale, property}); - ctx.restore(); -} -function drawfill(ctx, source, area) { - const target = getTarget(source); - const {line, scale, axis} = source; - const lineOpts = line.options; - const fillOption = lineOpts.fill; - const color = lineOpts.backgroundColor; - const {above = color, below = color} = fillOption || {}; - if (target && line.points.length) { - clipArea(ctx, area); - doFill(ctx, {line, target, above, below, area, scale, axis}); - unclipArea(ctx); - } -} -var plugin_filler = { - id: 'filler', - afterDatasetsUpdate(chart, _args, options) { - const count = (chart.data.datasets || []).length; - const sources = []; - let meta, i, line, source; - for (i = 0; i < count; ++i) { - meta = chart.getDatasetMeta(i); - line = meta.dataset; - source = null; - if (line && line.options && line instanceof LineElement) { - source = { - visible: chart.isDatasetVisible(i), - index: i, - fill: decodeFill(line, i, count), - chart, - axis: meta.controller.options.indexAxis, - scale: meta.vScale, - line, - }; - } - meta.$filler = source; - sources.push(source); - } - for (i = 0; i < count; ++i) { - source = sources[i]; - if (!source || source.fill === false) { - continue; - } - source.fill = resolveTarget(sources, i, options.propagate); - } - }, - beforeDraw(chart, _args, options) { - const draw = options.drawTime === 'beforeDraw'; - const metasets = chart.getSortedVisibleDatasetMetas(); - const area = chart.chartArea; - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (!source) { - continue; - } - source.line.updateControlPoints(area, source.axis); - if (draw) { - drawfill(chart.ctx, source, area); - } - } - }, - beforeDatasetsDraw(chart, _args, options) { - if (options.drawTime !== 'beforeDatasetsDraw') { - return; - } - const metasets = chart.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (source) { - drawfill(chart.ctx, source, chart.chartArea); - } - } - }, - beforeDatasetDraw(chart, args, options) { - const source = args.meta.$filler; - if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') { - return; - } - drawfill(chart.ctx, source, chart.chartArea); - }, - defaults: { - propagate: true, - drawTime: 'beforeDatasetDraw' - } -}; -const getBoxSize = (labelOpts, fontSize) => { - let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts; - if (labelOpts.usePointStyle) { - boxHeight = Math.min(boxHeight, fontSize); - boxWidth = Math.min(boxWidth, fontSize); - } - return { - boxWidth, - boxHeight, - itemHeight: Math.max(fontSize, boxHeight) - }; -}; -const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; -class Legend extends Element { - constructor(config) { - super(); - this._added = false; - this.legendHitBoxes = []; - this._hoveredItem = null; - this.doughnutMode = false; - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this.legendItems = undefined; - this.columnSizes = undefined; - this.lineWidths = undefined; - this.maxHeight = undefined; - this.maxWidth = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.height = undefined; - this.width = undefined; - this._margins = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight, margins) { - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins; - this.setDimensions(); - this.buildLabels(); - this.fit(); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = this._margins.left; - this.right = this.width; +function _createBoundaryLine(boundary, line) { + let points = []; + let _loop = false; + if (isArray(boundary)) { + _loop = true; + points = boundary; } else { - this.height = this.maxHeight; - this.top = this._margins.top; - this.bottom = this.height; + points = _pointsFromSegments(boundary, line); } - } - buildLabels() { - const labelOpts = this.options.labels || {}; - let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || []; - if (labelOpts.filter) { - legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data)); + return points.length ? new LineElement({ + points, + options: { + tension: 0 + }, + _loop, + _fullLoop: _loop + }) : null; +} +function _shouldApplyFill(source) { + return source && source.fill !== false; +} + +function _resolveTarget(sources, index, propagate) { + const source = sources[index]; + let fill = source.fill; + const visited = [ + index + ]; + let target; + if (!propagate) { + return fill; } - if (labelOpts.sort) { - legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data)); - } - if (this.options.reverse) { - legendItems.reverse(); - } - this.legendItems = legendItems; - } - fit() { - const {options, ctx} = this; - if (!options.display) { - this.width = this.height = 0; - return; - } - const labelOpts = options.labels; - const labelFont = toFont(labelOpts.font); - const fontSize = labelFont.size; - const titleHeight = this._computeTitleHeight(); - const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize); - let width, height; - ctx.font = labelFont.string; - if (this.isHorizontal()) { - width = this.maxWidth; - height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } else { - height = this.maxHeight; - width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } - this.width = Math.min(width, options.maxWidth || this.maxWidth); - this.height = Math.min(height, options.maxHeight || this.maxHeight); - } - _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxWidth, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const lineWidths = this.lineWidths = [0]; - const lineHeight = itemHeight + padding; - let totalHeight = titleHeight; - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - let row = -1; - let top = -lineHeight; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { - totalHeight += lineHeight; - lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; - top += lineHeight; - row++; - } - hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight}; - lineWidths[lineWidths.length - 1] += itemWidth + padding; - }); - return totalHeight; - } - _fitCols(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxHeight, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const columnSizes = this.columnSizes = []; - const heightLimit = maxHeight - titleHeight; - let totalWidth = padding; - let currentColWidth = 0; - let currentColHeight = 0; - let left = 0; - let col = 0; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { - totalWidth += currentColWidth + padding; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - left += currentColWidth + padding; - col++; - currentColWidth = currentColHeight = 0; - } - hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight}; - currentColWidth = Math.max(currentColWidth, itemWidth); - currentColHeight += itemHeight + padding; - }); - totalWidth += currentColWidth; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - return totalWidth; - } - adjustHitBoxes() { - if (!this.options.display) { - return; - } - const titleHeight = this._computeTitleHeight(); - const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this; - const rtlHelper = getRtlAdapter(rtl, this.left, this.width); - if (this.isHorizontal()) { - let row = 0; - let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); - for (const hitbox of hitboxes) { - if (row !== hitbox.row) { - row = hitbox.row; - left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + while(fill !== false && visited.indexOf(fill) === -1){ + if (!isNumberFinite(fill)) { + return fill; } - hitbox.top += this.top + titleHeight + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); - left += hitbox.width + padding; - } - } else { - let col = 0; - let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); - for (const hitbox of hitboxes) { - if (hitbox.col !== col) { - col = hitbox.col; - top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + target = sources[fill]; + if (!target) { + return false; } - hitbox.top = top; - hitbox.left += this.left + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); - top += hitbox.height + padding; - } + if (target.visible) { + return fill; + } + visited.push(fill); + fill = target.fill; } - } - isHorizontal() { - return this.options.position === 'top' || this.options.position === 'bottom'; - } - draw() { - if (this.options.display) { - const ctx = this.ctx; - clipArea(ctx, this); - this._draw(); - unclipArea(ctx); + return false; +} + function _decodeFill(line, index, count) { + const fill = parseFillOption(line); + if (isObject(fill)) { + return isNaN(fill.value) ? false : fill; } - } - _draw() { - const {options: opts, columnSizes, lineWidths, ctx} = this; - const {align, labels: labelOpts} = opts; - const defaultColor = defaults.color; - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const labelFont = toFont(labelOpts.font); - const {color: fontColor, padding} = labelOpts; - const fontSize = labelFont.size; - const halfFontSize = fontSize / 2; - let cursor; - this.drawTitle(); - ctx.textAlign = rtlHelper.textAlign('left'); - ctx.textBaseline = 'middle'; - ctx.lineWidth = 0.5; - ctx.font = labelFont.string; - const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize); - const drawLegendBox = function(x, y, legendItem) { - if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { - return; - } - ctx.save(); - const lineWidth = valueOrDefault(legendItem.lineWidth, 1); - ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); - ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); - ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); - ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); - ctx.lineWidth = lineWidth; - ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); - ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); - if (labelOpts.usePointStyle) { - const drawOptions = { - radius: boxWidth * Math.SQRT2 / 2, - pointStyle: legendItem.pointStyle, - rotation: legendItem.rotation, - borderWidth: lineWidth - }; - const centerX = rtlHelper.xPlus(x, boxWidth / 2); - const centerY = y + halfFontSize; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); - const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); - const borderRadius = toTRBLCorners(legendItem.borderRadius); - ctx.beginPath(); - if (Object.values(borderRadius).some(v => v !== 0)) { - addRoundedRectPath(ctx, { - x: xBoxLeft, - y: yBoxTop, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); + let target = parseFloat(fill); + if (isNumberFinite(target) && Math.floor(target) === target) { + return decodeTargetIndex(fill[0], index, target, count); + } + return [ + 'origin', + 'start', + 'end', + 'stack', + 'shape' + ].indexOf(fill) >= 0 && fill; +} +function decodeTargetIndex(firstCh, index, target, count) { + if (firstCh === '-' || firstCh === '+') { + target = index + target; + } + if (target === index || target < 0 || target >= count) { + return false; + } + return target; +} + function _getTargetPixel(fill, scale) { + let pixel = null; + if (fill === 'start') { + pixel = scale.bottom; + } else if (fill === 'end') { + pixel = scale.top; + } else if (isObject(fill)) { + pixel = scale.getPixelForValue(fill.value); + } else if (scale.getBasePixel) { + pixel = scale.getBasePixel(); + } + return pixel; +} + function _getTargetValue(fill, scale, startValue) { + let value; + if (fill === 'start') { + value = startValue; + } else if (fill === 'end') { + value = scale.options.reverse ? scale.min : scale.max; + } else if (isObject(fill)) { + value = fill.value; + } else { + value = scale.getBaseValue(); + } + return value; +} + function parseFillOption(line) { + const options = line.options; + const fillOption = options.fill; + let fill = valueOrDefault(fillOption && fillOption.target, fillOption); + if (fill === undefined) { + fill = !!options.backgroundColor; + } + if (fill === false || fill === null) { + return false; + } + if (fill === true) { + return 'origin'; + } + return fill; +} + +function _buildStackLine(source) { + const { scale , index , line } = source; + const points = []; + const segments = line.segments; + const sourcePoints = line.points; + const linesBelow = getLinesBelow(scale, index); + linesBelow.push(_createBoundaryLine({ + x: null, + y: scale.bottom + }, line)); + for(let i = 0; i < segments.length; i++){ + const segment = segments[i]; + for(let j = segment.start; j <= segment.end; j++){ + addPointsBelow(points, sourcePoints[j], linesBelow); + } + } + return new LineElement({ + points, + options: {} + }); +} + function getLinesBelow(scale, index) { + const below = []; + const metas = scale.getMatchingVisibleMetas('line'); + for(let i = 0; i < metas.length; i++){ + const meta = metas[i]; + if (meta.index === index) { + break; + } + if (!meta.hidden) { + below.unshift(meta.dataset); + } + } + return below; +} + function addPointsBelow(points, sourcePoint, linesBelow) { + const postponed = []; + for(let j = 0; j < linesBelow.length; j++){ + const line = linesBelow[j]; + const { first , last , point } = findPoint(line, sourcePoint, 'x'); + if (!point || first && last) { + continue; + } + if (first) { + postponed.unshift(point); } else { - ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); + points.push(point); + if (!last) { + break; + } } - ctx.fill(); - if (lineWidth !== 0) { - ctx.stroke(); + } + points.push(...postponed); +} + function findPoint(line, sourcePoint, property) { + const point = line.interpolate(sourcePoint, property); + if (!point) { + return {}; + } + const pointValue = point[property]; + const segments = line.segments; + const linePoints = line.points; + let first = false; + let last = false; + for(let i = 0; i < segments.length; i++){ + const segment = segments[i]; + const firstValue = linePoints[segment.start][property]; + const lastValue = linePoints[segment.end][property]; + if (_isBetween(pointValue, firstValue, lastValue)) { + first = pointValue === firstValue; + last = pointValue === lastValue; + break; } - } - ctx.restore(); + } + return { + first, + last, + point }; - const fillText = function(x, y, legendItem) { - renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, { - strikethrough: legendItem.hidden, - textAlign: rtlHelper.textAlign(legendItem.textAlign) - }); - }; - const isHorizontal = this.isHorizontal(); - const titleHeight = this._computeTitleHeight(); - if (isHorizontal) { - cursor = { - x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), - y: this.top + padding + titleHeight, - line: 0 - }; - } else { - cursor = { - x: this.left + padding, - y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), - line: 0 - }; +} + +class simpleArc { + constructor(opts){ + this.x = opts.x; + this.y = opts.y; + this.radius = opts.radius; } - overrideTextDirection(this.ctx, opts.textDirection); - const lineHeight = itemHeight + padding; - this.legendItems.forEach((legendItem, i) => { - ctx.strokeStyle = legendItem.fontColor || fontColor; - ctx.fillStyle = legendItem.fontColor || fontColor; - const textWidth = ctx.measureText(legendItem.text).width; - const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); - const width = boxWidth + halfFontSize + textWidth; - let x = cursor.x; - let y = cursor.y; - rtlHelper.setWidth(this.width); - if (isHorizontal) { - if (i > 0 && x + width + padding > this.right) { - y = cursor.y += lineHeight; - cursor.line++; - x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); - } - } else if (i > 0 && y + lineHeight > this.bottom) { - x = cursor.x = x + columnSizes[cursor.line].width + padding; - cursor.line++; - y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); - } - const realX = rtlHelper.x(x); - drawLegendBox(realX, y, legendItem); - x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); - fillText(rtlHelper.x(x), y, legendItem); - if (isHorizontal) { - cursor.x += width + padding; - } else { - cursor.y += lineHeight; - } - }); - restoreTextDirection(this.ctx, opts.textDirection); - } - drawTitle() { - const opts = this.options; - const titleOpts = opts.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - if (!titleOpts.display) { - return; + pathSegment(ctx, bounds, opts) { + const { x , y , radius } = this; + bounds = bounds || { + start: 0, + end: TAU + }; + ctx.arc(x, y, radius, bounds.end, bounds.start, true); + return !opts.bounds; } - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const ctx = this.ctx; - const position = titleOpts.position; - const halfFontSize = titleFont.size / 2; - const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; - let y; - let left = this.left; - let maxWidth = this.width; - if (this.isHorizontal()) { - maxWidth = Math.max(...this.lineWidths); - y = this.top + topPaddingPlusHalfFontSize; - left = _alignStartEnd(opts.align, left, this.right - maxWidth); - } else { - const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0); - y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); + interpolate(point) { + const { x , y , radius } = this; + const angle = point.angle; + return { + x: x + Math.cos(angle) * radius, + y: y + Math.sin(angle) * radius, + angle + }; } - const x = _alignStartEnd(position, left, left + maxWidth); - ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); - ctx.textBaseline = 'middle'; - ctx.strokeStyle = titleOpts.color; - ctx.fillStyle = titleOpts.color; - ctx.font = titleFont.string; - renderText(ctx, titleOpts.text, x, y, titleFont); - } - _computeTitleHeight() { - const titleOpts = this.options.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; - } - _getLegendItemAt(x, y) { - let i, hitBox, lh; - if (_isBetween(x, this.left, this.right) - && _isBetween(y, this.top, this.bottom)) { - lh = this.legendHitBoxes; - for (i = 0; i < lh.length; ++i) { - hitBox = lh[i]; - if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) - && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { - return this.legendItems[i]; - } - } +} + +function _getTarget(source) { + const { chart , fill , line } = source; + if (isNumberFinite(fill)) { + return getLineByIndex(chart, fill); + } + if (fill === 'stack') { + return _buildStackLine(source); + } + if (fill === 'shape') { + return true; + } + const boundary = computeBoundary(source); + if (boundary instanceof simpleArc) { + return boundary; + } + return _createBoundaryLine(boundary, line); +} + function getLineByIndex(chart, index) { + const meta = chart.getDatasetMeta(index); + const visible = meta && chart.isDatasetVisible(index); + return visible ? meta.dataset : null; +} +function computeBoundary(source) { + const scale = source.scale || {}; + if (scale.getPointPositionForValue) { + return computeCircularBoundary(source); + } + return computeLinearBoundary(source); +} +function computeLinearBoundary(source) { + const { scale ={} , fill } = source; + const pixel = _getTargetPixel(fill, scale); + if (isNumberFinite(pixel)) { + const horizontal = scale.isHorizontal(); + return { + x: horizontal ? pixel : null, + y: horizontal ? null : pixel + }; } return null; - } - handleEvent(e) { - const opts = this.options; - if (!isListened(e.type, opts)) { - return; +} +function computeCircularBoundary(source) { + const { scale , fill } = source; + const options = scale.options; + const length = scale.getLabels().length; + const start = options.reverse ? scale.max : scale.min; + const value = _getTargetValue(fill, scale, start); + const target = []; + if (options.grid.circular) { + const center = scale.getPointPositionForValue(0, start); + return new simpleArc({ + x: center.x, + y: center.y, + radius: scale.getDistanceFromCenterForValue(value) + }); } - const hoveredItem = this._getLegendItemAt(e.x, e.y); - if (e.type === 'mousemove') { - const previous = this._hoveredItem; - const sameItem = itemsEqual(previous, hoveredItem); - if (previous && !sameItem) { - callback(opts.onLeave, [e, previous, this], this); - } - this._hoveredItem = hoveredItem; - if (hoveredItem && !sameItem) { - callback(opts.onHover, [e, hoveredItem, this], this); - } - } else if (hoveredItem) { - callback(opts.onClick, [e, hoveredItem, this], this); + for(let i = 0; i < length; ++i){ + target.push(scale.getPointPositionForValue(i, value)); } - } + return target; +} + +function _drawfill(ctx, source, area) { + const target = _getTarget(source); + const { line , scale , axis } = source; + const lineOpts = line.options; + const fillOption = lineOpts.fill; + const color = lineOpts.backgroundColor; + const { above =color , below =color } = fillOption || {}; + if (target && line.points.length) { + clipArea(ctx, area); + doFill(ctx, { + line, + target, + above, + below, + area, + scale, + axis + }); + unclipArea(ctx); + } +} +function doFill(ctx, cfg) { + const { line , target , above , below , area , scale } = cfg; + const property = line._loop ? 'angle' : cfg.axis; + ctx.save(); + if (property === 'x' && below !== above) { + clipVertical(ctx, target, area.top); + fill(ctx, { + line, + target, + color: above, + scale, + property + }); + ctx.restore(); + ctx.save(); + clipVertical(ctx, target, area.bottom); + } + fill(ctx, { + line, + target, + color: below, + scale, + property + }); + ctx.restore(); +} +function clipVertical(ctx, target, clipY) { + const { segments , points } = target; + let first = true; + let lineLoop = false; + ctx.beginPath(); + for (const segment of segments){ + const { start , end } = segment; + const firstPoint = points[start]; + const lastPoint = points[_findSegmentEnd(start, end, points)]; + if (first) { + ctx.moveTo(firstPoint.x, firstPoint.y); + first = false; + } else { + ctx.lineTo(firstPoint.x, clipY); + ctx.lineTo(firstPoint.x, firstPoint.y); + } + lineLoop = !!target.pathSegment(ctx, segment, { + move: lineLoop + }); + if (lineLoop) { + ctx.closePath(); + } else { + ctx.lineTo(lastPoint.x, clipY); + } + } + ctx.lineTo(target.first().x, clipY); + ctx.closePath(); + ctx.clip(); +} +function fill(ctx, cfg) { + const { line , target , property , color , scale } = cfg; + const segments = _segments(line, target, property); + for (const { source: src , target: tgt , start , end } of segments){ + const { style: { backgroundColor =color } = {} } = src; + const notShape = target !== true; + ctx.save(); + ctx.fillStyle = backgroundColor; + clipBounds(ctx, scale, notShape && _getBounds(property, start, end)); + ctx.beginPath(); + const lineLoop = !!line.pathSegment(ctx, src); + let loop; + if (notShape) { + if (lineLoop) { + ctx.closePath(); + } else { + interpolatedLineTo(ctx, target, end, property); + } + const targetLoop = !!target.pathSegment(ctx, tgt, { + move: lineLoop, + reverse: true + }); + loop = lineLoop && targetLoop; + if (!loop) { + interpolatedLineTo(ctx, target, start, property); + } + } + ctx.closePath(); + ctx.fill(loop ? 'evenodd' : 'nonzero'); + ctx.restore(); + } +} +function clipBounds(ctx, scale, bounds) { + const { top , bottom } = scale.chart.chartArea; + const { property , start , end } = bounds || {}; + if (property === 'x') { + ctx.beginPath(); + ctx.rect(start, top, end - start, bottom - top); + ctx.clip(); + } +} +function interpolatedLineTo(ctx, target, point, property) { + const interpolatedPoint = target.interpolate(point, property); + if (interpolatedPoint) { + ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); + } +} + +var index = { + id: 'filler', + afterDatasetsUpdate (chart, _args, options) { + const count = (chart.data.datasets || []).length; + const sources = []; + let meta, i, line, source; + for(i = 0; i < count; ++i){ + meta = chart.getDatasetMeta(i); + line = meta.dataset; + source = null; + if (line && line.options && line instanceof LineElement) { + source = { + visible: chart.isDatasetVisible(i), + index: i, + fill: _decodeFill(line, i, count), + chart, + axis: meta.controller.options.indexAxis, + scale: meta.vScale, + line + }; + } + meta.$filler = source; + sources.push(source); + } + for(i = 0; i < count; ++i){ + source = sources[i]; + if (!source || source.fill === false) { + continue; + } + source.fill = _resolveTarget(sources, i, options.propagate); + } + }, + beforeDraw (chart, _args, options) { + const draw = options.drawTime === 'beforeDraw'; + const metasets = chart.getSortedVisibleDatasetMetas(); + const area = chart.chartArea; + for(let i = metasets.length - 1; i >= 0; --i){ + const source = metasets[i].$filler; + if (!source) { + continue; + } + source.line.updateControlPoints(area, source.axis); + if (draw && source.fill) { + _drawfill(chart.ctx, source, area); + } + } + }, + beforeDatasetsDraw (chart, _args, options) { + if (options.drawTime !== 'beforeDatasetsDraw') { + return; + } + const metasets = chart.getSortedVisibleDatasetMetas(); + for(let i = metasets.length - 1; i >= 0; --i){ + const source = metasets[i].$filler; + if (_shouldApplyFill(source)) { + _drawfill(chart.ctx, source, chart.chartArea); + } + } + }, + beforeDatasetDraw (chart, args, options) { + const source = args.meta.$filler; + if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') { + return; + } + _drawfill(chart.ctx, source, chart.chartArea); + }, + defaults: { + propagate: true, + drawTime: 'beforeDatasetDraw' + } +}; + +const getBoxSize = (labelOpts, fontSize)=>{ + let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts; + if (labelOpts.usePointStyle) { + boxHeight = Math.min(boxHeight, fontSize); + boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize); + } + return { + boxWidth, + boxHeight, + itemHeight: Math.max(fontSize, boxHeight) + }; +}; +const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; +class Legend extends Element { + constructor(config){ + super(); + this._added = false; + this.legendHitBoxes = []; + this._hoveredItem = null; + this.doughnutMode = false; + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this.legendItems = undefined; + this.columnSizes = undefined; + this.lineWidths = undefined; + this.maxHeight = undefined; + this.maxWidth = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.height = undefined; + this.width = undefined; + this._margins = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; + } + update(maxWidth, maxHeight, margins) { + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins; + this.setDimensions(); + this.buildLabels(); + this.fit(); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = this._margins.left; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = this._margins.top; + this.bottom = this.height; + } + } + buildLabels() { + const labelOpts = this.options.labels || {}; + let legendItems = callback(labelOpts.generateLabels, [ + this.chart + ], this) || []; + if (labelOpts.filter) { + legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data)); + } + if (labelOpts.sort) { + legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data)); + } + if (this.options.reverse) { + legendItems.reverse(); + } + this.legendItems = legendItems; + } + fit() { + const { options , ctx } = this; + if (!options.display) { + this.width = this.height = 0; + return; + } + const labelOpts = options.labels; + const labelFont = toFont(labelOpts.font); + const fontSize = labelFont.size; + const titleHeight = this._computeTitleHeight(); + const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize); + let width, height; + ctx.font = labelFont.string; + if (this.isHorizontal()) { + width = this.maxWidth; + height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; + } else { + height = this.maxHeight; + width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10; + } + this.width = Math.min(width, options.maxWidth || this.maxWidth); + this.height = Math.min(height, options.maxHeight || this.maxHeight); + } + _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { + const { ctx , maxWidth , options: { labels: { padding } } } = this; + const hitboxes = this.legendHitBoxes = []; + const lineWidths = this.lineWidths = [ + 0 + ]; + const lineHeight = itemHeight + padding; + let totalHeight = titleHeight; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + let row = -1; + let top = -lineHeight; + this.legendItems.forEach((legendItem, i)=>{ + const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width; + if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { + totalHeight += lineHeight; + lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; + top += lineHeight; + row++; + } + hitboxes[i] = { + left: 0, + top, + row, + width: itemWidth, + height: itemHeight + }; + lineWidths[lineWidths.length - 1] += itemWidth + padding; + }); + return totalHeight; + } + _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) { + const { ctx , maxHeight , options: { labels: { padding } } } = this; + const hitboxes = this.legendHitBoxes = []; + const columnSizes = this.columnSizes = []; + const heightLimit = maxHeight - titleHeight; + let totalWidth = padding; + let currentColWidth = 0; + let currentColHeight = 0; + let left = 0; + let col = 0; + this.legendItems.forEach((legendItem, i)=>{ + const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight); + if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { + totalWidth += currentColWidth + padding; + columnSizes.push({ + width: currentColWidth, + height: currentColHeight + }); + left += currentColWidth + padding; + col++; + currentColWidth = currentColHeight = 0; + } + hitboxes[i] = { + left, + top: currentColHeight, + col, + width: itemWidth, + height: itemHeight + }; + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += itemHeight + padding; + }); + totalWidth += currentColWidth; + columnSizes.push({ + width: currentColWidth, + height: currentColHeight + }); + return totalWidth; + } + adjustHitBoxes() { + if (!this.options.display) { + return; + } + const titleHeight = this._computeTitleHeight(); + const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this; + const rtlHelper = getRtlAdapter(rtl, this.left, this.width); + if (this.isHorizontal()) { + let row = 0; + let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + for (const hitbox of hitboxes){ + if (row !== hitbox.row) { + row = hitbox.row; + left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + } + hitbox.top += this.top + titleHeight + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); + left += hitbox.width + padding; + } + } else { + let col = 0; + let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + for (const hitbox of hitboxes){ + if (hitbox.col !== col) { + col = hitbox.col; + top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + } + hitbox.top = top; + hitbox.left += this.left + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); + top += hitbox.height + padding; + } + } + } + isHorizontal() { + return this.options.position === 'top' || this.options.position === 'bottom'; + } + draw() { + if (this.options.display) { + const ctx = this.ctx; + clipArea(ctx, this); + this._draw(); + unclipArea(ctx); + } + } + _draw() { + const { options: opts , columnSizes , lineWidths , ctx } = this; + const { align , labels: labelOpts } = opts; + const defaultColor = defaults.color; + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const labelFont = toFont(labelOpts.font); + const { padding } = labelOpts; + const fontSize = labelFont.size; + const halfFontSize = fontSize / 2; + let cursor; + this.drawTitle(); + ctx.textAlign = rtlHelper.textAlign('left'); + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.font = labelFont.string; + const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize); + const drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { + return; + } + ctx.save(); + const lineWidth = valueOrDefault(legendItem.lineWidth, 1); + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); + ctx.lineWidth = lineWidth; + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); + ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); + if (labelOpts.usePointStyle) { + const drawOptions = { + radius: boxHeight * Math.SQRT2 / 2, + pointStyle: legendItem.pointStyle, + rotation: legendItem.rotation, + borderWidth: lineWidth + }; + const centerX = rtlHelper.xPlus(x, boxWidth / 2); + const centerY = y + halfFontSize; + drawPointLegend(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth); + } else { + const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); + const borderRadius = toTRBLCorners(legendItem.borderRadius); + ctx.beginPath(); + if (Object.values(borderRadius).some((v)=>v !== 0)) { + addRoundedRectPath(ctx, { + x: xBoxLeft, + y: yBoxTop, + w: boxWidth, + h: boxHeight, + radius: borderRadius + }); + } else { + ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); + } + ctx.fill(); + if (lineWidth !== 0) { + ctx.stroke(); + } + } + ctx.restore(); + }; + const fillText = function(x, y, legendItem) { + renderText(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, { + strikethrough: legendItem.hidden, + textAlign: rtlHelper.textAlign(legendItem.textAlign) + }); + }; + const isHorizontal = this.isHorizontal(); + const titleHeight = this._computeTitleHeight(); + if (isHorizontal) { + cursor = { + x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), + y: this.top + padding + titleHeight, + line: 0 + }; + } else { + cursor = { + x: this.left + padding, + y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), + line: 0 + }; + } + overrideTextDirection(this.ctx, opts.textDirection); + const lineHeight = itemHeight + padding; + this.legendItems.forEach((legendItem, i)=>{ + ctx.strokeStyle = legendItem.fontColor; + ctx.fillStyle = legendItem.fontColor; + const textWidth = ctx.measureText(legendItem.text).width; + const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); + const width = boxWidth + halfFontSize + textWidth; + let x = cursor.x; + let y = cursor.y; + rtlHelper.setWidth(this.width); + if (isHorizontal) { + if (i > 0 && x + width + padding > this.right) { + y = cursor.y += lineHeight; + cursor.line++; + x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); + } + } else if (i > 0 && y + lineHeight > this.bottom) { + x = cursor.x = x + columnSizes[cursor.line].width + padding; + cursor.line++; + y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); + } + const realX = rtlHelper.x(x); + drawLegendBox(realX, y, legendItem); + x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); + fillText(rtlHelper.x(x), y, legendItem); + if (isHorizontal) { + cursor.x += width + padding; + } else if (typeof legendItem.text !== 'string') { + const fontLineHeight = labelFont.lineHeight; + cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight); + } else { + cursor.y += lineHeight; + } + }); + restoreTextDirection(this.ctx, opts.textDirection); + } + drawTitle() { + const opts = this.options; + const titleOpts = opts.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + if (!titleOpts.display) { + return; + } + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const ctx = this.ctx; + const position = titleOpts.position; + const halfFontSize = titleFont.size / 2; + const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; + let y; + let left = this.left; + let maxWidth = this.width; + if (this.isHorizontal()) { + maxWidth = Math.max(...this.lineWidths); + y = this.top + topPaddingPlusHalfFontSize; + left = _alignStartEnd(opts.align, left, this.right - maxWidth); + } else { + const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0); + y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); + } + const x = _alignStartEnd(position, left, left + maxWidth); + ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); + ctx.textBaseline = 'middle'; + ctx.strokeStyle = titleOpts.color; + ctx.fillStyle = titleOpts.color; + ctx.font = titleFont.string; + renderText(ctx, titleOpts.text, x, y, titleFont); + } + _computeTitleHeight() { + const titleOpts = this.options.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; + } + _getLegendItemAt(x, y) { + let i, hitBox, lh; + if (_isBetween(x, this.left, this.right) && _isBetween(y, this.top, this.bottom)) { + lh = this.legendHitBoxes; + for(i = 0; i < lh.length; ++i){ + hitBox = lh[i]; + if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { + return this.legendItems[i]; + } + } + } + return null; + } + handleEvent(e) { + const opts = this.options; + if (!isListened(e.type, opts)) { + return; + } + const hoveredItem = this._getLegendItemAt(e.x, e.y); + if (e.type === 'mousemove' || e.type === 'mouseout') { + const previous = this._hoveredItem; + const sameItem = itemsEqual(previous, hoveredItem); + if (previous && !sameItem) { + callback(opts.onLeave, [ + e, + previous, + this + ], this); + } + this._hoveredItem = hoveredItem; + if (hoveredItem && !sameItem) { + callback(opts.onHover, [ + e, + hoveredItem, + this + ], this); + } + } else if (hoveredItem) { + callback(opts.onClick, [ + e, + hoveredItem, + this + ], this); + } + } +} +function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) { + const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx); + const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight); + return { + itemWidth, + itemHeight + }; +} +function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) { + let legendItemText = legendItem.text; + if (legendItemText && typeof legendItemText !== 'string') { + legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b); + } + return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width; +} +function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) { + let itemHeight = _itemHeight; + if (typeof legendItem.text !== 'string') { + itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight); + } + return itemHeight; +} +function calculateLegendItemHeight(legendItem, fontLineHeight) { + const labelHeight = legendItem.text ? legendItem.text.length + 0.5 : 0; + return fontLineHeight * labelHeight; } function isListened(type, opts) { - if (type === 'mousemove' && (opts.onHover || opts.onLeave)) { - return true; - } - if (opts.onClick && (type === 'click' || type === 'mouseup')) { - return true; - } - return false; + if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) { + return true; + } + if (opts.onClick && (type === 'click' || type === 'mouseup')) { + return true; + } + return false; } var plugin_legend = { - id: 'legend', - _element: Legend, - start(chart, _args, options) { - const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart}); - layouts.configure(chart, legend, options); - layouts.addBox(chart, legend); - }, - stop(chart) { - layouts.removeBox(chart, chart.legend); - delete chart.legend; - }, - beforeUpdate(chart, _args, options) { - const legend = chart.legend; - layouts.configure(chart, legend, options); - legend.options = options; - }, - afterUpdate(chart) { - const legend = chart.legend; - legend.buildLabels(); - legend.adjustHitBoxes(); - }, - afterEvent(chart, args) { - if (!args.replay) { - chart.legend.handleEvent(args.event); - } - }, - defaults: { - display: true, - position: 'top', - align: 'center', - fullSize: true, - reverse: false, - weight: 1000, - onClick(e, legendItem, legend) { - const index = legendItem.datasetIndex; - const ci = legend.chart; - if (ci.isDatasetVisible(index)) { - ci.hide(index); - legendItem.hidden = true; - } else { - ci.show(index); - legendItem.hidden = false; - } + id: 'legend', + _element: Legend, + start (chart, _args, options) { + const legend = chart.legend = new Legend({ + ctx: chart.ctx, + options, + chart + }); + layouts.configure(chart, legend, options); + layouts.addBox(chart, legend); }, - onHover: null, - onLeave: null, - labels: { - color: (ctx) => ctx.chart.options.color, - boxWidth: 40, - padding: 10, - generateLabels(chart) { - const datasets = chart.data.datasets; - const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options; - return chart._getSortedDatasetMetas().map((meta) => { - const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); - const borderWidth = toPadding(style.borderWidth); - return { - text: datasets[meta.index].label, - fillStyle: style.backgroundColor, - fontColor: color, - hidden: !meta.visible, - lineCap: style.borderCapStyle, - lineDash: style.borderDash, - lineDashOffset: style.borderDashOffset, - lineJoin: style.borderJoinStyle, - lineWidth: (borderWidth.width + borderWidth.height) / 4, - strokeStyle: style.borderColor, - pointStyle: pointStyle || style.pointStyle, - rotation: style.rotation, - textAlign: textAlign || style.textAlign, - borderRadius: 0, - datasetIndex: meta.index - }; - }, this); - } + stop (chart) { + layouts.removeBox(chart, chart.legend); + delete chart.legend; }, - title: { - color: (ctx) => ctx.chart.options.color, - display: false, - position: 'center', - text: '', + beforeUpdate (chart, _args, options) { + const legend = chart.legend; + layouts.configure(chart, legend, options); + legend.options = options; + }, + afterUpdate (chart) { + const legend = chart.legend; + legend.buildLabels(); + legend.adjustHitBoxes(); + }, + afterEvent (chart, args) { + if (!args.replay) { + chart.legend.handleEvent(args.event); + } + }, + defaults: { + display: true, + position: 'top', + align: 'center', + fullSize: true, + reverse: false, + weight: 1000, + onClick (e, legendItem, legend) { + const index = legendItem.datasetIndex; + const ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } + }, + onHover: null, + onLeave: null, + labels: { + color: (ctx)=>ctx.chart.options.color, + boxWidth: 40, + padding: 10, + generateLabels (chart) { + const datasets = chart.data.datasets; + const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options; + return chart._getSortedDatasetMetas().map((meta)=>{ + const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); + const borderWidth = toPadding(style.borderWidth); + return { + text: datasets[meta.index].label, + fillStyle: style.backgroundColor, + fontColor: color, + hidden: !meta.visible, + lineCap: style.borderCapStyle, + lineDash: style.borderDash, + lineDashOffset: style.borderDashOffset, + lineJoin: style.borderJoinStyle, + lineWidth: (borderWidth.width + borderWidth.height) / 4, + strokeStyle: style.borderColor, + pointStyle: pointStyle || style.pointStyle, + rotation: style.rotation, + textAlign: textAlign || style.textAlign, + borderRadius: useBorderRadius && (borderRadius || style.borderRadius), + datasetIndex: meta.index + }; + }, this); + } + }, + title: { + color: (ctx)=>ctx.chart.options.color, + display: false, + position: 'center', + text: '' + } + }, + descriptors: { + _scriptable: (name)=>!name.startsWith('on'), + labels: { + _scriptable: (name)=>![ + 'generateLabels', + 'filter', + 'sort' + ].includes(name) + } } - }, - descriptors: { - _scriptable: (name) => !name.startsWith('on'), - labels: { - _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name), - } - }, }; class Title extends Element { - constructor(config) { - super(); - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this._padding = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight) { - const opts = this.options; - this.left = 0; - this.top = 0; - if (!opts.display) { - this.width = this.height = this.right = this.bottom = 0; - return; + constructor(config){ + super(); + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this._padding = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; } - this.width = this.right = maxWidth; - this.height = this.bottom = maxHeight; - const lineCount = isArray(opts.text) ? opts.text.length : 1; - this._padding = toPadding(opts.padding); - const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; - if (this.isHorizontal()) { - this.height = textSize; - } else { - this.width = textSize; + update(maxWidth, maxHeight) { + const opts = this.options; + this.left = 0; + this.top = 0; + if (!opts.display) { + this.width = this.height = this.right = this.bottom = 0; + return; + } + this.width = this.right = maxWidth; + this.height = this.bottom = maxHeight; + const lineCount = isArray(opts.text) ? opts.text.length : 1; + this._padding = toPadding(opts.padding); + const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; + if (this.isHorizontal()) { + this.height = textSize; + } else { + this.width = textSize; + } } - } - isHorizontal() { - const pos = this.options.position; - return pos === 'top' || pos === 'bottom'; - } - _drawArgs(offset) { - const {top, left, bottom, right, options} = this; - const align = options.align; - let rotation = 0; - let maxWidth, titleX, titleY; - if (this.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - titleY = top + offset; - maxWidth = right - left; - } else { - if (options.position === 'left') { - titleX = left + offset; - titleY = _alignStartEnd(align, bottom, top); - rotation = PI * -0.5; - } else { - titleX = right - offset; - titleY = _alignStartEnd(align, top, bottom); - rotation = PI * 0.5; - } - maxWidth = bottom - top; + isHorizontal() { + const pos = this.options.position; + return pos === 'top' || pos === 'bottom'; } - return {titleX, titleY, maxWidth, rotation}; - } - draw() { - const ctx = this.ctx; - const opts = this.options; - if (!opts.display) { - return; + _drawArgs(offset) { + const { top , left , bottom , right , options } = this; + const align = options.align; + let rotation = 0; + let maxWidth, titleX, titleY; + if (this.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + titleY = top + offset; + maxWidth = right - left; + } else { + if (options.position === 'left') { + titleX = left + offset; + titleY = _alignStartEnd(align, bottom, top); + rotation = PI * -0.5; + } else { + titleX = right - offset; + titleY = _alignStartEnd(align, top, bottom); + rotation = PI * 0.5; + } + maxWidth = bottom - top; + } + return { + titleX, + titleY, + maxWidth, + rotation + }; + } + draw() { + const ctx = this.ctx; + const opts = this.options; + if (!opts.display) { + return; + } + const fontOpts = toFont(opts.font); + const lineHeight = fontOpts.lineHeight; + const offset = lineHeight / 2 + this._padding.top; + const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset); + renderText(ctx, opts.text, 0, 0, fontOpts, { + color: opts.color, + maxWidth, + rotation, + textAlign: _toLeftRightCenter(opts.align), + textBaseline: 'middle', + translation: [ + titleX, + titleY + ] + }); } - const fontOpts = toFont(opts.font); - const lineHeight = fontOpts.lineHeight; - const offset = lineHeight / 2 + this._padding.top; - const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset); - renderText(ctx, opts.text, 0, 0, fontOpts, { - color: opts.color, - maxWidth, - rotation, - textAlign: _toLeftRightCenter(opts.align), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } } function createTitle(chart, titleOpts) { - const title = new Title({ - ctx: chart.ctx, - options: titleOpts, - chart - }); - layouts.configure(chart, title, titleOpts); - layouts.addBox(chart, title); - chart.titleBlock = title; + const title = new Title({ + ctx: chart.ctx, + options: titleOpts, + chart + }); + layouts.configure(chart, title, titleOpts); + layouts.addBox(chart, title); + chart.titleBlock = title; } var plugin_title = { - id: 'title', - _element: Title, - start(chart, _args, options) { - createTitle(chart, options); - }, - stop(chart) { - const titleBlock = chart.titleBlock; - layouts.removeBox(chart, titleBlock); - delete chart.titleBlock; - }, - beforeUpdate(chart, _args, options) { - const title = chart.titleBlock; - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'bold', + id: 'title', + _element: Title, + start (chart, _args, options) { + createTitle(chart, options); }, - fullSize: true, - padding: 10, - position: 'top', - text: '', - weight: 2000 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, + stop (chart) { + const titleBlock = chart.titleBlock; + layouts.removeBox(chart, titleBlock); + delete chart.titleBlock; + }, + beforeUpdate (chart, _args, options) { + const title = chart.titleBlock; + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'bold' + }, + fullSize: true, + padding: 10, + position: 'top', + text: '', + weight: 2000 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false + } }; const map = new WeakMap(); var plugin_subtitle = { - id: 'subtitle', - start(chart, _args, options) { - const title = new Title({ - ctx: chart.ctx, - options, - chart - }); - layouts.configure(chart, title, options); - layouts.addBox(chart, title); - map.set(chart, title); - }, - stop(chart) { - layouts.removeBox(chart, map.get(chart)); - map.delete(chart); - }, - beforeUpdate(chart, _args, options) { - const title = map.get(chart); - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'normal', + id: 'subtitle', + start (chart, _args, options) { + const title = new Title({ + ctx: chart.ctx, + options, + chart + }); + layouts.configure(chart, title, options); + layouts.addBox(chart, title); + map.set(chart, title); }, - fullSize: true, - padding: 0, - position: 'top', - text: '', - weight: 1500 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, + stop (chart) { + layouts.removeBox(chart, map.get(chart)); + map.delete(chart); + }, + beforeUpdate (chart, _args, options) { + const title = map.get(chart); + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'normal' + }, + fullSize: true, + padding: 0, + position: 'top', + text: '', + weight: 1500 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false + } }; const positioners = { - average(items) { - if (!items.length) { - return false; - } - let i, len; - let x = 0; - let y = 0; - let count = 0; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const pos = el.tooltipPosition(); - x += pos.x; - y += pos.y; - ++count; - } - } - return { - x: x / count, - y: y / count - }; - }, - nearest(items, eventPosition) { - if (!items.length) { - return false; - } - let x = eventPosition.x; - let y = eventPosition.y; - let minDistance = Number.POSITIVE_INFINITY; - let i, len, nearestElement; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const center = el.getCenterPoint(); - const d = distanceBetweenPoints(eventPosition, center); - if (d < minDistance) { - minDistance = d; - nearestElement = el; + average (items) { + if (!items.length) { + return false; } - } + let i, len; + let x = 0; + let y = 0; + let count = 0; + for(i = 0, len = items.length; i < len; ++i){ + const el = items[i].element; + if (el && el.hasValue()) { + const pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest (items, eventPosition) { + if (!items.length) { + return false; + } + let x = eventPosition.x; + let y = eventPosition.y; + let minDistance = Number.POSITIVE_INFINITY; + let i, len, nearestElement; + for(i = 0, len = items.length; i < len; ++i){ + const el = items[i].element; + if (el && el.hasValue()) { + const center = el.getCenterPoint(); + const d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + const tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x, + y + }; } - if (nearestElement) { - const tp = nearestElement.tooltipPosition(); - x = tp.x; - y = tp.y; - } - return { - x, - y - }; - } }; function pushOrConcat(base, toPush) { - if (toPush) { - if (isArray(toPush)) { - Array.prototype.push.apply(base, toPush); - } else { - base.push(toPush); + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } } - } - return base; + return base; } -function splitNewlines(str) { - if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { - return str.split('\n'); - } - return str; + function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; } -function createTooltipItem(chart, item) { - const {element, datasetIndex, index} = item; - const controller = chart.getDatasetMeta(datasetIndex).controller; - const {label, value} = controller.getLabelAndValue(index); - return { - chart, - label, - parsed: controller.getParsed(index), - raw: chart.data.datasets[datasetIndex].data[index], - formattedValue: value, - dataset: controller.getDataset(), - dataIndex: index, - datasetIndex, - element - }; + function createTooltipItem(chart, item) { + const { element , datasetIndex , index } = item; + const controller = chart.getDatasetMeta(datasetIndex).controller; + const { label , value } = controller.getLabelAndValue(index); + return { + chart, + label, + parsed: controller.getParsed(index), + raw: chart.data.datasets[datasetIndex].data[index], + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex, + element + }; } -function getTooltipSize(tooltip, options) { - const ctx = tooltip.chart.ctx; - const {body, footer, title} = tooltip; - const {boxWidth, boxHeight} = options; - const bodyFont = toFont(options.bodyFont); - const titleFont = toFont(options.titleFont); - const footerFont = toFont(options.footerFont); - const titleLineCount = title.length; - const footerLineCount = footer.length; - const bodyLineItemCount = body.length; - const padding = toPadding(options.padding); - let height = padding.height; - let width = 0; - let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); - combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; - if (titleLineCount) { - height += titleLineCount * titleFont.lineHeight - + (titleLineCount - 1) * options.titleSpacing - + options.titleMarginBottom; - } - if (combinedBodyLength) { - const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; - height += bodyLineItemCount * bodyLineHeight - + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight - + (combinedBodyLength - 1) * options.bodySpacing; - } - if (footerLineCount) { - height += options.footerMarginTop - + footerLineCount * footerFont.lineHeight - + (footerLineCount - 1) * options.footerSpacing; - } - let widthPadding = 0; - const maxLineWidth = function(line) { - width = Math.max(width, ctx.measureText(line).width + widthPadding); - }; - ctx.save(); - ctx.font = titleFont.string; - each(tooltip.title, maxLineWidth); - ctx.font = bodyFont.string; - each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); - widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0; - each(body, (bodyItem) => { - each(bodyItem.before, maxLineWidth); - each(bodyItem.lines, maxLineWidth); - each(bodyItem.after, maxLineWidth); - }); - widthPadding = 0; - ctx.font = footerFont.string; - each(tooltip.footer, maxLineWidth); - ctx.restore(); - width += padding.width; - return {width, height}; + function getTooltipSize(tooltip, options) { + const ctx = tooltip.chart.ctx; + const { body , footer , title } = tooltip; + const { boxWidth , boxHeight } = options; + const bodyFont = toFont(options.bodyFont); + const titleFont = toFont(options.titleFont); + const footerFont = toFont(options.footerFont); + const titleLineCount = title.length; + const footerLineCount = footer.length; + const bodyLineItemCount = body.length; + const padding = toPadding(options.padding); + let height = padding.height; + let width = 0; + let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom; + } + if (combinedBodyLength) { + const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; + height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing; + } + let widthPadding = 0; + const maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0; + each(body, (bodyItem)=>{ + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += padding.width; + return { + width, + height + }; } function determineYAlign(chart, size) { - const {y, height} = size; - if (y < height / 2) { - return 'top'; - } else if (y > (chart.height - height / 2)) { - return 'bottom'; - } - return 'center'; + const { y , height } = size; + if (y < height / 2) { + return 'top'; + } else if (y > chart.height - height / 2) { + return 'bottom'; + } + return 'center'; } function doesNotFitWithAlign(xAlign, chart, options, size) { - const {x, width} = size; - const caret = options.caretSize + options.caretPadding; - if (xAlign === 'left' && x + width + caret > chart.width) { - return true; - } - if (xAlign === 'right' && x - width - caret < 0) { - return true; - } + const { x , width } = size; + const caret = options.caretSize + options.caretPadding; + if (xAlign === 'left' && x + width + caret > chart.width) { + return true; + } + if (xAlign === 'right' && x - width - caret < 0) { + return true; + } } function determineXAlign(chart, options, size, yAlign) { - const {x, width} = size; - const {width: chartWidth, chartArea: {left, right}} = chart; - let xAlign = 'center'; - if (yAlign === 'center') { - xAlign = x <= (left + right) / 2 ? 'left' : 'right'; - } else if (x <= width / 2) { - xAlign = 'left'; - } else if (x >= chartWidth - width / 2) { - xAlign = 'right'; - } - if (doesNotFitWithAlign(xAlign, chart, options, size)) { - xAlign = 'center'; - } - return xAlign; + const { x , width } = size; + const { width: chartWidth , chartArea: { left , right } } = chart; + let xAlign = 'center'; + if (yAlign === 'center') { + xAlign = x <= (left + right) / 2 ? 'left' : 'right'; + } else if (x <= width / 2) { + xAlign = 'left'; + } else if (x >= chartWidth - width / 2) { + xAlign = 'right'; + } + if (doesNotFitWithAlign(xAlign, chart, options, size)) { + xAlign = 'center'; + } + return xAlign; } -function determineAlignment(chart, options, size) { - const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); - return { - xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), - yAlign - }; + function determineAlignment(chart, options, size) { + const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); + return { + xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), + yAlign + }; } function alignX(size, xAlign) { - let {x, width} = size; - if (xAlign === 'right') { - x -= width; - } else if (xAlign === 'center') { - x -= (width / 2); - } - return x; + let { x , width } = size; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= width / 2; + } + return x; } function alignY(size, yAlign, paddingAndSize) { - let {y, height} = size; - if (yAlign === 'top') { - y += paddingAndSize; - } else if (yAlign === 'bottom') { - y -= height + paddingAndSize; - } else { - y -= (height / 2); - } - return y; -} -function getBackgroundPoint(options, size, alignment, chart) { - const {caretSize, caretPadding, cornerRadius} = options; - const {xAlign, yAlign} = alignment; - const paddingAndSize = caretSize + caretPadding; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - let x = alignX(size, xAlign); - const y = alignY(size, yAlign, paddingAndSize); - if (yAlign === 'center') { - if (xAlign === 'left') { - x += paddingAndSize; - } else if (xAlign === 'right') { - x -= paddingAndSize; + let { y , height } = size; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= height / 2; } - } else if (xAlign === 'left') { - x -= Math.max(topLeft, bottomLeft) + caretSize; - } else if (xAlign === 'right') { - x += Math.max(topRight, bottomRight) + caretSize; - } - return { - x: _limitValue(x, 0, chart.width - size.width), - y: _limitValue(y, 0, chart.height - size.height) - }; + return y; +} + function getBackgroundPoint(options, size, alignment, chart) { + const { caretSize , caretPadding , cornerRadius } = options; + const { xAlign , yAlign } = alignment; + const paddingAndSize = caretSize + caretPadding; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); + let x = alignX(size, xAlign); + const y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x += Math.max(topRight, bottomRight) + caretSize; + } + return { + x: _limitValue(x, 0, chart.width - size.width), + y: _limitValue(y, 0, chart.height - size.height) + }; } function getAlignedX(tooltip, align, options) { - const padding = toPadding(options.padding); - return align === 'center' - ? tooltip.x + tooltip.width / 2 - : align === 'right' - ? tooltip.x + tooltip.width - padding.right - : tooltip.x + padding.left; + const padding = toPadding(options.padding); + return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left; } -function getBeforeAfterBodyLines(callback) { - return pushOrConcat([], splitNewlines(callback)); + function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); } function createTooltipContext(parent, tooltip, tooltipItems) { - return createContext(parent, { - tooltip, - tooltipItems, - type: 'tooltip' - }); + return createContext(parent, { + tooltip, + tooltipItems, + type: 'tooltip' + }); } function overrideCallbacks(callbacks, context) { - const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; - return override ? callbacks.override(override) : callbacks; + const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; + return override ? callbacks.override(override) : callbacks; } -class Tooltip extends Element { - constructor(config) { - super(); - this.opacity = 0; - this._active = []; - this._eventPosition = undefined; - this._size = undefined; - this._cachedAnimations = undefined; - this._tooltipItems = []; - this.$animations = undefined; - this.$context = undefined; - this.chart = config.chart || config._chart; - this._chart = this.chart; - this.options = config.options; - this.dataPoints = undefined; - this.title = undefined; - this.beforeBody = undefined; - this.body = undefined; - this.afterBody = undefined; - this.footer = undefined; - this.xAlign = undefined; - this.yAlign = undefined; - this.x = undefined; - this.y = undefined; - this.height = undefined; - this.width = undefined; - this.caretX = undefined; - this.caretY = undefined; - this.labelColors = undefined; - this.labelPointStyles = undefined; - this.labelTextColors = undefined; - } - initialize(options) { - this.options = options; - this._cachedAnimations = undefined; - this.$context = undefined; - } - _resolveAnimations() { - const cached = this._cachedAnimations; - if (cached) { - return cached; - } - const chart = this.chart; - const options = this.options.setContext(this.getContext()); - const opts = options.enabled && chart.options.animation && options.animations; - const animations = new Animations(this.chart, opts); - if (opts._cacheable) { - this._cachedAnimations = Object.freeze(animations); - } - return animations; - } - getContext() { - return this.$context || - (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); - } - getTitle(context, options) { - const {callbacks} = options; - const beforeTitle = callbacks.beforeTitle.apply(this, [context]); - const title = callbacks.title.apply(this, [context]); - const afterTitle = callbacks.afterTitle.apply(this, [context]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeTitle)); - lines = pushOrConcat(lines, splitNewlines(title)); - lines = pushOrConcat(lines, splitNewlines(afterTitle)); - return lines; - } - getBeforeBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems])); - } - getBody(tooltipItems, options) { - const {callbacks} = options; - const bodyItems = []; - each(tooltipItems, (context) => { - const bodyItem = { - before: [], - lines: [], - after: [] - }; - const scoped = overrideCallbacks(callbacks, context); - pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context))); - pushOrConcat(bodyItem.lines, scoped.label.call(this, context)); - pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context))); - bodyItems.push(bodyItem); - }); - return bodyItems; - } - getAfterBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems])); - } - getFooter(tooltipItems, options) { - const {callbacks} = options; - const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]); - const footer = callbacks.footer.apply(this, [tooltipItems]); - const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeFooter)); - lines = pushOrConcat(lines, splitNewlines(footer)); - lines = pushOrConcat(lines, splitNewlines(afterFooter)); - return lines; - } - _createItems(options) { - const active = this._active; - const data = this.chart.data; - const labelColors = []; - const labelPointStyles = []; - const labelTextColors = []; - let tooltipItems = []; - let i, len; - for (i = 0, len = active.length; i < len; ++i) { - tooltipItems.push(createTooltipItem(this.chart, active[i])); - } - if (options.filter) { - tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); - } - if (options.itemSort) { - tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); - } - each(tooltipItems, (context) => { - const scoped = overrideCallbacks(options.callbacks, context); - labelColors.push(scoped.labelColor.call(this, context)); - labelPointStyles.push(scoped.labelPointStyle.call(this, context)); - labelTextColors.push(scoped.labelTextColor.call(this, context)); - }); - this.labelColors = labelColors; - this.labelPointStyles = labelPointStyles; - this.labelTextColors = labelTextColors; - this.dataPoints = tooltipItems; - return tooltipItems; - } - update(changed, replay) { - const options = this.options.setContext(this.getContext()); - const active = this._active; - let properties; - let tooltipItems = []; - if (!active.length) { - if (this.opacity !== 0) { - properties = { - opacity: 0 - }; - } - } else { - const position = positioners[options.position].call(this, active, this._eventPosition); - tooltipItems = this._createItems(options); - this.title = this.getTitle(tooltipItems, options); - this.beforeBody = this.getBeforeBody(tooltipItems, options); - this.body = this.getBody(tooltipItems, options); - this.afterBody = this.getAfterBody(tooltipItems, options); - this.footer = this.getFooter(tooltipItems, options); - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, size); - const alignment = determineAlignment(this.chart, options, positionAndSize); - const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - properties = { - opacity: 1, - x: backgroundPoint.x, - y: backgroundPoint.y, - width: size.width, - height: size.height, - caretX: position.x, - caretY: position.y - }; - } - this._tooltipItems = tooltipItems; - this.$context = undefined; - if (properties) { - this._resolveAnimations().update(this, properties); - } - if (changed && options.external) { - options.external.call(this, {chart: this.chart, tooltip: this, replay}); - } - } - drawCaret(tooltipPoint, ctx, size, options) { - const caretPosition = this.getCaretPosition(tooltipPoint, size, options); - ctx.lineTo(caretPosition.x1, caretPosition.y1); - ctx.lineTo(caretPosition.x2, caretPosition.y2); - ctx.lineTo(caretPosition.x3, caretPosition.y3); - } - getCaretPosition(tooltipPoint, size, options) { - const {xAlign, yAlign} = this; - const {caretSize, cornerRadius} = options; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - const {x: ptX, y: ptY} = tooltipPoint; - const {width, height} = size; - let x1, x2, x3, y1, y2, y3; - if (yAlign === 'center') { - y2 = ptY + (height / 2); - if (xAlign === 'left') { - x1 = ptX; - x2 = x1 - caretSize; - y1 = y2 + caretSize; - y3 = y2 - caretSize; - } else { - x1 = ptX + width; - x2 = x1 + caretSize; - y1 = y2 - caretSize; - y3 = y2 + caretSize; - } - x3 = x1; - } else { - if (xAlign === 'left') { - x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize); - } else if (xAlign === 'right') { - x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; - } else { - x2 = this.caretX; - } - if (yAlign === 'top') { - y1 = ptY; - y2 = y1 - caretSize; - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } else { - y1 = ptY + height; - y2 = y1 + caretSize; - x1 = x2 + caretSize; - x3 = x2 - caretSize; - } - y3 = y1; - } - return {x1, x2, x3, y1, y2, y3}; - } - drawTitle(pt, ctx, options) { - const title = this.title; - const length = title.length; - let titleFont, titleSpacing, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.titleAlign, options); - ctx.textAlign = rtlHelper.textAlign(options.titleAlign); - ctx.textBaseline = 'middle'; - titleFont = toFont(options.titleFont); - titleSpacing = options.titleSpacing; - ctx.fillStyle = options.titleColor; - ctx.font = titleFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); - pt.y += titleFont.lineHeight + titleSpacing; - if (i + 1 === length) { - pt.y += options.titleMarginBottom - titleSpacing; - } - } - } - } - _drawColorBox(ctx, pt, i, rtlHelper, options) { - const labelColors = this.labelColors[i]; - const labelPointStyle = this.labelPointStyles[i]; - const {boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - const colorX = getAlignedX(this, 'left', options); - const rtlColorX = rtlHelper.x(colorX); - const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; - const colorY = pt.y + yOffSet; - if (options.usePointStyle) { - const drawOptions = { - radius: Math.min(boxWidth, boxHeight) / 2, - pointStyle: labelPointStyle.pointStyle, - rotation: labelPointStyle.rotation, - borderWidth: 1 - }; - const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; - const centerY = colorY + boxHeight / 2; - ctx.strokeStyle = options.multiKeyBackground; - ctx.fillStyle = options.multiKeyBackground; - drawPoint(ctx, drawOptions, centerX, centerY); - ctx.strokeStyle = labelColors.borderColor; - ctx.fillStyle = labelColors.backgroundColor; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - ctx.lineWidth = labelColors.borderWidth || 1; - ctx.strokeStyle = labelColors.borderColor; - ctx.setLineDash(labelColors.borderDash || []); - ctx.lineDashOffset = labelColors.borderDashOffset || 0; - const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding); - const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2); - const borderRadius = toTRBLCorners(labelColors.borderRadius); - if (Object.values(borderRadius).some(v => v !== 0)) { - ctx.beginPath(); - ctx.fillStyle = options.multiKeyBackground; - addRoundedRectPath(ctx, { - x: outerX, - y: colorY, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); - ctx.fill(); - ctx.stroke(); - ctx.fillStyle = labelColors.backgroundColor; - ctx.beginPath(); - addRoundedRectPath(ctx, { - x: innerX, - y: colorY + 1, - w: boxWidth - 2, - h: boxHeight - 2, - radius: borderRadius, - }); - ctx.fill(); - } else { - ctx.fillStyle = options.multiKeyBackground; - ctx.fillRect(outerX, colorY, boxWidth, boxHeight); - ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); - ctx.fillStyle = labelColors.backgroundColor; - ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); - } - } - ctx.fillStyle = this.labelTextColors[i]; - } - drawBody(pt, ctx, options) { - const {body} = this; - const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - let bodyLineHeight = bodyFont.lineHeight; - let xLinePadding = 0; - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - const fillLineOfText = function(line) { - ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); - pt.y += bodyLineHeight + bodySpacing; - }; - const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); - let bodyItem, textColor, lines, i, j, ilen, jlen; - ctx.textAlign = bodyAlign; - ctx.textBaseline = 'middle'; - ctx.font = bodyFont.string; - pt.x = getAlignedX(this, bodyAlignForCalculation, options); - ctx.fillStyle = options.bodyColor; - each(this.beforeBody, fillLineOfText); - xLinePadding = displayColors && bodyAlignForCalculation !== 'right' - ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding) - : 0; - for (i = 0, ilen = body.length; i < ilen; ++i) { - bodyItem = body[i]; - textColor = this.labelTextColors[i]; - ctx.fillStyle = textColor; - each(bodyItem.before, fillLineOfText); - lines = bodyItem.lines; - if (displayColors && lines.length) { - this._drawColorBox(ctx, pt, i, rtlHelper, options); - bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); - } - for (j = 0, jlen = lines.length; j < jlen; ++j) { - fillLineOfText(lines[j]); - bodyLineHeight = bodyFont.lineHeight; - } - each(bodyItem.after, fillLineOfText); - } - xLinePadding = 0; - bodyLineHeight = bodyFont.lineHeight; - each(this.afterBody, fillLineOfText); - pt.y -= bodySpacing; - } - drawFooter(pt, ctx, options) { - const footer = this.footer; - const length = footer.length; - let footerFont, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.footerAlign, options); - pt.y += options.footerMarginTop; - ctx.textAlign = rtlHelper.textAlign(options.footerAlign); - ctx.textBaseline = 'middle'; - footerFont = toFont(options.footerFont); - ctx.fillStyle = options.footerColor; - ctx.font = footerFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); - pt.y += footerFont.lineHeight + options.footerSpacing; - } - } - } - drawBackground(pt, ctx, tooltipSize, options) { - const {xAlign, yAlign} = this; - const {x, y} = pt; - const {width, height} = tooltipSize; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius); - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.beginPath(); - ctx.moveTo(x + topLeft, y); - if (yAlign === 'top') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width - topRight, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); - if (yAlign === 'center' && xAlign === 'right') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width, y + height - bottomRight); - ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); - if (yAlign === 'bottom') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + bottomLeft, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); - if (yAlign === 'center' && xAlign === 'left') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x, y + topLeft); - ctx.quadraticCurveTo(x, y, x + topLeft, y); - ctx.closePath(); - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } - } - _updateAnimationTarget(options) { - const chart = this.chart; - const anims = this.$animations; - const animX = anims && anims.x; - const animY = anims && anims.y; - if (animX || animY) { - const position = positioners[options.position].call(this, this._active, this._eventPosition); - if (!position) { - return; - } - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, this._size); - const alignment = determineAlignment(chart, options, positionAndSize); - const point = getBackgroundPoint(options, positionAndSize, alignment, chart); - if (animX._to !== point.x || animY._to !== point.y) { - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - this.width = size.width; - this.height = size.height; - this.caretX = position.x; - this.caretY = position.y; - this._resolveAnimations().update(this, point); - } - } - } - draw(ctx) { - const options = this.options.setContext(this.getContext()); - let opacity = this.opacity; - if (!opacity) { - return; - } - this._updateAnimationTarget(options); - const tooltipSize = { - width: this.width, - height: this.height - }; - const pt = { - x: this.x, - y: this.y - }; - opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; - const padding = toPadding(options.padding); - const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; - if (options.enabled && hasTooltipContent) { - ctx.save(); - ctx.globalAlpha = opacity; - this.drawBackground(pt, ctx, tooltipSize, options); - overrideTextDirection(ctx, options.textDirection); - pt.y += padding.top; - this.drawTitle(pt, ctx, options); - this.drawBody(pt, ctx, options); - this.drawFooter(pt, ctx, options); - restoreTextDirection(ctx, options.textDirection); - ctx.restore(); - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements, eventPosition) { - const lastActive = this._active; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.chart.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('Cannot find a dataset at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(lastActive, active); - const positionChanged = this._positionChanged(active, eventPosition); - if (changed || positionChanged) { - this._active = active; - this._eventPosition = eventPosition; - this._ignoreReplayEvents = true; - this.update(true); - } - } - handleEvent(e, replay, inChartArea = true) { - if (replay && this._ignoreReplayEvents) { - return false; - } - this._ignoreReplayEvents = false; - const options = this.options; - const lastActive = this._active || []; - const active = this._getActiveElements(e, lastActive, replay, inChartArea); - const positionChanged = this._positionChanged(active, e); - const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; - if (changed) { - this._active = active; - if (options.enabled || options.external) { - this._eventPosition = { - x: e.x, - y: e.y - }; - this.update(true, replay); - } - } - return changed; - } - _getActiveElements(e, lastActive, replay, inChartArea) { - const options = this.options; - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); - if (options.reverse) { - active.reverse(); - } - return active; - } - _positionChanged(active, e) { - const {caretX, caretY, options} = this; - const position = positioners[options.position].call(this, active, e); - return position !== false && (caretX !== position.x || caretY !== position.y); - } -} -Tooltip.positioners = positioners; -var plugin_tooltip = { - id: 'tooltip', - _element: Tooltip, - positioners, - afterInit(chart, _args, options) { - if (options) { - chart.tooltip = new Tooltip({chart, options}); - } - }, - beforeUpdate(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - reset(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - afterDraw(chart) { - const tooltip = chart.tooltip; - const args = { - tooltip - }; - if (chart.notifyPlugins('beforeTooltipDraw', args) === false) { - return; - } - if (tooltip) { - tooltip.draw(chart.ctx); - } - chart.notifyPlugins('afterTooltipDraw', args); - }, - afterEvent(chart, args) { - if (chart.tooltip) { - const useFinalPosition = args.replay; - if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { - args.changed = true; - } - } - }, - defaults: { - enabled: true, - external: null, - position: 'average', - backgroundColor: 'rgba(0,0,0,0.8)', - titleColor: '#fff', - titleFont: { - weight: 'bold', - }, - titleSpacing: 2, - titleMarginBottom: 6, - titleAlign: 'left', - bodyColor: '#fff', - bodySpacing: 2, - bodyFont: { - }, - bodyAlign: 'left', - footerColor: '#fff', - footerSpacing: 2, - footerMarginTop: 6, - footerFont: { - weight: 'bold', - }, - footerAlign: 'left', - padding: 6, - caretPadding: 2, - caretSize: 5, - cornerRadius: 6, - boxHeight: (ctx, opts) => opts.bodyFont.size, - boxWidth: (ctx, opts) => opts.bodyFont.size, - multiKeyBackground: '#fff', - displayColors: true, - boxPadding: 0, - borderColor: 'rgba(0,0,0,0)', - borderWidth: 0, - animation: { - duration: 400, - easing: 'easeOutQuart', - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], - }, - opacity: { - easing: 'linear', - duration: 200 - } - }, - callbacks: { - beforeTitle: noop, - title(tooltipItems) { +const defaultCallbacks = { + beforeTitle: noop, + title (tooltipItems) { if (tooltipItems.length > 0) { - const item = tooltipItems[0]; - const labels = item.chart.data.labels; - const labelCount = labels ? labels.length : 0; - if (this && this.options && this.options.mode === 'dataset') { - return item.dataset.label || ''; - } else if (item.label) { - return item.label; - } else if (labelCount > 0 && item.dataIndex < labelCount) { - return labels[item.dataIndex]; - } + const item = tooltipItems[0]; + const labels = item.chart.data.labels; + const labelCount = labels ? labels.length : 0; + if (this && this.options && this.options.mode === 'dataset') { + return item.dataset.label || ''; + } else if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } } return ''; - }, - afterTitle: noop, - beforeBody: noop, - beforeLabel: noop, - label(tooltipItem) { + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label (tooltipItem) { if (this && this.options && this.options.mode === 'dataset') { - return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; + return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; } let label = tooltipItem.dataset.label || ''; if (label) { - label += ': '; + label += ': '; } const value = tooltipItem.formattedValue; if (!isNullOrUndef(value)) { - label += value; + label += value; } return label; - }, - labelColor(tooltipItem) { + }, + labelColor (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { - borderColor: options.borderColor, - backgroundColor: options.backgroundColor, - borderWidth: options.borderWidth, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderRadius: 0, + borderColor: options.borderColor, + backgroundColor: options.backgroundColor, + borderWidth: options.borderWidth, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderRadius: 0 }; - }, - labelTextColor() { + }, + labelTextColor () { return this.options.bodyColor; - }, - labelPointStyle(tooltipItem) { + }, + labelPointStyle (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { - pointStyle: options.pointStyle, - rotation: options.rotation, + pointStyle: options.pointStyle, + rotation: options.rotation }; - }, - afterLabel: noop, - afterBody: noop, - beforeFooter: noop, - footer: noop, - afterFooter: noop - } - }, - defaultRoutes: { - bodyFont: 'font', - footerFont: 'font', - titleFont: 'font' - }, - descriptors: { - _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external', - _indexable: false, - callbacks: { - _scriptable: false, - _indexable: false, }, - animation: { - _fallback: false - }, - animations: { - _fallback: 'animation' + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop +}; + function invokeCallbackWithFallback(callbacks, name, ctx, arg) { + const result = callbacks[name].call(ctx, arg); + if (typeof result === 'undefined') { + return defaultCallbacks[name].call(ctx, arg); } - }, - additionalOptionScopes: ['interaction'] + return result; +} +class Tooltip extends Element { + static positioners = positioners; + constructor(config){ + super(); + this.opacity = 0; + this._active = []; + this._eventPosition = undefined; + this._size = undefined; + this._cachedAnimations = undefined; + this._tooltipItems = []; + this.$animations = undefined; + this.$context = undefined; + this.chart = config.chart; + this.options = config.options; + this.dataPoints = undefined; + this.title = undefined; + this.beforeBody = undefined; + this.body = undefined; + this.afterBody = undefined; + this.footer = undefined; + this.xAlign = undefined; + this.yAlign = undefined; + this.x = undefined; + this.y = undefined; + this.height = undefined; + this.width = undefined; + this.caretX = undefined; + this.caretY = undefined; + this.labelColors = undefined; + this.labelPointStyles = undefined; + this.labelTextColors = undefined; + } + initialize(options) { + this.options = options; + this._cachedAnimations = undefined; + this.$context = undefined; + } + _resolveAnimations() { + const cached = this._cachedAnimations; + if (cached) { + return cached; + } + const chart = this.chart; + const options = this.options.setContext(this.getContext()); + const opts = options.enabled && chart.options.animation && options.animations; + const animations = new Animations(this.chart, opts); + if (opts._cacheable) { + this._cachedAnimations = Object.freeze(animations); + } + return animations; + } + getContext() { + return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); + } + getTitle(context, options) { + const { callbacks } = options; + const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context); + const title = invokeCallbackWithFallback(callbacks, 'title', this, context); + const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + } + getBeforeBody(tooltipItems, options) { + return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems)); + } + getBody(tooltipItems, options) { + const { callbacks } = options; + const bodyItems = []; + each(tooltipItems, (context)=>{ + const bodyItem = { + before: [], + lines: [], + after: [] + }; + const scoped = overrideCallbacks(callbacks, context); + pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context))); + pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context)); + pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + } + getAfterBody(tooltipItems, options) { + return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems)); + } + getFooter(tooltipItems, options) { + const { callbacks } = options; + const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems); + const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems); + const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + _createItems(options) { + const active = this._active; + const data = this.chart.data; + const labelColors = []; + const labelPointStyles = []; + const labelTextColors = []; + let tooltipItems = []; + let i, len; + for(i = 0, len = active.length; i < len; ++i){ + tooltipItems.push(createTooltipItem(this.chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data)); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data)); + } + each(tooltipItems, (context)=>{ + const scoped = overrideCallbacks(options.callbacks, context); + labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context)); + labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context)); + labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context)); + }); + this.labelColors = labelColors; + this.labelPointStyles = labelPointStyles; + this.labelTextColors = labelTextColors; + this.dataPoints = tooltipItems; + return tooltipItems; + } + update(changed, replay) { + const options = this.options.setContext(this.getContext()); + const active = this._active; + let properties; + let tooltipItems = []; + if (!active.length) { + if (this.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + const position = positioners[options.position].call(this, active, this._eventPosition); + tooltipItems = this._createItems(options); + this.title = this.getTitle(tooltipItems, options); + this.beforeBody = this.getBeforeBody(tooltipItems, options); + this.body = this.getBody(tooltipItems, options); + this.afterBody = this.getAfterBody(tooltipItems, options); + this.footer = this.getFooter(tooltipItems, options); + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, size); + const alignment = determineAlignment(this.chart, options, positionAndSize); + const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + this._tooltipItems = tooltipItems; + this.$context = undefined; + if (properties) { + this._resolveAnimations().update(this, properties); + } + if (changed && options.external) { + options.external.call(this, { + chart: this.chart, + tooltip: this, + replay + }); + } + } + drawCaret(tooltipPoint, ctx, size, options) { + const caretPosition = this.getCaretPosition(tooltipPoint, size, options); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + } + getCaretPosition(tooltipPoint, size, options) { + const { xAlign , yAlign } = this; + const { caretSize , cornerRadius } = options; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); + const { x: ptX , y: ptY } = tooltipPoint; + const { width , height } = size; + let x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + height / 2; + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return { + x1, + x2, + x3, + y1, + y2, + y3 + }; + } + drawTitle(pt, ctx, options) { + const title = this.title; + const length = title.length; + let titleFont, titleSpacing, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.titleAlign, options); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = toFont(options.titleFont); + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleColor; + ctx.font = titleFont.string; + for(i = 0; i < length; ++i){ + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); + pt.y += titleFont.lineHeight + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + _drawColorBox(ctx, pt, i, rtlHelper, options) { + const labelColor = this.labelColors[i]; + const labelPointStyle = this.labelPointStyles[i]; + const { boxHeight , boxWidth } = options; + const bodyFont = toFont(options.bodyFont); + const colorX = getAlignedX(this, 'left', options); + const rtlColorX = rtlHelper.x(colorX); + const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; + const colorY = pt.y + yOffSet; + if (options.usePointStyle) { + const drawOptions = { + radius: Math.min(boxWidth, boxHeight) / 2, + pointStyle: labelPointStyle.pointStyle, + rotation: labelPointStyle.rotation, + borderWidth: 1 + }; + const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; + const centerY = colorY + boxHeight / 2; + ctx.strokeStyle = options.multiKeyBackground; + ctx.fillStyle = options.multiKeyBackground; + drawPoint(ctx, drawOptions, centerX, centerY); + ctx.strokeStyle = labelColor.borderColor; + ctx.fillStyle = labelColor.backgroundColor; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + ctx.lineWidth = isObject(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1; + ctx.strokeStyle = labelColor.borderColor; + ctx.setLineDash(labelColor.borderDash || []); + ctx.lineDashOffset = labelColor.borderDashOffset || 0; + const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth); + const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2); + const borderRadius = toTRBLCorners(labelColor.borderRadius); + if (Object.values(borderRadius).some((v)=>v !== 0)) { + ctx.beginPath(); + ctx.fillStyle = options.multiKeyBackground; + addRoundedRectPath(ctx, { + x: outerX, + y: colorY, + w: boxWidth, + h: boxHeight, + radius: borderRadius + }); + ctx.fill(); + ctx.stroke(); + ctx.fillStyle = labelColor.backgroundColor; + ctx.beginPath(); + addRoundedRectPath(ctx, { + x: innerX, + y: colorY + 1, + w: boxWidth - 2, + h: boxHeight - 2, + radius: borderRadius + }); + ctx.fill(); + } else { + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(outerX, colorY, boxWidth, boxHeight); + ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColor.backgroundColor; + ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); + } + } + ctx.fillStyle = this.labelTextColors[i]; + } + drawBody(pt, ctx, options) { + const { body } = this; + const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options; + const bodyFont = toFont(options.bodyFont); + let bodyLineHeight = bodyFont.lineHeight; + let xLinePadding = 0; + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + const fillLineOfText = function(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + let bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(this, bodyAlignForCalculation, options); + ctx.fillStyle = options.bodyColor; + each(this.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0; + for(i = 0, ilen = body.length; i < ilen; ++i){ + bodyItem = body[i]; + textColor = this.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + this._drawColorBox(ctx, pt, i, rtlHelper, options); + bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); + } + for(j = 0, jlen = lines.length; j < jlen; ++j){ + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.lineHeight; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.lineHeight; + each(this.afterBody, fillLineOfText); + pt.y -= bodySpacing; + } + drawFooter(pt, ctx, options) { + const footer = this.footer; + const length = footer.length; + let footerFont, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.footerAlign, options); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = toFont(options.footerFont); + ctx.fillStyle = options.footerColor; + ctx.font = footerFont.string; + for(i = 0; i < length; ++i){ + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); + pt.y += footerFont.lineHeight + options.footerSpacing; + } + } + } + drawBackground(pt, ctx, tooltipSize, options) { + const { xAlign , yAlign } = this; + const { x , y } = pt; + const { width , height } = tooltipSize; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(options.cornerRadius); + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + topLeft, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width - topRight, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width, y + height - bottomRight); + ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + bottomLeft, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x, y + topLeft); + ctx.quadraticCurveTo(x, y, x + topLeft, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + _updateAnimationTarget(options) { + const chart = this.chart; + const anims = this.$animations; + const animX = anims && anims.x; + const animY = anims && anims.y; + if (animX || animY) { + const position = positioners[options.position].call(this, this._active, this._eventPosition); + if (!position) { + return; + } + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, this._size); + const alignment = determineAlignment(chart, options, positionAndSize); + const point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + this.width = size.width; + this.height = size.height; + this.caretX = position.x; + this.caretY = position.y; + this._resolveAnimations().update(this, point); + } + } + } + _willRender() { + return !!this.opacity; + } + draw(ctx) { + const options = this.options.setContext(this.getContext()); + let opacity = this.opacity; + if (!opacity) { + return; + } + this._updateAnimationTarget(options); + const tooltipSize = { + width: this.width, + height: this.height + }; + const pt = { + x: this.x, + y: this.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + const padding = toPadding(options.padding); + const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + this.drawBackground(pt, ctx, tooltipSize, options); + overrideTextDirection(ctx, options.textDirection); + pt.y += padding.top; + this.drawTitle(pt, ctx, options); + this.drawBody(pt, ctx, options); + this.drawFooter(pt, ctx, options); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements, eventPosition) { + const lastActive = this._active; + const active = activeElements.map(({ datasetIndex , index })=>{ + const meta = this.chart.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('Cannot find a dataset at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index + }; + }); + const changed = !_elementsEqual(lastActive, active); + const positionChanged = this._positionChanged(active, eventPosition); + if (changed || positionChanged) { + this._active = active; + this._eventPosition = eventPosition; + this._ignoreReplayEvents = true; + this.update(true); + } + } + handleEvent(e, replay, inChartArea = true) { + if (replay && this._ignoreReplayEvents) { + return false; + } + this._ignoreReplayEvents = false; + const options = this.options; + const lastActive = this._active || []; + const active = this._getActiveElements(e, lastActive, replay, inChartArea); + const positionChanged = this._positionChanged(active, e); + const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + this._active = active; + if (options.enabled || options.external) { + this._eventPosition = { + x: e.x, + y: e.y + }; + this.update(true, replay); + } + } + return changed; + } + _getActiveElements(e, lastActive, replay, inChartArea) { + const options = this.options; + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + return active; + } + _positionChanged(active, e) { + const { caretX , caretY , options } = this; + const position = positioners[options.position].call(this, active, e); + return position !== false && (caretX !== position.x || caretY !== position.y); + } +} +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners, + afterInit (chart, _args, options) { + if (options) { + chart.tooltip = new Tooltip({ + chart, + options + }); + } + }, + beforeUpdate (chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + reset (chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + afterDraw (chart) { + const tooltip = chart.tooltip; + if (tooltip && tooltip._willRender()) { + const args = { + tooltip + }; + if (chart.notifyPlugins('beforeTooltipDraw', { + ...args, + cancelable: true + }) === false) { + return; + } + tooltip.draw(chart.ctx); + chart.notifyPlugins('afterTooltipDraw', args); + } + }, + afterEvent (chart, args) { + if (chart.tooltip) { + const useFinalPosition = args.replay; + if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { + args.changed = true; + } + } + }, + defaults: { + enabled: true, + external: null, + position: 'average', + backgroundColor: 'rgba(0,0,0,0.8)', + titleColor: '#fff', + titleFont: { + weight: 'bold' + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodyColor: '#fff', + bodySpacing: 2, + bodyFont: {}, + bodyAlign: 'left', + footerColor: '#fff', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + weight: 'bold' + }, + footerAlign: 'left', + padding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + boxHeight: (ctx, opts)=>opts.bodyFont.size, + boxWidth: (ctx, opts)=>opts.bodyFont.size, + multiKeyBackground: '#fff', + displayColors: true, + boxPadding: 0, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart' + }, + animations: { + numbers: { + type: 'number', + properties: [ + 'x', + 'y', + 'width', + 'height', + 'caretX', + 'caretY' + ] + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: defaultCallbacks + }, + defaultRoutes: { + bodyFont: 'font', + footerFont: 'font', + titleFont: 'font' + }, + descriptors: { + _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external', + _indexable: false, + callbacks: { + _scriptable: false, + _indexable: false + }, + animation: { + _fallback: false + }, + animations: { + _fallback: 'animation' + } + }, + additionalOptionScopes: [ + 'interaction' + ] }; var plugins = /*#__PURE__*/Object.freeze({ __proto__: null, +Colors: plugin_colors, Decimation: plugin_decimation, -Filler: plugin_filler, +Filler: index, Legend: plugin_legend, SubTitle: plugin_subtitle, Title: plugin_title, Tooltip: plugin_tooltip }); -const addIfString = (labels, raw, index, addedLabels) => { - if (typeof raw === 'string') { - index = labels.push(raw) - 1; - addedLabels.unshift({index, label: raw}); - } else if (isNaN(raw)) { - index = null; - } - return index; +const addIfString = (labels, raw, index, addedLabels)=>{ + if (typeof raw === 'string') { + index = labels.push(raw) - 1; + addedLabels.unshift({ + index, + label: raw + }); + } else if (isNaN(raw)) { + index = null; + } + return index; }; function findOrAddLabel(labels, raw, index, addedLabels) { - const first = labels.indexOf(raw); - if (first === -1) { - return addIfString(labels, raw, index, addedLabels); - } - const last = labels.lastIndexOf(raw); - return first !== last ? index : first; + const first = labels.indexOf(raw); + if (first === -1) { + return addIfString(labels, raw, index, addedLabels); + } + const last = labels.lastIndexOf(raw); + return first !== last ? index : first; } -const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max); -class CategoryScale extends Scale { - constructor(cfg) { - super(cfg); - this._startValue = undefined; - this._valueRange = 0; - this._addedLabels = []; - } - init(scaleOptions) { - const added = this._addedLabels; - if (added.length) { - const labels = this.getLabels(); - for (const {index, label} of added) { - if (labels[index] === label) { - labels.splice(index, 1); - } - } - this._addedLabels = []; - } - super.init(scaleOptions); - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; - } - const labels = this.getLabels(); - index = isFinite(index) && labels[index] === raw ? index - : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); - return validIndex(index, labels.length - 1); - } - determineDataLimits() { - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this.getMinMax(true); - if (this.options.bounds === 'ticks') { - if (!minDefined) { - min = 0; - } - if (!maxDefined) { - max = this.getLabels().length - 1; - } - } - this.min = min; - this.max = max; - } - buildTicks() { - const min = this.min; - const max = this.max; - const offset = this.options.offset; - const ticks = []; - let labels = this.getLabels(); - labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); - this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); - this._startValue = this.min - (offset ? 0.5 : 0); - for (let value = min; value <= max; value++) { - ticks.push({value}); - } - return ticks; - } - getLabelForValue(value) { +const validIndex = (index, max)=>index === null ? null : _limitValue(Math.round(index), 0, max); +function _getLabelForValue(value) { const labels = this.getLabels(); if (value >= 0 && value < labels.length) { - return labels[value]; + return labels[value]; } return value; - } - configure() { - super.configure(); - if (!this.isHorizontal()) { - this._reversePixels = !this._reversePixels; - } - } - getPixelForValue(value) { - if (typeof value !== 'number') { - value = this.parse(value); - } - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getValueForPixel(pixel) { - return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); - } - getBasePixel() { - return this.bottom; - } } -CategoryScale.id = 'category'; -CategoryScale.defaults = { - ticks: { - callback: CategoryScale.prototype.getLabelForValue - } -}; +class CategoryScale extends Scale { + static id = 'category'; + static defaults = { + ticks: { + callback: _getLabelForValue + } + }; + constructor(cfg){ + super(cfg); + this._startValue = undefined; + this._valueRange = 0; + this._addedLabels = []; + } + init(scaleOptions) { + const added = this._addedLabels; + if (added.length) { + const labels = this.getLabels(); + for (const { index , label } of added){ + if (labels[index] === label) { + labels.splice(index, 1); + } + } + this._addedLabels = []; + } + super.init(scaleOptions); + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + const labels = this.getLabels(); + index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); + return validIndex(index, labels.length - 1); + } + determineDataLimits() { + const { minDefined , maxDefined } = this.getUserBounds(); + let { min , max } = this.getMinMax(true); + if (this.options.bounds === 'ticks') { + if (!minDefined) { + min = 0; + } + if (!maxDefined) { + max = this.getLabels().length - 1; + } + } + this.min = min; + this.max = max; + } + buildTicks() { + const min = this.min; + const max = this.max; + const offset = this.options.offset; + const ticks = []; + let labels = this.getLabels(); + labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1); + this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); + this._startValue = this.min - (offset ? 0.5 : 0); + for(let value = min; value <= max; value++){ + ticks.push({ + value + }); + } + return ticks; + } + getLabelForValue(value) { + return _getLabelForValue.call(this, value); + } + configure() { + super.configure(); + if (!this.isHorizontal()) { + this._reversePixels = !this._reversePixels; + } + } + getPixelForValue(value) { + if (typeof value !== 'number') { + value = this.parse(value); + } + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getValueForPixel(pixel) { + return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); + } + getBasePixel() { + return this.bottom; + } +} function generateTicks$1(generationOptions, dataRange) { - const ticks = []; - const MIN_SPACING = 1e-14; - const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions; - const unit = step || 1; - const maxSpaces = maxTicks - 1; - const {min: rmin, max: rmax} = dataRange; - const minDefined = !isNullOrUndef(min); - const maxDefined = !isNullOrUndef(max); - const countDefined = !isNullOrUndef(count); - const minSpacing = (rmax - rmin) / (maxDigits + 1); - let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; - let factor, niceMin, niceMax, numSpaces; - if (spacing < MIN_SPACING && !minDefined && !maxDefined) { - return [{value: rmin}, {value: rmax}]; - } - numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); - if (numSpaces > maxSpaces) { - spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; - } - if (!isNullOrUndef(precision)) { - factor = Math.pow(10, precision); - spacing = Math.ceil(spacing * factor) / factor; - } - if (bounds === 'ticks') { - niceMin = Math.floor(rmin / spacing) * spacing; - niceMax = Math.ceil(rmax / spacing) * spacing; - } else { - niceMin = rmin; - niceMax = rmax; - } - if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { - numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); - spacing = (max - min) / numSpaces; - niceMin = min; - niceMax = max; - } else if (countDefined) { - niceMin = minDefined ? min : niceMin; - niceMax = maxDefined ? max : niceMax; - numSpaces = count - 1; - spacing = (niceMax - niceMin) / numSpaces; - } else { - numSpaces = (niceMax - niceMin) / spacing; - if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { - numSpaces = Math.round(numSpaces); + const ticks = []; + const MIN_SPACING = 1e-14; + const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions; + const unit = step || 1; + const maxSpaces = maxTicks - 1; + const { min: rmin , max: rmax } = dataRange; + const minDefined = !isNullOrUndef(min); + const maxDefined = !isNullOrUndef(max); + const countDefined = !isNullOrUndef(count); + const minSpacing = (rmax - rmin) / (maxDigits + 1); + let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; + let factor, niceMin, niceMax, numSpaces; + if (spacing < MIN_SPACING && !minDefined && !maxDefined) { + return [ + { + value: rmin + }, + { + value: rmax + } + ]; + } + numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); + if (numSpaces > maxSpaces) { + spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; + } + if (!isNullOrUndef(precision)) { + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } + if (bounds === 'ticks') { + niceMin = Math.floor(rmin / spacing) * spacing; + niceMax = Math.ceil(rmax / spacing) * spacing; } else { - numSpaces = Math.ceil(numSpaces); + niceMin = rmin; + niceMax = rmax; } - } - const decimalPlaces = Math.max( - _decimalPlaces(spacing), - _decimalPlaces(niceMin) - ); - factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); - niceMin = Math.round(niceMin * factor) / factor; - niceMax = Math.round(niceMax * factor) / factor; - let j = 0; - if (minDefined) { - if (includeBounds && niceMin !== min) { - ticks.push({value: min}); - if (niceMin < min) { - j++; - } - if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { - j++; - } - } else if (niceMin < min) { - j++; - } - } - for (; j < numSpaces; ++j) { - ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); - } - if (maxDefined && includeBounds && niceMax !== max) { - if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { - ticks[ticks.length - 1].value = max; + if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { + numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); + spacing = (max - min) / numSpaces; + niceMin = min; + niceMax = max; + } else if (countDefined) { + niceMin = minDefined ? min : niceMin; + niceMax = maxDefined ? max : niceMax; + numSpaces = count - 1; + spacing = (niceMax - niceMin) / numSpaces; } else { - ticks.push({value: max}); + numSpaces = (niceMax - niceMin) / spacing; + if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } } - } else if (!maxDefined || niceMax === max) { - ticks.push({value: niceMax}); - } - return ticks; -} -function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) { - const rad = toRadians(minRotation); - const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; - const length = 0.75 * minSpacing * ('' + value).length; - return Math.min(minSpacing / ratio, length); -} -class LinearScaleBase extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._endValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; + const decimalPlaces = Math.max(_decimalPlaces(spacing), _decimalPlaces(niceMin)); + factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); + niceMin = Math.round(niceMin * factor) / factor; + niceMax = Math.round(niceMax * factor) / factor; + let j = 0; + if (minDefined) { + if (includeBounds && niceMin !== min) { + ticks.push({ + value: min + }); + if (niceMin < min) { + j++; + } + if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { + j++; + } + } else if (niceMin < min) { + j++; + } } - if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { - return null; + for(; j < numSpaces; ++j){ + const tickValue = Math.round((niceMin + j * spacing) * factor) / factor; + if (maxDefined && tickValue > max) { + break; + } + ticks.push({ + value: tickValue + }); } - return +raw; - } - handleTickRangeOptions() { - const {beginAtZero} = this.options; - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - if (beginAtZero) { - const minSign = sign(min); - const maxSign = sign(max); - if (minSign < 0 && maxSign < 0) { - setMax(0); - } else if (minSign > 0 && maxSign > 0) { - setMin(0); - } - } - if (min === max) { - let offset = 1; - if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) { - offset = Math.abs(max * 0.05); - } - setMax(max + offset); - if (!beginAtZero) { - setMin(min - offset); - } - } - this.min = min; - this.max = max; - } - getTickLimit() { - const tickOpts = this.options.ticks; - let {maxTicksLimit, stepSize} = tickOpts; - let maxTicks; - if (stepSize) { - maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; - if (maxTicks > 1000) { - console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); - maxTicks = 1000; - } - } else { - maxTicks = this.computeTickLimit(); - maxTicksLimit = maxTicksLimit || 11; - } - if (maxTicksLimit) { - maxTicks = Math.min(maxTicksLimit, maxTicks); - } - return maxTicks; - } - computeTickLimit() { - return Number.POSITIVE_INFINITY; - } - buildTicks() { - const opts = this.options; - const tickOpts = opts.ticks; - let maxTicks = this.getTickLimit(); - maxTicks = Math.max(2, maxTicks); - const numericGeneratorOptions = { - maxTicks, - bounds: opts.bounds, - min: opts.min, - max: opts.max, - precision: tickOpts.precision, - step: tickOpts.stepSize, - count: tickOpts.count, - maxDigits: this._maxDigits(), - horizontal: this.isHorizontal(), - minRotation: tickOpts.minRotation || 0, - includeBounds: tickOpts.includeBounds !== false - }; - const dataRange = this._range || this; - const ticks = generateTicks$1(numericGeneratorOptions, dataRange); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); - } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; + if (maxDefined && includeBounds && niceMax !== max) { + if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { + ticks[ticks.length - 1].value = max; + } else { + ticks.push({ + value: max + }); + } + } else if (!maxDefined || niceMax === max) { + ticks.push({ + value: niceMax + }); } return ticks; - } - configure() { - const ticks = this.ticks; - let start = this.min; - let end = this.max; - super.configure(); - if (this.options.offset && ticks.length) { - const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; - start -= offset; - end += offset; +} +function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) { + const rad = toRadians(minRotation); + const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; + const length = 0.75 * minSpacing * ('' + value).length; + return Math.min(minSpacing / ratio, length); +} +class LinearScaleBase extends Scale { + constructor(cfg){ + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._endValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { + return null; + } + return +raw; + } + handleTickRangeOptions() { + const { beginAtZero } = this.options; + const { minDefined , maxDefined } = this.getUserBounds(); + let { min , max } = this; + const setMin = (v)=>min = minDefined ? min : v; + const setMax = (v)=>max = maxDefined ? max : v; + if (beginAtZero) { + const minSign = sign(min); + const maxSign = sign(max); + if (minSign < 0 && maxSign < 0) { + setMax(0); + } else if (minSign > 0 && maxSign > 0) { + setMin(0); + } + } + if (min === max) { + let offset = max === 0 ? 1 : Math.abs(max * 0.05); + setMax(max + offset); + if (!beginAtZero) { + setMin(min - offset); + } + } + this.min = min; + this.max = max; + } + getTickLimit() { + const tickOpts = this.options.ticks; + let { maxTicksLimit , stepSize } = tickOpts; + let maxTicks; + if (stepSize) { + maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; + if (maxTicks > 1000) { + console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); + maxTicks = 1000; + } + } else { + maxTicks = this.computeTickLimit(); + maxTicksLimit = maxTicksLimit || 11; + } + if (maxTicksLimit) { + maxTicks = Math.min(maxTicksLimit, maxTicks); + } + return maxTicks; + } + computeTickLimit() { + return Number.POSITIVE_INFINITY; + } + buildTicks() { + const opts = this.options; + const tickOpts = opts.ticks; + let maxTicks = this.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + const numericGeneratorOptions = { + maxTicks, + bounds: opts.bounds, + min: opts.min, + max: opts.max, + precision: tickOpts.precision, + step: tickOpts.stepSize, + count: tickOpts.count, + maxDigits: this._maxDigits(), + horizontal: this.isHorizontal(), + minRotation: tickOpts.minRotation || 0, + includeBounds: tickOpts.includeBounds !== false + }; + const dataRange = this._range || this; + const ticks = generateTicks$1(numericGeneratorOptions, dataRange); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + configure() { + const ticks = this.ticks; + let start = this.min; + let end = this.max; + super.configure(); + if (this.options.offset && ticks.length) { + const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; + start -= offset; + end += offset; + } + this._startValue = start; + this._endValue = end; + this._valueRange = end - start; + } + getLabelForValue(value) { + return formatNumber(value, this.chart.options.locale, this.options.ticks.format); } - this._startValue = start; - this._endValue = end; - this._valueRange = end - start; - } - getLabelForValue(value) { - return formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } } class LinearScale extends LinearScaleBase { - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? min : 0; - this.max = isNumberFinite(max) ? max : 1; - this.handleTickRangeOptions(); - } - computeTickLimit() { - const horizontal = this.isHorizontal(); - const length = horizontal ? this.width : this.height; - const minRotation = toRadians(this.options.ticks.minRotation); - const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; - const tickFont = this._resolveTickFontOptions(0); - return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); - } - getPixelForValue(value) { - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; - } -} -LinearScale.id = 'linear'; -LinearScale.defaults = { - ticks: { - callback: Ticks.formatters.numeric - } -}; - -function isMajor(tickVal) { - const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); - return remain === 1; -} -function generateTicks(generationOptions, dataRange) { - const endExp = Math.floor(log10(dataRange.max)); - const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); - const ticks = []; - let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); - let exp = Math.floor(log10(tickVal)); - let significand = Math.floor(tickVal / Math.pow(10, exp)); - let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; - do { - ticks.push({value: tickVal, major: isMajor(tickVal)}); - ++significand; - if (significand === 10) { - significand = 1; - ++exp; - precision = exp >= 0 ? 1 : precision; + static id = 'linear'; + static defaults = { + ticks: { + callback: Ticks.formatters.numeric + } + }; + determineDataLimits() { + const { min , max } = this.getMinMax(true); + this.min = isNumberFinite(min) ? min : 0; + this.max = isNumberFinite(max) ? max : 1; + this.handleTickRangeOptions(); } - tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; - } while (exp < endExp || (exp === endExp && significand < endSignificand)); - const lastTick = finiteOrDefault(generationOptions.max, tickVal); - ticks.push({value: lastTick, major: isMajor(tickVal)}); - return ticks; + computeTickLimit() { + const horizontal = this.isHorizontal(); + const length = horizontal ? this.width : this.height; + const minRotation = toRadians(this.options.ticks.minRotation); + const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; + const tickFont = this._resolveTickFontOptions(0); + return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); + } + getPixelForValue(value) { + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; + } +} + +const log10Floor = (v)=>Math.floor(log10(v)); +const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m); +function isMajor(tickVal) { + const remain = tickVal / Math.pow(10, log10Floor(tickVal)); + return remain === 1; +} +function steps(min, max, rangeExp) { + const rangeStep = Math.pow(10, rangeExp); + const start = Math.floor(min / rangeStep); + const end = Math.ceil(max / rangeStep); + return end - start; +} +function startExp(min, max) { + const range = max - min; + let rangeExp = log10Floor(range); + while(steps(min, max, rangeExp) > 10){ + rangeExp++; + } + while(steps(min, max, rangeExp) < 10){ + rangeExp--; + } + return Math.min(rangeExp, log10Floor(min)); +} + function generateTicks(generationOptions, { min , max }) { + min = finiteOrDefault(generationOptions.min, min); + const ticks = []; + const minExp = log10Floor(min); + let exp = startExp(min, max); + let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; + const stepSize = Math.pow(10, exp); + const base = minExp > exp ? Math.pow(10, minExp) : 0; + const start = Math.round((min - base) * precision) / precision; + const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10; + let significand = Math.floor((start - offset) / Math.pow(10, exp)); + let value = finiteOrDefault(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision); + while(value < max){ + ticks.push({ + value, + major: isMajor(value), + significand + }); + if (significand >= 10) { + significand = significand < 15 ? 15 : 20; + } else { + significand++; + } + if (significand >= 20) { + exp++; + significand = 2; + precision = exp >= 0 ? 1 : precision; + } + value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision; + } + const lastTick = finiteOrDefault(generationOptions.max, value); + ticks.push({ + value: lastTick, + major: isMajor(lastTick), + significand + }); + return ticks; } class LogarithmicScale extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); - if (value === 0) { - this._zero = true; - return undefined; - } - return isNumberFinite(value) && value > 0 ? value : null; - } - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? Math.max(0, min) : null; - this.max = isNumberFinite(max) ? Math.max(0, max) : null; - if (this.options.beginAtZero) { - this._zero = true; - } - this.handleTickRangeOptions(); - } - handleTickRangeOptions() { - const {minDefined, maxDefined} = this.getUserBounds(); - let min = this.min; - let max = this.max; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m); - if (min === max) { - if (min <= 0) { - setMin(1); - setMax(10); - } else { - setMin(exp(min, -1)); - setMax(exp(max, +1)); - } - } - if (min <= 0) { - setMin(exp(max, -1)); - } - if (max <= 0) { - setMax(exp(min, +1)); - } - if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) { - setMin(exp(min, -1)); - } - this.min = min; - this.max = max; - } - buildTicks() { - const opts = this.options; - const generationOptions = { - min: this._userMin, - max: this._userMax + static id = 'logarithmic'; + static defaults = { + ticks: { + callback: Ticks.formatters.logarithmic, + major: { + enabled: true + } + } }; - const ticks = generateTicks(generationOptions, this); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); + constructor(cfg){ + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._valueRange = 0; } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; + parse(raw, index) { + const value = LinearScaleBase.prototype.parse.apply(this, [ + raw, + index + ]); + if (value === 0) { + this._zero = true; + return undefined; + } + return isNumberFinite(value) && value > 0 ? value : null; } - return ticks; - } - getLabelForValue(value) { - return value === undefined - ? '0' - : formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } - configure() { - const start = this.min; - super.configure(); - this._startValue = log10(start); - this._valueRange = log10(this.max) - log10(start); - } - getPixelForValue(value) { - if (value === undefined || value === 0) { - value = this.min; + determineDataLimits() { + const { min , max } = this.getMinMax(true); + this.min = isNumberFinite(min) ? Math.max(0, min) : null; + this.max = isNumberFinite(max) ? Math.max(0, max) : null; + if (this.options.beginAtZero) { + this._zero = true; + } + if (this._zero && this.min !== this._suggestedMin && !isNumberFinite(this._userMin)) { + this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0); + } + this.handleTickRangeOptions(); } - if (value === null || isNaN(value)) { - return NaN; + handleTickRangeOptions() { + const { minDefined , maxDefined } = this.getUserBounds(); + let min = this.min; + let max = this.max; + const setMin = (v)=>min = minDefined ? min : v; + const setMax = (v)=>max = maxDefined ? max : v; + if (min === max) { + if (min <= 0) { + setMin(1); + setMax(10); + } else { + setMin(changeExponent(min, -1)); + setMax(changeExponent(max, +1)); + } + } + if (min <= 0) { + setMin(changeExponent(max, -1)); + } + if (max <= 0) { + setMax(changeExponent(min, +1)); + } + this.min = min; + this.max = max; + } + buildTicks() { + const opts = this.options; + const generationOptions = { + min: this._userMin, + max: this._userMax + }; + const ticks = generateTicks(generationOptions, this); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + getLabelForValue(value) { + return value === undefined ? '0' : formatNumber(value, this.chart.options.locale, this.options.ticks.format); + } + configure() { + const start = this.min; + super.configure(); + this._startValue = log10(start); + this._valueRange = log10(this.max) - log10(start); + } + getPixelForValue(value) { + if (value === undefined || value === 0) { + value = this.min; + } + if (value === null || isNaN(value)) { + return NaN; + } + return this.getPixelForDecimal(value === this.min ? 0 : (log10(value) - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + const decimal = this.getDecimalForPixel(pixel); + return Math.pow(10, this._startValue + decimal * this._valueRange); } - return this.getPixelForDecimal(value === this.min - ? 0 - : (log10(value) - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - const decimal = this.getDecimalForPixel(pixel); - return Math.pow(10, this._startValue + decimal * this._valueRange); - } } -LogarithmicScale.id = 'logarithmic'; -LogarithmicScale.defaults = { - ticks: { - callback: Ticks.formatters.logarithmic, - major: { - enabled: true - } - } -}; function getTickBackdropHeight(opts) { - const tickOpts = opts.ticks; - if (tickOpts.display && opts.display) { - const padding = toPadding(tickOpts.backdropPadding); - return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; - } - return 0; + const tickOpts = opts.ticks; + if (tickOpts.display && opts.display) { + const padding = toPadding(tickOpts.backdropPadding); + return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; + } + return 0; } function measureLabelSize(ctx, font, label) { - label = isArray(label) ? label : [label]; - return { - w: _longestText(ctx, font.string, label), - h: label.length * font.lineHeight - }; + label = isArray(label) ? label : [ + label + ]; + return { + w: _longestText(ctx, font.string, label), + h: label.length * font.lineHeight + }; } function determineLimits(angle, pos, size, min, max) { - if (angle === min || angle === max) { + if (angle === min || angle === max) { + return { + start: pos - size / 2, + end: pos + size / 2 + }; + } else if (angle < min || angle > max) { + return { + start: pos - size, + end: pos + }; + } return { - start: pos - (size / 2), - end: pos + (size / 2) + start: pos, + end: pos + size }; - } else if (angle < min || angle > max) { - return { - start: pos - size, - end: pos - }; - } - return { - start: pos, - end: pos + size - }; } -function fitWithPointLabels(scale) { - const orig = { - l: scale.left + scale._padding.left, - r: scale.right - scale._padding.right, - t: scale.top + scale._padding.top, - b: scale.bottom - scale._padding.bottom - }; - const limits = Object.assign({}, orig); - const labelSizes = []; - const padding = []; - const valueCount = scale._pointLabels.length; - const pointLabelOpts = scale.options.pointLabels; - const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); - padding[i] = opts.padding; - const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); - const plFont = toFont(opts.font); - const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); - labelSizes[i] = textSize; - const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); - const angle = Math.round(toDegrees(angleRadians)); - const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); - const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); - updateLimits(limits, orig, angleRadians, hLimits, vLimits); - } - scale.setCenterPoint( - orig.l - limits.l, - limits.r - orig.r, - orig.t - limits.t, - limits.b - orig.b - ); - scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); + function fitWithPointLabels(scale) { + const orig = { + l: scale.left + scale._padding.left, + r: scale.right - scale._padding.right, + t: scale.top + scale._padding.top, + b: scale.bottom - scale._padding.bottom + }; + const limits = Object.assign({}, orig); + const labelSizes = []; + const padding = []; + const valueCount = scale._pointLabels.length; + const pointLabelOpts = scale.options.pointLabels; + const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; + for(let i = 0; i < valueCount; i++){ + const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); + padding[i] = opts.padding; + const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); + const plFont = toFont(opts.font); + const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); + labelSizes[i] = textSize; + const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); + const angle = Math.round(toDegrees(angleRadians)); + const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + updateLimits(limits, orig, angleRadians, hLimits, vLimits); + } + scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b); + scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); } function updateLimits(limits, orig, angle, hLimits, vLimits) { - const sin = Math.abs(Math.sin(angle)); - const cos = Math.abs(Math.cos(angle)); - let x = 0; - let y = 0; - if (hLimits.start < orig.l) { - x = (orig.l - hLimits.start) / sin; - limits.l = Math.min(limits.l, orig.l - x); - } else if (hLimits.end > orig.r) { - x = (hLimits.end - orig.r) / sin; - limits.r = Math.max(limits.r, orig.r + x); - } - if (vLimits.start < orig.t) { - y = (orig.t - vLimits.start) / cos; - limits.t = Math.min(limits.t, orig.t - y); - } else if (vLimits.end > orig.b) { - y = (vLimits.end - orig.b) / cos; - limits.b = Math.max(limits.b, orig.b + y); - } + const sin = Math.abs(Math.sin(angle)); + const cos = Math.abs(Math.cos(angle)); + let x = 0; + let y = 0; + if (hLimits.start < orig.l) { + x = (orig.l - hLimits.start) / sin; + limits.l = Math.min(limits.l, orig.l - x); + } else if (hLimits.end > orig.r) { + x = (hLimits.end - orig.r) / sin; + limits.r = Math.max(limits.r, orig.r + x); + } + if (vLimits.start < orig.t) { + y = (orig.t - vLimits.start) / cos; + limits.t = Math.min(limits.t, orig.t - y); + } else if (vLimits.end > orig.b) { + y = (vLimits.end - orig.b) / cos; + limits.b = Math.max(limits.b, orig.b + y); + } } -function buildPointLabelItems(scale, labelSizes, padding) { - const items = []; - const valueCount = scale._pointLabels.length; - const opts = scale.options; - const extra = getTickBackdropHeight(opts) / 2; - const outerDistance = scale.drawingArea; - const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle); +function createPointLabelItem(scale, index, itemOpts) { + const outerDistance = scale.drawingArea; + const { extra , additionalAngle , padding , size } = itemOpts; + const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle); const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); - const size = labelSizes[i]; const y = yForAngle(pointLabelPosition.y, size.h, angle); const textAlign = getTextAlignForAngle(angle); const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); - items.push({ - x: pointLabelPosition.x, - y, - textAlign, - left, - top: y, - right: left + size.w, - bottom: y + size.h - }); - } - return items; + return { + visible: true, + x: pointLabelPosition.x, + y, + textAlign, + left, + top: y, + right: left + size.w, + bottom: y + size.h + }; +} +function isNotOverlapped(item, area) { + if (!area) { + return true; + } + const { left , top , right , bottom } = item; + const apexesInArea = _isPointInArea({ + x: left, + y: top + }, area) || _isPointInArea({ + x: left, + y: bottom + }, area) || _isPointInArea({ + x: right, + y: top + }, area) || _isPointInArea({ + x: right, + y: bottom + }, area); + return !apexesInArea; +} +function buildPointLabelItems(scale, labelSizes, padding) { + const items = []; + const valueCount = scale._pointLabels.length; + const opts = scale.options; + const { centerPointLabels , display } = opts.pointLabels; + const itemOpts = { + extra: getTickBackdropHeight(opts) / 2, + additionalAngle: centerPointLabels ? PI / valueCount : 0 + }; + let area; + for(let i = 0; i < valueCount; i++){ + itemOpts.padding = padding[i]; + itemOpts.size = labelSizes[i]; + const item = createPointLabelItem(scale, i, itemOpts); + items.push(item); + if (display === 'auto') { + item.visible = isNotOverlapped(item, area); + if (item.visible) { + area = item; + } + } + } + return items; } function getTextAlignForAngle(angle) { - if (angle === 0 || angle === 180) { - return 'center'; - } else if (angle < 180) { - return 'left'; - } - return 'right'; + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + return 'right'; } function leftForTextAlign(x, w, align) { - if (align === 'right') { - x -= w; - } else if (align === 'center') { - x -= (w / 2); - } - return x; + if (align === 'right') { + x -= w; + } else if (align === 'center') { + x -= w / 2; + } + return x; } function yForAngle(y, h, angle) { - if (angle === 90 || angle === 270) { - y -= (h / 2); - } else if (angle > 270 || angle < 90) { - y -= h; - } - return y; + if (angle === 90 || angle === 270) { + y -= h / 2; + } else if (angle > 270 || angle < 90) { + y -= h; + } + return y; +} +function drawPointLabelBox(ctx, opts, item) { + const { left , top , right , bottom } = item; + const { backdropColor } = opts; + if (!isNullOrUndef(backdropColor)) { + const borderRadius = toTRBLCorners(opts.borderRadius); + const padding = toPadding(opts.backdropPadding); + ctx.fillStyle = backdropColor; + const backdropLeft = left - padding.left; + const backdropTop = top - padding.top; + const backdropWidth = right - left + padding.width; + const backdropHeight = bottom - top + padding.height; + if (Object.values(borderRadius).some((v)=>v !== 0)) { + ctx.beginPath(); + addRoundedRectPath(ctx, { + x: backdropLeft, + y: backdropTop, + w: backdropWidth, + h: backdropHeight, + radius: borderRadius + }); + ctx.fill(); + } else { + ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight); + } + } } function drawPointLabels(scale, labelCount) { - const {ctx, options: {pointLabels}} = scale; - for (let i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); - const plFont = toFont(optsAtIndex.font); - const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i]; - const {backdropColor} = optsAtIndex; - if (!isNullOrUndef(backdropColor)) { - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillStyle = backdropColor; - ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height); + const { ctx , options: { pointLabels } } = scale; + for(let i = labelCount - 1; i >= 0; i--){ + const item = scale._pointLabelItems[i]; + if (!item.visible) { + continue; + } + const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); + drawPointLabelBox(ctx, optsAtIndex, item); + const plFont = toFont(optsAtIndex.font); + const { x , y , textAlign } = item; + renderText(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, { + color: optsAtIndex.color, + textAlign: textAlign, + textBaseline: 'middle' + }); } - renderText( - ctx, - scale._pointLabels[i], - x, - y + (plFont.lineHeight / 2), - plFont, - { - color: optsAtIndex.color, - textAlign: textAlign, - textBaseline: 'middle' - } - ); - } } function pathRadiusLine(scale, radius, circular, labelCount) { - const {ctx} = scale; - if (circular) { - ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); - } else { - let pointPosition = scale.getPointPosition(0, radius); - ctx.moveTo(pointPosition.x, pointPosition.y); - for (let i = 1; i < labelCount; i++) { - pointPosition = scale.getPointPosition(i, radius); - ctx.lineTo(pointPosition.x, pointPosition.y); + const { ctx } = scale; + if (circular) { + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); + } else { + let pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + for(let i = 1; i < labelCount; i++){ + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } } - } } -function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { - const ctx = scale.ctx; - const circular = gridLineOpts.circular; - const {color, lineWidth} = gridLineOpts; - if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { - return; - } - ctx.save(); - ctx.strokeStyle = color; - ctx.lineWidth = lineWidth; - ctx.setLineDash(gridLineOpts.borderDash); - ctx.lineDashOffset = gridLineOpts.borderDashOffset; - ctx.beginPath(); - pathRadiusLine(scale, radius, circular, labelCount); - ctx.closePath(); - ctx.stroke(); - ctx.restore(); +function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) { + const ctx = scale.ctx; + const circular = gridLineOpts.circular; + const { color , lineWidth } = gridLineOpts; + if (!circular && !labelCount || !color || !lineWidth || radius < 0) { + return; + } + ctx.save(); + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.setLineDash(borderOpts.dash); + ctx.lineDashOffset = borderOpts.dashOffset; + ctx.beginPath(); + pathRadiusLine(scale, radius, circular, labelCount); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); } function createPointLabelContext(parent, index, label) { - return createContext(parent, { - label, - index, - type: 'pointLabel' - }); + return createContext(parent, { + label, + index, + type: 'pointLabel' + }); } class RadialLinearScale extends LinearScaleBase { - constructor(cfg) { - super(cfg); - this.xCenter = undefined; - this.yCenter = undefined; - this.drawingArea = undefined; - this._pointLabels = []; - this._pointLabelItems = []; - } - setDimensions() { - const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); - const w = this.width = this.maxWidth - padding.width; - const h = this.height = this.maxHeight - padding.height; - this.xCenter = Math.floor(this.left + w / 2 + padding.left); - this.yCenter = Math.floor(this.top + h / 2 + padding.top); - this.drawingArea = Math.floor(Math.min(w, h) / 2); - } - determineDataLimits() { - const {min, max} = this.getMinMax(false); - this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; - this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; - this.handleTickRangeOptions(); - } - computeTickLimit() { - return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); - } - generateTickLabels(ticks) { - LinearScaleBase.prototype.generateTickLabels.call(this, ticks); - this._pointLabels = this.getLabels() - .map((value, index) => { - const label = callback(this.options.pointLabels.callback, [value, index], this); - return label || label === 0 ? label : ''; - }) - .filter((v, i) => this.chart.getDataVisibility(i)); - } - fit() { - const opts = this.options; - if (opts.display && opts.pointLabels.display) { - fitWithPointLabels(this); - } else { - this.setCenterPoint(0, 0, 0, 0); - } - } - setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { - this.xCenter += Math.floor((leftMovement - rightMovement) / 2); - this.yCenter += Math.floor((topMovement - bottomMovement) / 2); - this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); - } - getIndexAngle(index) { - const angleMultiplier = TAU / (this._pointLabels.length || 1); - const startAngle = this.options.startAngle || 0; - return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); - } - getDistanceFromCenterForValue(value) { - if (isNullOrUndef(value)) { - return NaN; - } - const scalingFactor = this.drawingArea / (this.max - this.min); - if (this.options.reverse) { - return (this.max - value) * scalingFactor; - } - return (value - this.min) * scalingFactor; - } - getValueForDistanceFromCenter(distance) { - if (isNullOrUndef(distance)) { - return NaN; - } - const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); - return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; - } - getPointLabelContext(index) { - const pointLabels = this._pointLabels || []; - if (index >= 0 && index < pointLabels.length) { - const pointLabel = pointLabels[index]; - return createPointLabelContext(this.getContext(), index, pointLabel); - } - } - getPointPosition(index, distanceFromCenter, additionalAngle = 0) { - const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; - return { - x: Math.cos(angle) * distanceFromCenter + this.xCenter, - y: Math.sin(angle) * distanceFromCenter + this.yCenter, - angle - }; - } - getPointPositionForValue(index, value) { - return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); - } - getBasePosition(index) { - return this.getPointPositionForValue(index || 0, this.getBaseValue()); - } - getPointLabelPosition(index) { - const {left, top, right, bottom} = this._pointLabelItems[index]; - return { - left, - top, - right, - bottom, - }; - } - drawBackground() { - const {backgroundColor, grid: {circular}} = this.options; - if (backgroundColor) { - const ctx = this.ctx; - ctx.save(); - ctx.beginPath(); - pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); - ctx.closePath(); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - } - drawGrid() { - const ctx = this.ctx; - const opts = this.options; - const {angleLines, grid} = opts; - const labelCount = this._pointLabels.length; - let i, offset, position; - if (opts.pointLabels.display) { - drawPointLabels(this, labelCount); - } - if (grid.display) { - this.ticks.forEach((tick, index) => { - if (index !== 0) { - offset = this.getDistanceFromCenterForValue(tick.value); - const optsAtIndex = grid.setContext(this.getContext(index - 1)); - drawRadiusLine(this, optsAtIndex, offset, labelCount); + static id = 'radialLinear'; + static defaults = { + display: true, + animate: true, + position: 'chartArea', + angleLines: { + display: true, + lineWidth: 1, + borderDash: [], + borderDashOffset: 0.0 + }, + grid: { + circular: false + }, + startAngle: 0, + ticks: { + showLabelBackdrop: true, + callback: Ticks.formatters.numeric + }, + pointLabels: { + backdropColor: undefined, + backdropPadding: 2, + display: true, + font: { + size: 10 + }, + callback (label) { + return label; + }, + padding: 5, + centerPointLabels: false } - }); - } - if (angleLines.display) { - ctx.save(); - for (i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); - const {color, lineWidth} = optsAtIndex; - if (!lineWidth || !color) { - continue; + }; + static defaultRoutes = { + 'angleLines.color': 'borderColor', + 'pointLabels.color': 'color', + 'ticks.color': 'color' + }; + static descriptors = { + angleLines: { + _fallback: 'grid' } - ctx.lineWidth = lineWidth; - ctx.strokeStyle = color; - ctx.setLineDash(optsAtIndex.borderDash); - ctx.lineDashOffset = optsAtIndex.borderDashOffset; - offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); - position = this.getPointPosition(i, offset); - ctx.beginPath(); - ctx.moveTo(this.xCenter, this.yCenter); - ctx.lineTo(position.x, position.y); - ctx.stroke(); - } - ctx.restore(); + }; + constructor(cfg){ + super(cfg); + this.xCenter = undefined; + this.yCenter = undefined; + this.drawingArea = undefined; + this._pointLabels = []; + this._pointLabelItems = []; } - } - drawBorder() {} - drawLabels() { - const ctx = this.ctx; - const opts = this.options; - const tickOpts = opts.ticks; - if (!tickOpts.display) { - return; + setDimensions() { + const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); + const w = this.width = this.maxWidth - padding.width; + const h = this.height = this.maxHeight - padding.height; + this.xCenter = Math.floor(this.left + w / 2 + padding.left); + this.yCenter = Math.floor(this.top + h / 2 + padding.top); + this.drawingArea = Math.floor(Math.min(w, h) / 2); } - const startAngle = this.getIndexAngle(0); - let offset, width; - ctx.save(); - ctx.translate(this.xCenter, this.yCenter); - ctx.rotate(startAngle); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - this.ticks.forEach((tick, index) => { - if (index === 0 && !opts.reverse) { - return; - } - const optsAtIndex = tickOpts.setContext(this.getContext(index)); - const tickFont = toFont(optsAtIndex.font); - offset = this.getDistanceFromCenterForValue(this.ticks[index].value); - if (optsAtIndex.showLabelBackdrop) { - ctx.font = tickFont.string; - width = ctx.measureText(tick.label).width; - ctx.fillStyle = optsAtIndex.backdropColor; - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillRect( - -width / 2 - padding.left, - -offset - tickFont.size / 2 - padding.top, - width + padding.width, - tickFont.size + padding.height - ); - } - renderText(ctx, tick.label, 0, -offset, tickFont, { - color: optsAtIndex.color, - }); - }); - ctx.restore(); - } - drawTitle() {} + determineDataLimits() { + const { min , max } = this.getMinMax(false); + this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; + this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; + this.handleTickRangeOptions(); + } + computeTickLimit() { + return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); + } + generateTickLabels(ticks) { + LinearScaleBase.prototype.generateTickLabels.call(this, ticks); + this._pointLabels = this.getLabels().map((value, index)=>{ + const label = callback(this.options.pointLabels.callback, [ + value, + index + ], this); + return label || label === 0 ? label : ''; + }).filter((v, i)=>this.chart.getDataVisibility(i)); + } + fit() { + const opts = this.options; + if (opts.display && opts.pointLabels.display) { + fitWithPointLabels(this); + } else { + this.setCenterPoint(0, 0, 0, 0); + } + } + setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { + this.xCenter += Math.floor((leftMovement - rightMovement) / 2); + this.yCenter += Math.floor((topMovement - bottomMovement) / 2); + this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); + } + getIndexAngle(index) { + const angleMultiplier = TAU / (this._pointLabels.length || 1); + const startAngle = this.options.startAngle || 0; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); + } + getDistanceFromCenterForValue(value) { + if (isNullOrUndef(value)) { + return NaN; + } + const scalingFactor = this.drawingArea / (this.max - this.min); + if (this.options.reverse) { + return (this.max - value) * scalingFactor; + } + return (value - this.min) * scalingFactor; + } + getValueForDistanceFromCenter(distance) { + if (isNullOrUndef(distance)) { + return NaN; + } + const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); + return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; + } + getPointLabelContext(index) { + const pointLabels = this._pointLabels || []; + if (index >= 0 && index < pointLabels.length) { + const pointLabel = pointLabels[index]; + return createPointLabelContext(this.getContext(), index, pointLabel); + } + } + getPointPosition(index, distanceFromCenter, additionalAngle = 0) { + const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; + return { + x: Math.cos(angle) * distanceFromCenter + this.xCenter, + y: Math.sin(angle) * distanceFromCenter + this.yCenter, + angle + }; + } + getPointPositionForValue(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + } + getBasePosition(index) { + return this.getPointPositionForValue(index || 0, this.getBaseValue()); + } + getPointLabelPosition(index) { + const { left , top , right , bottom } = this._pointLabelItems[index]; + return { + left, + top, + right, + bottom + }; + } + drawBackground() { + const { backgroundColor , grid: { circular } } = this.options; + if (backgroundColor) { + const ctx = this.ctx; + ctx.save(); + ctx.beginPath(); + pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); + ctx.closePath(); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + } + drawGrid() { + const ctx = this.ctx; + const opts = this.options; + const { angleLines , grid , border } = opts; + const labelCount = this._pointLabels.length; + let i, offset, position; + if (opts.pointLabels.display) { + drawPointLabels(this, labelCount); + } + if (grid.display) { + this.ticks.forEach((tick, index)=>{ + if (index !== 0) { + offset = this.getDistanceFromCenterForValue(tick.value); + const context = this.getContext(index); + const optsAtIndex = grid.setContext(context); + const optsAtIndexBorder = border.setContext(context); + drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder); + } + }); + } + if (angleLines.display) { + ctx.save(); + for(i = labelCount - 1; i >= 0; i--){ + const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); + const { color , lineWidth } = optsAtIndex; + if (!lineWidth || !color) { + continue; + } + ctx.lineWidth = lineWidth; + ctx.strokeStyle = color; + ctx.setLineDash(optsAtIndex.borderDash); + ctx.lineDashOffset = optsAtIndex.borderDashOffset; + offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); + position = this.getPointPosition(i, offset); + ctx.beginPath(); + ctx.moveTo(this.xCenter, this.yCenter); + ctx.lineTo(position.x, position.y); + ctx.stroke(); + } + ctx.restore(); + } + } + drawBorder() {} + drawLabels() { + const ctx = this.ctx; + const opts = this.options; + const tickOpts = opts.ticks; + if (!tickOpts.display) { + return; + } + const startAngle = this.getIndexAngle(0); + let offset, width; + ctx.save(); + ctx.translate(this.xCenter, this.yCenter); + ctx.rotate(startAngle); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + this.ticks.forEach((tick, index)=>{ + if (index === 0 && !opts.reverse) { + return; + } + const optsAtIndex = tickOpts.setContext(this.getContext(index)); + const tickFont = toFont(optsAtIndex.font); + offset = this.getDistanceFromCenterForValue(this.ticks[index].value); + if (optsAtIndex.showLabelBackdrop) { + ctx.font = tickFont.string; + width = ctx.measureText(tick.label).width; + ctx.fillStyle = optsAtIndex.backdropColor; + const padding = toPadding(optsAtIndex.backdropPadding); + ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height); + } + renderText(ctx, tick.label, 0, -offset, tickFont, { + color: optsAtIndex.color + }); + }); + ctx.restore(); + } + drawTitle() {} } -RadialLinearScale.id = 'radialLinear'; -RadialLinearScale.defaults = { - display: true, - animate: true, - position: 'chartArea', - angleLines: { - display: true, - lineWidth: 1, - borderDash: [], - borderDashOffset: 0.0 - }, - grid: { - circular: false - }, - startAngle: 0, - ticks: { - showLabelBackdrop: true, - callback: Ticks.formatters.numeric - }, - pointLabels: { - backdropColor: undefined, - backdropPadding: 2, - display: true, - font: { - size: 10 - }, - callback(label) { - return label; - }, - padding: 5, - centerPointLabels: false - } -}; -RadialLinearScale.defaultRoutes = { - 'angleLines.color': 'borderColor', - 'pointLabels.color': 'color', - 'ticks.color': 'color' -}; -RadialLinearScale.descriptors = { - angleLines: { - _fallback: 'grid' - } -}; const INTERVALS = { - millisecond: {common: true, size: 1, steps: 1000}, - second: {common: true, size: 1000, steps: 60}, - minute: {common: true, size: 60000, steps: 60}, - hour: {common: true, size: 3600000, steps: 24}, - day: {common: true, size: 86400000, steps: 30}, - week: {common: false, size: 604800000, steps: 4}, - month: {common: true, size: 2.628e9, steps: 12}, - quarter: {common: false, size: 7.884e9, steps: 4}, - year: {common: true, size: 3.154e10} + millisecond: { + common: true, + size: 1, + steps: 1000 + }, + second: { + common: true, + size: 1000, + steps: 60 + }, + minute: { + common: true, + size: 60000, + steps: 60 + }, + hour: { + common: true, + size: 3600000, + steps: 24 + }, + day: { + common: true, + size: 86400000, + steps: 30 + }, + week: { + common: false, + size: 604800000, + steps: 4 + }, + month: { + common: true, + size: 2.628e9, + steps: 12 + }, + quarter: { + common: false, + size: 7.884e9, + steps: 4 + }, + year: { + common: true, + size: 3.154e10 + } }; -const UNITS = (Object.keys(INTERVALS)); -function sorter(a, b) { - return a - b; + const UNITS = /* #__PURE__ */ Object.keys(INTERVALS); + function sorter(a, b) { + return a - b; } -function parse(scale, input) { - if (isNullOrUndef(input)) { - return null; - } - const adapter = scale._adapter; - const {parser, round, isoWeekday} = scale._parseOpts; - let value = input; - if (typeof parser === 'function') { - value = parser(value); - } - if (!isNumberFinite(value)) { - value = typeof parser === 'string' - ? adapter.parse(value, parser) - : adapter.parse(value); - } - if (value === null) { - return null; - } - if (round) { - value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) - ? adapter.startOf(value, 'isoWeek', isoWeekday) - : adapter.startOf(value, round); - } - return +value; -} -function determineUnitForAutoTicks(minUnit, min, max, capacity) { - const ilen = UNITS.length; - for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { - const interval = INTERVALS[UNITS[i]]; - const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; - if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { - return UNITS[i]; + function parse(scale, input) { + if (isNullOrUndef(input)) { + return null; } - } - return UNITS[ilen - 1]; -} -function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { - for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { - const unit = UNITS[i]; - if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { - return unit; + const adapter = scale._adapter; + const { parser , round , isoWeekday } = scale._parseOpts; + let value = input; + if (typeof parser === 'function') { + value = parser(value); } - } - return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; -} -function determineMajorUnit(unit) { - for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { - if (INTERVALS[UNITS[i]].common) { - return UNITS[i]; + if (!isNumberFinite(value)) { + value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value); } - } -} -function addTick(ticks, time, timestamps) { - if (!timestamps) { - ticks[time] = true; - } else if (timestamps.length) { - const {lo, hi} = _lookup(timestamps, time); - const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; - ticks[timestamp] = true; - } -} -function setMajorTicks(scale, ticks, map, majorUnit) { - const adapter = scale._adapter; - const first = +adapter.startOf(ticks[0].value, majorUnit); - const last = ticks[ticks.length - 1].value; - let major, index; - for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { - index = map[major]; - if (index >= 0) { - ticks[index].major = true; + if (value === null) { + return null; } - } - return ticks; + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round); + } + return +value; } -function ticksFromTimestamps(scale, values, majorUnit) { - const ticks = []; - const map = {}; - const ilen = values.length; - let i, value; - for (i = 0; i < ilen; ++i) { - value = values[i]; - map[value] = i; - ticks.push({ - value, - major: false - }); - } - return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); + function determineUnitForAutoTicks(minUnit, min, max, capacity) { + const ilen = UNITS.length; + for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){ + const interval = INTERVALS[UNITS[i]]; + const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} + function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){ + const unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} + function determineMajorUnit(unit) { + for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){ + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} + function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + const { lo , hi } = _lookup(timestamps, time); + const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} + function setMajorTicks(scale, ticks, map, majorUnit) { + const adapter = scale._adapter; + const first = +adapter.startOf(ticks[0].value, majorUnit); + const last = ticks[ticks.length - 1].value; + let major, index; + for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){ + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} + function ticksFromTimestamps(scale, values, majorUnit) { + const ticks = []; + const map = {}; + const ilen = values.length; + let i, value; + for(i = 0; i < ilen; ++i){ + value = values[i]; + map[value] = i; + ticks.push({ + value, + major: false + }); + } + return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit); } class TimeScale extends Scale { - constructor(props) { - super(props); - this._cache = { - data: [], - labels: [], - all: [] + static id = 'time'; + static defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + callback: false, + major: { + enabled: false + } + } }; - this._unit = 'day'; - this._majorUnit = undefined; - this._offsets = {}; - this._normalized = false; - this._parseOpts = undefined; - } - init(scaleOpts, opts) { - const time = scaleOpts.time || (scaleOpts.time = {}); - const adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date); - mergeIf(time.displayFormats, adapter.formats()); - this._parseOpts = { - parser: time.parser, - round: time.round, - isoWeekday: time.isoWeekday - }; - super.init(scaleOpts); - this._normalized = opts.normalized; - } - parse(raw, index) { - if (raw === undefined) { - return null; + constructor(props){ + super(props); + this._cache = { + data: [], + labels: [], + all: [] + }; + this._unit = 'day'; + this._majorUnit = undefined; + this._offsets = {}; + this._normalized = false; + this._parseOpts = undefined; } - return parse(this, raw); - } - beforeLayout() { - super.beforeLayout(); - this._cache = { - data: [], - labels: [], - all: [] - }; - } - determineDataLimits() { - const options = this.options; - const adapter = this._adapter; - const unit = options.time.unit || 'day'; - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - function _applyBounds(bounds) { - if (!minDefined && !isNaN(bounds.min)) { - min = Math.min(min, bounds.min); - } - if (!maxDefined && !isNaN(bounds.max)) { - max = Math.max(max, bounds.max); - } + init(scaleOpts, opts = {}) { + const time = scaleOpts.time || (scaleOpts.time = {}); + const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); + adapter.init(opts); + mergeIf(time.displayFormats, adapter.formats()); + this._parseOpts = { + parser: time.parser, + round: time.round, + isoWeekday: time.isoWeekday + }; + super.init(scaleOpts); + this._normalized = opts.normalized; } - if (!minDefined || !maxDefined) { - _applyBounds(this._getLabelBounds()); - if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { - _applyBounds(this.getMinMax(false)); - } + parse(raw, index) { + if (raw === undefined) { + return null; + } + return parse(this, raw); } - min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); - max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; - this.min = Math.min(min, max - 1); - this.max = Math.max(min + 1, max); - } - _getLabelBounds() { - const arr = this.getLabelTimestamps(); - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - if (arr.length) { - min = arr[0]; - max = arr[arr.length - 1]; + beforeLayout() { + super.beforeLayout(); + this._cache = { + data: [], + labels: [], + all: [] + }; } - return {min, max}; - } - buildTicks() { - const options = this.options; - const timeOpts = options.time; - const tickOpts = options.ticks; - const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); - if (options.bounds === 'ticks' && timestamps.length) { - this.min = this._userMin || timestamps[0]; - this.max = this._userMax || timestamps[timestamps.length - 1]; + determineDataLimits() { + const options = this.options; + const adapter = this._adapter; + const unit = options.time.unit || 'day'; + let { min , max , minDefined , maxDefined } = this.getUserBounds(); + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(this._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(this.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + this.min = Math.min(min, max - 1); + this.max = Math.max(min + 1, max); } - const min = this.min; - const max = this.max; - const ticks = _filterBetween(timestamps, min, max); - this._unit = timeOpts.unit || (tickOpts.autoSkip - ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) - : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); - this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined - : determineMajorUnit(this._unit); - this.initOffsets(timestamps); - if (options.reverse) { - ticks.reverse(); + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return { + min, + max + }; } - return ticksFromTimestamps(this, ticks, this._majorUnit); - } - initOffsets(timestamps) { - let start = 0; - let end = 0; - let first, last; - if (this.options.offset && timestamps.length) { - first = this.getDecimalForValue(timestamps[0]); - if (timestamps.length === 1) { - start = 1 - first; - } else { - start = (this.getDecimalForValue(timestamps[1]) - first) / 2; - } - last = this.getDecimalForValue(timestamps[timestamps.length - 1]); - if (timestamps.length === 1) { - end = last; - } else { - end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; - } + buildTicks() { + const options = this.options; + const timeOpts = options.time; + const tickOpts = options.ticks; + const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + this.min = this._userMin || timestamps[0]; + this.max = this._userMax || timestamps[timestamps.length - 1]; + } + const min = this.min; + const max = this.max; + const ticks = _filterBetween(timestamps, min, max); + this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); + this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit); + this.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(this, ticks, this._majorUnit); } - const limit = timestamps.length < 3 ? 0.5 : 0.25; - start = _limitValue(start, 0, limit); - end = _limitValue(end, 0, limit); - this._offsets = {start, end, factor: 1 / (start + 1 + end)}; - } - _generate() { - const adapter = this._adapter; - const min = this.min; - const max = this.max; - const options = this.options; - const timeOpts = options.time; - const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); - const stepSize = valueOrDefault(timeOpts.stepSize, 1); - const weekday = minor === 'week' ? timeOpts.isoWeekday : false; - const hasWeekday = isNumber(weekday) || weekday === true; - const ticks = {}; - let first = min; - let time, count; - if (hasWeekday) { - first = +adapter.startOf(first, 'isoWeek', weekday); + afterAutoSkip() { + if (this.options.offsetAfterAutoskip) { + this.initOffsets(this.ticks.map((tick)=>+tick.value)); + } } - first = +adapter.startOf(first, hasWeekday ? 'day' : minor); - if (adapter.diff(max, min, minor) > 100000 * stepSize) { - throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + initOffsets(timestamps = []) { + let start = 0; + let end = 0; + let first, last; + if (this.options.offset && timestamps.length) { + first = this.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (this.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = this.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + const limit = timestamps.length < 3 ? 0.5 : 0.25; + start = _limitValue(start, 0, limit); + end = _limitValue(end, 0, limit); + this._offsets = { + start, + end, + factor: 1 / (start + 1 + end) + }; } - const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); - for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) { - addTick(ticks, time, timestamps); + _generate() { + const adapter = this._adapter; + const min = this.min; + const max = this.max; + const options = this.options; + const timeOpts = options.time; + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); + const stepSize = valueOrDefault(options.ticks.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const hasWeekday = isNumber(weekday) || weekday === true; + const ticks = {}; + let first = min; + let time, count; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); + for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){ + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks' || count === 1) { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort((a, b)=>a - b).map((x)=>+x); } - if (time === max || options.bounds === 'ticks' || count === 1) { - addTick(ticks, time, timestamps); + getLabelForValue(value) { + const adapter = this._adapter; + const timeOpts = this.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); } - return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); - } - getLabelForValue(value) { - const adapter = this._adapter; - const timeOpts = this.options.time; - if (timeOpts.tooltipFormat) { - return adapter.format(value, timeOpts.tooltipFormat); + format(value, format) { + const options = this.options; + const formats = options.time.displayFormats; + const unit = this._unit; + const fmt = format || formats[unit]; + return this._adapter.format(value, fmt); } - return adapter.format(value, timeOpts.displayFormats.datetime); - } - _tickFormatFunction(time, index, ticks, format) { - const options = this.options; - const formats = options.time.displayFormats; - const unit = this._unit; - const majorUnit = this._majorUnit; - const minorFormat = unit && formats[unit]; - const majorFormat = majorUnit && formats[majorUnit]; - const tick = ticks[index]; - const major = majorUnit && majorFormat && tick && tick.major; - const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat)); - const formatter = options.ticks.callback; - return formatter ? callback(formatter, [label, index, ticks], this) : label; - } - generateTickLabels(ticks) { - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - tick.label = this._tickFormatFunction(tick.value, i, ticks); + _tickFormatFunction(time, index, ticks, format) { + const options = this.options; + const formatter = options.ticks.callback; + if (formatter) { + return callback(formatter, [ + time, + index, + ticks + ], this); + } + const formats = options.time.displayFormats; + const unit = this._unit; + const majorUnit = this._majorUnit; + const minorFormat = unit && formats[unit]; + const majorFormat = majorUnit && formats[majorUnit]; + const tick = ticks[index]; + const major = majorUnit && majorFormat && tick && tick.major; + return this._adapter.format(time, format || (major ? majorFormat : minorFormat)); } - } - getDecimalForValue(value) { - return value === null ? NaN : (value - this.min) / (this.max - this.min); - } - getPixelForValue(value) { - const offsets = this._offsets; - const pos = this.getDecimalForValue(value); - return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return this.min + pos * (this.max - this.min); - } - _getLabelSize(label) { - const ticksOpts = this.options.ticks; - const tickLabelWidth = this.ctx.measureText(label).width; - const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); - const cosRotation = Math.cos(angle); - const sinRotation = Math.sin(angle); - const tickFontSize = this._resolveTickFontOptions(0).size; - return { - w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), - h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) - }; - } - _getLabelCapacity(exampleTime) { - const timeOpts = this.options.time; - const displayFormats = timeOpts.displayFormats; - const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; - const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format); - const size = this._getLabelSize(exampleLabel); - const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; - return capacity > 0 ? capacity : 1; - } - getDataTimestamps() { - let timestamps = this._cache.data || []; - let i, ilen; - if (timestamps.length) { - return timestamps; + generateTickLabels(ticks) { + let i, ilen, tick; + for(i = 0, ilen = ticks.length; i < ilen; ++i){ + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } } - const metas = this.getMatchingVisibleMetas(); - if (this._normalized && metas.length) { - return (this._cache.data = metas[0].controller.getAllParsedValues(this)); + getDecimalForValue(value) { + return value === null ? NaN : (value - this.min) / (this.max - this.min); } - for (i = 0, ilen = metas.length; i < ilen; ++i) { - timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); + getPixelForValue(value) { + const offsets = this._offsets; + const pos = this.getDecimalForValue(value); + return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); } - return (this._cache.data = this.normalize(timestamps)); - } - getLabelTimestamps() { - const timestamps = this._cache.labels || []; - let i, ilen; - if (timestamps.length) { - return timestamps; + getValueForPixel(pixel) { + const offsets = this._offsets; + const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return this.min + pos * (this.max - this.min); } - const labels = this.getLabels(); - for (i = 0, ilen = labels.length; i < ilen; ++i) { - timestamps.push(parse(this, labels[i])); + _getLabelSize(label) { + const ticksOpts = this.options.ticks; + const tickLabelWidth = this.ctx.measureText(label).width; + const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + const cosRotation = Math.cos(angle); + const sinRotation = Math.sin(angle); + const tickFontSize = this._resolveTickFontOptions(0).size; + return { + w: tickLabelWidth * cosRotation + tickFontSize * sinRotation, + h: tickLabelWidth * sinRotation + tickFontSize * cosRotation + }; + } + _getLabelCapacity(exampleTime) { + const timeOpts = this.options.time; + const displayFormats = timeOpts.displayFormats; + const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [ + exampleTime + ], this._majorUnit), format); + const size = this._getLabelSize(exampleLabel); + const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + getDataTimestamps() { + let timestamps = this._cache.data || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const metas = this.getMatchingVisibleMetas(); + if (this._normalized && metas.length) { + return this._cache.data = metas[0].controller.getAllParsedValues(this); + } + for(i = 0, ilen = metas.length; i < ilen; ++i){ + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); + } + return this._cache.data = this.normalize(timestamps); + } + getLabelTimestamps() { + const timestamps = this._cache.labels || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const labels = this.getLabels(); + for(i = 0, ilen = labels.length; i < ilen; ++i){ + timestamps.push(parse(this, labels[i])); + } + return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps); + } + normalize(values) { + return _arrayUnique(values.sort(sorter)); } - return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps)); - } - normalize(values) { - return _arrayUnique(values.sort(sorter)); - } } -TimeScale.id = 'time'; -TimeScale.defaults = { - bounds: 'data', - adapters: {}, - time: { - parser: false, - unit: false, - round: false, - isoWeekday: false, - minUnit: 'millisecond', - displayFormats: {} - }, - ticks: { - source: 'auto', - major: { - enabled: false - } - } -}; function interpolate(table, val, reverse) { - let lo = 0; - let hi = table.length - 1; - let prevSource, nextSource, prevTarget, nextTarget; - if (reverse) { - if (val >= table[lo].pos && val <= table[hi].pos) { - ({lo, hi} = _lookupByKey(table, 'pos', val)); + let lo = 0; + let hi = table.length - 1; + let prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + if (val >= table[lo].pos && val <= table[hi].pos) { + ({ lo , hi } = _lookupByKey(table, 'pos', val)); + } + ({ pos: prevSource , time: prevTarget } = table[lo]); + ({ pos: nextSource , time: nextTarget } = table[hi]); + } else { + if (val >= table[lo].time && val <= table[hi].time) { + ({ lo , hi } = _lookupByKey(table, 'time', val)); + } + ({ time: prevSource , pos: prevTarget } = table[lo]); + ({ time: nextSource , pos: nextTarget } = table[hi]); } - ({pos: prevSource, time: prevTarget} = table[lo]); - ({pos: nextSource, time: nextTarget} = table[hi]); - } else { - if (val >= table[lo].time && val <= table[hi].time) { - ({lo, hi} = _lookupByKey(table, 'time', val)); - } - ({time: prevSource, pos: prevTarget} = table[lo]); - ({time: nextSource, pos: nextTarget} = table[hi]); - } - const span = nextSource - prevSource; - return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; + const span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; } class TimeSeriesScale extends TimeScale { - constructor(props) { - super(props); - this._table = []; - this._minPos = undefined; - this._tableRange = undefined; - } - initOffsets() { - const timestamps = this._getTimestampsForTable(); - const table = this._table = this.buildLookupTable(timestamps); - this._minPos = interpolate(table, this.min); - this._tableRange = interpolate(table, this.max) - this._minPos; - super.initOffsets(timestamps); - } - buildLookupTable(timestamps) { - const {min, max} = this; - const items = []; - const table = []; - let i, ilen, prev, curr, next; - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - curr = timestamps[i]; - if (curr >= min && curr <= max) { - items.push(curr); - } + static id = 'timeseries'; + static defaults = TimeScale.defaults; + constructor(props){ + super(props); + this._table = []; + this._minPos = undefined; + this._tableRange = undefined; } - if (items.length < 2) { - return [ - {time: min, pos: 0}, - {time: max, pos: 1} - ]; + initOffsets() { + const timestamps = this._getTimestampsForTable(); + const table = this._table = this.buildLookupTable(timestamps); + this._minPos = interpolate(table, this.min); + this._tableRange = interpolate(table, this.max) - this._minPos; + super.initOffsets(timestamps); } - for (i = 0, ilen = items.length; i < ilen; ++i) { - next = items[i + 1]; - prev = items[i - 1]; - curr = items[i]; - if (Math.round((next + prev) / 2) !== curr) { - table.push({time: curr, pos: i / (ilen - 1)}); - } + buildLookupTable(timestamps) { + const { min , max } = this; + const items = []; + const table = []; + let i, ilen, prev, curr, next; + for(i = 0, ilen = timestamps.length; i < ilen; ++i){ + curr = timestamps[i]; + if (curr >= min && curr <= max) { + items.push(curr); + } + } + if (items.length < 2) { + return [ + { + time: min, + pos: 0 + }, + { + time: max, + pos: 1 + } + ]; + } + for(i = 0, ilen = items.length; i < ilen; ++i){ + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + if (Math.round((next + prev) / 2) !== curr) { + table.push({ + time: curr, + pos: i / (ilen - 1) + }); + } + } + return table; } - return table; - } - _getTimestampsForTable() { - let timestamps = this._cache.all || []; - if (timestamps.length) { - return timestamps; + _getTimestampsForTable() { + let timestamps = this._cache.all || []; + if (timestamps.length) { + return timestamps; + } + const data = this.getDataTimestamps(); + const label = this.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = this.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = this._cache.all = timestamps; + return timestamps; } - const data = this.getDataTimestamps(); - const label = this.getLabelTimestamps(); - if (data.length && label.length) { - timestamps = this.normalize(data.concat(label)); - } else { - timestamps = data.length ? data : label; + getDecimalForValue(value) { + return (interpolate(this._table, value) - this._minPos) / this._tableRange; + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(this._table, decimal * this._tableRange + this._minPos, true); } - timestamps = this._cache.all = timestamps; - return timestamps; - } - getDecimalForValue(value) { - return (interpolate(this._table, value) - this._minPos) / this._tableRange; - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return interpolate(this._table, decimal * this._tableRange + this._minPos, true); - } } -TimeSeriesScale.id = 'timeseries'; -TimeSeriesScale.defaults = TimeScale.defaults; var scales = /*#__PURE__*/Object.freeze({ __proto__: null, @@ -13224,27 +11413,12 @@ TimeScale: TimeScale, TimeSeriesScale: TimeSeriesScale }); -Chart.register(controllers, scales, elements, plugins); -Chart.helpers = {...helpers}; -Chart._adapters = _adapters; -Chart.Animation = Animation; -Chart.Animations = Animations; -Chart.animator = animator; -Chart.controllers = registry.controllers.items; -Chart.DatasetController = DatasetController; -Chart.Element = Element; -Chart.elements = elements; -Chart.Interaction = Interaction; -Chart.layouts = layouts; -Chart.platforms = platforms; -Chart.Scale = Scale; -Chart.Ticks = Ticks; -Object.assign(Chart, controllers, scales, elements, plugins, platforms); -Chart.Chart = Chart; -if (typeof window !== 'undefined') { - window.Chart = Chart; -} +const registerables = [ + controllers, + elements, + plugins, + scales +]; -return Chart; - -})); +export { Animation, Animations, ArcElement, BarController, BarElement, BasePlatform, BasicPlatform, BubbleController, CategoryScale, Chart, plugin_colors as Colors, DatasetController, plugin_decimation as Decimation, DomPlatform, DoughnutController, Element, index as Filler, Interaction, plugin_legend as Legend, LineController, LineElement, LinearScale, LogarithmicScale, PieController, PointElement, PolarAreaController, RadarController, RadialLinearScale, Scale, ScatterController, plugin_subtitle as SubTitle, Ticks, TimeScale, TimeSeriesScale, plugin_title as Title, plugin_tooltip as Tooltip, adapters as _adapters, _detectPlatform, animator, controllers, defaults, elements, layouts, plugins, registerables, registry, scales }; +//# sourceMappingURL=chart.js.map diff --git a/EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/chart.min.js b/EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/chart.min.js index 07b5445..71bc22e 100644 --- a/EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/chart.min.js +++ b/EgwCoreLib.BlazorTest/wwwroot/lib/Chart.js/chart.min.js @@ -1,13 +1 @@ -/*! - * Chart.js v3.7.0 - * https://www.chartjs.org - * (c) 2021 Chart.js Contributors - * Released under the MIT License - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";const t="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function e(e,i,s){const n=s||(t=>Array.prototype.slice.call(t));let o=!1,a=[];return function(...s){a=n(s),o||(o=!0,t.call(window,(()=>{o=!1,e.apply(i,a)})))}}function i(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const s=t=>"start"===t?"left":"end"===t?"right":"center",n=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,o=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;var a=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=t.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}; -/*! - * @kurkle/color v0.1.9 - * https://github.com/kurkle/color#readme - * (c) 2020 Jukka Kurkela - * Released under the MIT License - */const r={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},l="0123456789ABCDEF",h=t=>l[15&t],c=t=>l[(240&t)>>4]+l[15&t],d=t=>(240&t)>>4==(15&t);function u(t){var e=function(t){return d(t.r)&&d(t.g)&&d(t.b)&&d(t.a)}(t)?h:c;return t?"#"+e(t.r)+e(t.g)+e(t.b)+(t.a<255?e(t.a):""):t}function f(t){return t+.5|0}const g=(t,e,i)=>Math.max(Math.min(t,i),e);function p(t){return g(f(2.55*t),0,255)}function m(t){return g(f(255*t),0,255)}function x(t){return g(f(t/2.55)/100,0,1)}function b(t){return g(f(100*t),0,100)}const _=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const y=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function v(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function w(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function M(t,e,i){const s=v(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function k(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=n===e?(i-s)/h+(i>16&255,o>>8&255,255&o]}return t}(),T.transparent=[0,0,0,0]);const e=T[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}function R(t,e,i){if(t){let s=k(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=P(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function E(t,e){return t?Object.assign(e||{},t):t}function I(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=m(t[3]))):(e=E(t,{r:0,g:0,b:0,a:1})).a=m(e.a),e}function z(t){return"r"===t.charAt(0)?function(t){const e=_.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=255&(e[8]?p(t):255*t)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?p(i):i),s=255&(e[4]?p(s):s),n=255&(e[6]?p(n):n),{r:i,g:s,b:n,a:o}}}(t):C(t)}class F{constructor(t){if(t instanceof F)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=I(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*r[s[1]],g:255&17*r[s[2]],b:255&17*r[s[3]],a:5===o?17*r[s[4]]:255}:7!==o&&9!==o||(n={r:r[s[1]]<<4|r[s[2]],g:r[s[3]]<<4|r[s[4]],b:r[s[5]]<<4|r[s[6]],a:9===o?r[s[7]]<<4|r[s[8]]:255})),i=n||L(t)||z(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=E(this._rgb);return t&&(t.a=x(t.a)),t}set rgb(t){this._rgb=I(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${x(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):this._rgb;var t}hexString(){return this._valid?u(this._rgb):this._rgb}hslString(){return this._valid?function(t){if(!t)return;const e=k(t),i=e[0],s=b(e[1]),n=b(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${x(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):this._rgb}mix(t,e){const i=this;if(t){const s=i.rgb,n=t.rgb;let o;const a=e===o?.5:e,r=2*a-1,l=s.a-n.a,h=((r*l==-1?r:(r+l)/(1+r*l))+1)/2;o=1-h,s.r=255&h*s.r+o*n.r+.5,s.g=255&h*s.g+o*n.g+.5,s.b=255&h*s.b+o*n.b+.5,s.a=a*s.a+(1-a)*n.a,i.rgb=s}return i}clone(){return new F(this.rgb)}alpha(t){return this._rgb.a=m(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=f(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return R(this._rgb,2,t),this}darken(t){return R(this._rgb,2,-t),this}saturate(t){return R(this._rgb,1,t),this}desaturate(t){return R(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=k(t);i[0]=D(i[0]+e),i=P(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function B(t){return new F(t)}const V=t=>t instanceof CanvasGradient||t instanceof CanvasPattern;function W(t){return V(t)?t:B(t)}function N(t){return V(t)?t:B(t).saturate(.5).darken(.1).hexString()}function H(){}const j=function(){let t=0;return function(){return t++}}();function $(t){return null==t}function Y(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)}function U(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}const X=t=>("number"==typeof t||t instanceof Number)&&isFinite(+t);function q(t,e){return X(t)?t:e}function K(t,e){return void 0===t?e:t}const G=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:t/e,Z=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function J(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function Q(t,e,i,s){let n,o,a;if(Y(t))if(o=t.length,s)for(n=o-1;n>=0;n--)e.call(i,t[n],n);else for(n=0;ni;)t=t[e.substr(i,s-i)],i=s+1,s=rt(e,i);return t}function ht(t){return t.charAt(0).toUpperCase()+t.slice(1)}const ct=t=>void 0!==t,dt=t=>"function"==typeof t,ut=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function ft(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const gt=Object.create(null),pt=Object.create(null);function mt(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>N(e.backgroundColor),this.hoverBorderColor=(t,e)=>N(e.borderColor),this.hoverColor=(t,e)=>N(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t)}set(t,e){return xt(this,t,e)}get(t){return mt(this,t)}describe(t,e){return xt(pt,t,e)}override(t,e){return xt(gt,t,e)}route(t,e,i,s){const n=mt(this,t),o=mt(this,i),a="_"+e;Object.defineProperties(n,{[a]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[a],e=o[s];return U(t)?Object.assign({},e,t):K(t,e)},set(t){this[a]=t}}})}}({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}});const _t=Math.PI,yt=2*_t,vt=yt+_t,wt=Number.POSITIVE_INFINITY,Mt=_t/180,kt=_t/2,St=_t/4,Pt=2*_t/3,Dt=Math.log10,Ct=Math.sign;function Ot(t){const e=Math.round(t);t=Lt(t,e,t/1e3)?e:t;const i=Math.pow(10,Math.floor(Dt(t))),s=t/i;return(s<=1?1:s<=2?2:s<=5?5:10)*i}function At(t){const e=[],i=Math.sqrt(t);let s;for(s=1;st-e)).pop(),e}function Tt(t){return!isNaN(parseFloat(t))&&isFinite(t)}function Lt(t,e,i){return Math.abs(t-e)=t}function Et(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function Ut(t){return!t||$(t.size)||$(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Xt(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function qt(t,e,i,s){let n=(s=s||{}).data=s.data||{},o=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(n=s.data={},o=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let a=0;const r=i.length;let l,h,c,d,u;for(l=0;li.length){for(l=0;l0&&t.stroke()}}function Jt(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==o.strokeColor;let l,h;for(t.save(),t.font=n.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]);$(e.rotation)||t.rotate(e.rotation);e.color&&(t.fillStyle=e.color);e.textAlign&&(t.textAlign=e.textAlign);e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,o),l=0;lt[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const re=(t,e,i)=>ae(t,i,(s=>t[s][e]ae(t,i,(s=>t[s][e]>=i));function he(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+ht(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function ue(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ce.forEach((e=>{delete t[e]})),delete t._chartjs)}function fe(t){const e=new Set;let i,s;for(i=0,s=t.length;iwindow.getComputedStyle(t,null);function be(t,e){return xe(t).getPropertyValue(e)}const _e=["top","right","bottom","left"];function ye(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=_e[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}function ve(t,e){const{canvas:i,currentDevicePixelRatio:s}=e,n=xe(i),o="border-box"===n.boxSizing,a=ye(n,"padding"),r=ye(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.native||t,s=i.touches,n=s&&s.length?s[0]:i,{offsetX:o,offsetY:a}=n;let r,l,h=!1;if(((t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot))(o,a,i.target))r=o,l=a;else{const t=e.getBoundingClientRect();r=n.clientX-t.left,l=n.clientY-t.top,h=!0}return{x:r,y:l,box:h}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const we=t=>Math.round(10*t)/10;function Me(t,e,i,s){const n=xe(t),o=ye(n,"margin"),a=me(n.maxWidth,t,"clientWidth")||wt,r=me(n.maxHeight,t,"clientHeight")||wt,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=pe(t);if(o){const t=o.getBoundingClientRect(),a=xe(o),r=ye(a,"border","width"),l=ye(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=me(a.maxWidth,o,"clientWidth"),n=me(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||wt,maxHeight:n||wt}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=ye(n,"border","width"),e=ye(n,"padding");h-=e.width+t.width,c-=e.height+t.height}return h=Math.max(0,h-o.width),c=Math.max(0,s?Math.floor(h/s):c-o.height),h=we(Math.min(h,a,l.maxWidth)),c=we(Math.min(c,r,l.maxHeight)),h&&!c&&(c=we(h/2)),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=n/s,t.width=o/s;const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function Pe(t,e){const i=be(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t,e){return"native"in t?{x:t.x,y:t.y}:ve(t,e)}function Ce(t,e,i,s){const{controller:n,data:o,_sorted:a}=t,r=n._cachedMeta.iScale;if(r&&e===r.axis&&"r"!==e&&a&&o.length){const t=r._reversePixels?le:re;if(!s)return t(o,e,i);if(n._sharedOptions){const s=o[0],n="function"==typeof s.getRange&&s.getRange(e);if(n){const s=t(o,e,i-n),a=t(o,e,i+n);return{lo:s.lo,hi:a.hi}}}}return{lo:0,hi:o.length-1}}function Oe(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t{t[r](n[a],s)&&o.push({element:t,datasetIndex:e,index:i}),t.inRange(n.x,n.y,s)&&(l=!0)})),i.intersect&&!l?[]:o}var Ee={modes:{index(t,e,i,s){const n=De(e,t),o=i.axis||"x",a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s),r=[];return a.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=a[0].index,i=t.data[e];i&&!i.skip&&r.push({element:i,datasetIndex:t.index,index:e})})),r):[]},dataset(t,e,i,s){const n=De(e,t),o=i.axis||"xy";let a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s);if(a.length>0){const e=a[0].datasetIndex,i=t.getDatasetMeta(e).data;a=[];for(let t=0;tAe(t,De(e,t),i.axis||"xy",s),nearest:(t,e,i,s)=>Le(t,De(e,t),i.axis||"xy",i.intersect,s),x:(t,e,i,s)=>Re(t,e,{axis:"x",intersect:i.intersect},s),y:(t,e,i,s)=>Re(t,e,{axis:"y",intersect:i.intersect},s)}};const Ie=new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/),ze=new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/);function Fe(t,e){const i=(""+t).match(Ie);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}function Be(t,e){const i={},s=U(e),n=s?Object.keys(e):e,o=U(t)?s?i=>K(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=+o(t)||0;return i}function Ve(t){return Be(t,{top:"y",right:"x",bottom:"y",left:"x"})}function We(t){return Be(t,["topLeft","topRight","bottomLeft","bottomRight"])}function Ne(t){const e=Ve(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function He(t,e){t=t||{},e=e||bt.font;let i=K(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=K(t.style,e.style);s&&!(""+s).match(ze)&&(console.warn('Invalid font style specified: "'+s+'"'),s="");const n={family:K(t.family,e.family),lineHeight:Fe(K(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:K(t.weight,e.weight),string:""};return n.string=Ut(n),n}function je(t,e,i,s){let n,o,a,r=!0;for(n=0,o=t.length;ni&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ye(t,e){return Object.assign(Object.create(t),e)}const Ue=["left","top","right","bottom"];function Xe(t,e){return t.filter((t=>t.pos===e))}function qe(t,e){return t.filter((t=>-1===Ue.indexOf(t.pos)&&t.box.axis===e))}function Ke(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function Ge(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Ue.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function ei(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Ke(Xe(e,"left"),!0),n=Ke(Xe(e,"right")),o=Ke(Xe(e,"top"),!0),a=Ke(Xe(e,"bottom")),r=qe(e,"x"),l=qe(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Xe(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;Q(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),u=Object.assign({},n);Je(u,Ne(s));const f=Object.assign({maxPadding:u,w:o,h:a,x:n.left,y:n.top},n),g=Ge(l.concat(h),d);ei(r.fullSize,f,d,g),ei(l,f,d,g),ei(h,f,d,g)&&ei(l,f,d,g),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(f),si(r.leftAndTop,f,d,g),f.x+=f.w,f.y+=f.h,si(r.rightAndBottom,f,d,g),t.chartArea={left:f.left,top:f.top,right:f.left+f.w,bottom:f.top+f.h,height:f.h,width:f.w},Q(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})}))}};function oi(t,e=[""],i=t,s,n=(()=>t[0])){ct(s)||(s=mi("_fallback",t));const o={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:i,_fallback:s,_getTarget:n,override:n=>oi([n,...t],e,i,s)};return new Proxy(o,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>ci(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=mi(li(o,t),i),ct(n))return hi(t,n)?gi(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>xi(t).includes(e),ownKeys:t=>xi(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function ai(t,e,i,s){const n={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:ri(t,s),setContext:e=>ai(t,e,i,s),override:n=>ai(t.override(n),e,i,s)};return new Proxy(n,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>ci(t,e,(()=>function(t,e,i){const{_proxy:s,_context:n,_subProxy:o,_descriptors:a}=t;let r=s[e];dt(r)&&a.isScriptable(e)&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t),e=e(o,a||s),r.delete(t),hi(t,e)&&(e=gi(n._scopes,n,t,e));return e}(e,r,t,i));Y(r)&&r.length&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_descriptors:r}=i;if(ct(o.index)&&s(t))e=e[o.index%e.length];else if(U(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const l of i){const i=gi(s,n,t,l);e.push(ai(i,o,a&&a[t],r))}}return e}(e,r,t,a.isIndexable));hi(e,r)&&(r=ai(r,n,o&&o[e],a));return r}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function ri(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:dt(i)?i:()=>i,isIndexable:dt(s)?s:()=>s}}const li=(t,e)=>t?t+ht(e):e,hi=(t,e)=>U(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function ci(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const s=i();return t[e]=s,s}function di(t,e,i){return dt(t)?t(e,i):t}const ui=(t,e)=>!0===t?e:"string"==typeof t?lt(e,t):void 0;function fi(t,e,i,s,n){for(const o of e){const e=ui(i,o);if(e){t.add(e);const o=di(e._fallback,i,n);if(ct(o)&&o!==i&&o!==s)return o}else if(!1===e&&ct(s)&&i!==s)return null}return!1}function gi(t,e,i,s){const n=e._rootScopes,o=di(e._fallback,i,s),a=[...t,...n],r=new Set;r.add(s);let l=pi(r,a,i,o||i,s);return null!==l&&((!ct(o)||o===i||(l=pi(r,a,o,l,s),null!==l))&&oi(Array.from(r),[""],n,o,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const n=s[e];if(Y(n)&&U(i))return i;return n}(e,i,s))))}function pi(t,e,i,s,n){for(;i;)i=fi(t,e,i,s,n);return i}function mi(t,e){for(const i of e){if(!i)continue;const e=i[t];if(ct(e))return e}}function xi(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}const bi=Number.EPSILON||1e-14,_i=(t,e)=>e"x"===t?"y":"x";function vi(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=Vt(o,n),l=Vt(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function wi(t,e="x"){const i=yi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=_i(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)wi(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,Pi=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*yt/i),Di=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*yt/i)+1,Ci={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*kt),easeOutSine:t=>Math.sin(t*kt),easeInOutSine:t=>-.5*(Math.cos(_t*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>Si(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>Si(t)?t:Pi(t,.075,.3),easeOutElastic:t=>Si(t)?t:Di(t,.075,.3),easeInOutElastic(t){const e=.1125;return Si(t)?t:t<.5?.5*Pi(2*t,e,.45):.5+.5*Di(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-Ci.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*Ci.easeInBounce(2*t):.5*Ci.easeOutBounce(2*t-1)+.5};function Oi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function Ai(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function Ti(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=Oi(t,n,i),r=Oi(n,o,i),l=Oi(o,e,i),h=Oi(a,r,i),c=Oi(r,l,i);return Oi(h,c,i)}const Li=new Map;function Ri(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=Li.get(i);return s||(s=new Intl.NumberFormat(t,e),Li.set(i,s)),s}(e,i).format(t)}function Ei(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ii(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function zi(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Fi(t){return"angle"===t?{between:Ht,compare:Wt,normalize:Nt}:{between:Yt,compare:(t,e)=>t-e,normalize:t=>t}}function Bi({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Vi(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Fi(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Fi(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hb||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Bi({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Bi({start:_,end:d,loop:u,count:a,style:f})),g}function Wi(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Hi(t,[{start:a,end:r,loop:o}],i,e);return Hi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,rnull===t||""===t;const Gi=!!Se&&{passive:!0};function Zi(t,e,i){t.canvas.removeEventListener(e,i,Gi)}function Ji(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function Qi(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.addedNodes,s),e=e&&!Ji(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function ts(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.removedNodes,s),e=e&&!Ji(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const es=new Map;let is=0;function ss(){const t=window.devicePixelRatio;t!==is&&(is=t,es.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function ns(t,i,s){const n=t.canvas,o=n&&pe(n);if(!o)return;const a=e(((t,e)=>{const i=o.clientWidth;s(t,e),i{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||a(i,s)}));return r.observe(o),function(t,e){es.size||window.addEventListener("resize",ss),es.set(t,e)}(t,a),r}function os(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){es.delete(t),es.size||window.removeEventListener("resize",ss)}(t)}function as(t,i,s){const n=t.canvas,o=e((e=>{null!==t.ctx&&s(function(t,e){const i=qi[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t,(t=>{const e=t[0];return[e,e.offsetX,e.offsetY]}));return function(t,e,i){t.addEventListener(e,i,Gi)}(n,i,o),o}class rs extends Ui{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t.$chartjs={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",Ki(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(Ki(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e.$chartjs)return!1;const i=e.$chartjs.initial;["height","width"].forEach((t=>{const s=i[t];$(s)?e.removeAttribute(t):e.setAttribute(t,s)}));const s=i.style||{};return Object.keys(s).forEach((t=>{e.style[t]=s[t]})),e.width=e.width,delete e.$chartjs,!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:Qi,detach:ts,resize:ns}[e]||as;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:os,detach:os,resize:os}[e]||Zi)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return Me(t,e,i,s)}isAttached(t){const e=pe(t);return!(!e||!e.isConnected)}}function ls(t){return!ge()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?Xi:rs}var hs=Object.freeze({__proto__:null,_detectPlatform:ls,BasePlatform:Ui,BasicPlatform:Xi,DomPlatform:rs});const cs="transparent",ds={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=W(t||cs),n=s.valid&&W(e||cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class us{constructor(t,e,i,s){const n=e[i];s=je([t.to,s,n,t.from]);const o=je([t.from,n,s]);this._active=!0,this._fn=t.fn||ds[t.type||typeof o],this._easing=Ci[t.easing]||Ci.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=je([t.to,e,s,t.from]),this._from=je([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),bt.set("animations",{colors:{type:"color",properties:["color","borderColor","backgroundColor"]},numbers:{type:"number",properties:["x","y","borderWidth","radius","tension"]}}),bt.describe("animations",{_fallback:"animation"}),bt.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}});class gs{constructor(t,e){this._chart=t,this._properties=new Map,this.configure(e)}configure(t){if(!U(t))return;const e=this._properties;Object.getOwnPropertyNames(t).forEach((i=>{const s=t[i];if(!U(s))return;const n={};for(const t of fs)n[t]=s[t];(Y(s.properties)&&s.properties||[i]).forEach((t=>{t!==i&&e.has(t)||e.set(t,n)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new us(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(a.add(this._chart,i),!0):void 0}}function ps(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function ms(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Ms(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i]}}}const ks=t=>"reset"===t||"none"===t,Ss=(t,e)=>e?t:Object.assign({},t);class Ps{constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.$context=void 0,this._syncList=[],this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=bs(t.vScale,t),this.addElements()}updateIndex(t){this.index!==t&&Ms(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=K(i.xAxisID,ws(t,"x")),o=e.yAxisID=K(i.yAxisID,ws(t,"y")),a=e.rAxisID=K(i.rAxisID,ws(t,"r")),r=e.indexAxis,l=e.iAxisID=s(r,n,o,a),h=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(l),e.vScale=this.getScaleForId(h)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&ue(this._data,this),t._stacked&&Ms(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(U(e))this._data=function(t){const e=Object.keys(t),i=new Array(e.length);let s,n,o;for(s=0,n=e.length;s0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,h=s;else{h=Y(s[t])?this.parseArrayData(i,s,t,e):U(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const n=()=>null===l[a]||d&&l[a]t&&!e.hidden&&e._stacked&&{keys:ms(i,!0),values:null})(e,i,this.chart),l={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:h,max:c}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(a);let d,u;function f(){u=s[d];const e=u[a.axis];return!X(u[t.axis])||h>e||c=0;--d)if(!f()){this.updateRangeFromParsed(l,t,u,r);break}return l}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Ss(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new gs(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||ks(t)||this.chart._animationsDisabled}updateElement(t,e,i,s){ks(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!ks(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}Ds.defaults={},Ds.defaultRoutes=void 0;const Cs={values:t=>Y(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=Dt(Math.abs(o)),r=Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),Ri(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=t/Math.pow(10,Math.floor(Dt(t)));return 1===s||2===s||5===s?Cs.numeric.call(this,t,e,i):""}};var Os={formatters:Cs};function As(t,e){const i=t.options.ticks,s=i.maxTicksLimit||function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),n=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;is)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(n,e,s);if(o>0){let t,i;const s=o>1?Math.round((r-a)/(o-1)):null;for(Ts(e,l,h,$(s)?0:a-s,a),t=0,i=o-1;te.lineWidth,tickColor:(t,e)=>e.color,offset:!1,borderDash:[],borderDashOffset:0,borderWidth:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:Os.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),bt.route("scale.ticks","color","","color"),bt.route("scale.grid","color","","borderColor"),bt.route("scale.grid","borderColor","","borderColor"),bt.route("scale.title","color","","color"),bt.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t}),bt.describe("scales",{_fallback:"scale"}),bt.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t});const Ls=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i;function Rs(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Is(t){return t.drawTicks?t.tickLength:0}function zs(t,e){if(!t.display)return 0;const i=He(t.font,e),s=Ne(t.padding);return(Y(t.text)?t.text.length:1)*i.lineHeight+s.height}function Fs(t,e,i){let n=s(t);return(i&&"right"!==e||!i&&"right"===e)&&(n=(t=>"left"===t?"right":"right"===t?"left":t)(n)),n}class Bs extends Ds{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=q(t,Number.POSITIVE_INFINITY),e=q(e,Number.NEGATIVE_INFINITY),i=q(i,Number.POSITIVE_INFINITY),s=q(s,Number.NEGATIVE_INFINITY),{min:q(t,i),max:q(e,s),minDefined:X(t),maxDefined:X(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:q(i,q(s,i)),max:q(s,q(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){J(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=$e(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=jt(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Is(t.grid)-e.padding-zs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=zt(Math.min(Math.asin(jt((h.highest.height+6)/o,-1,1)),Math.asin(jt(a/r,-1,1))-Math.asin(jt(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){J(this.options.afterCalculateLabelRotation,[this])}beforeFit(){J(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=zs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Is(n)+o):(t.height=this.maxHeight,t.width=Is(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=It(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){J(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:n[t]||0,height:o[t]||0});return{first:v(0),last:v(e-1),widest:v(_),highest:v(y),widths:n,heights:o}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return $t(this._alignToPixels?Kt(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:o}=s,a=n.offset,r=this.isHorizontal(),l=this.ticks.length+(a?1:0),h=Is(n),c=[],d=n.setContext(this.getContext()),u=d.drawBorder?d.borderWidth:0,f=u/2,g=function(t){return Kt(i,t,u)};let p,m,x,b,_,y,v,w,M,k,S,P;if("top"===o)p=g(this.bottom),y=this.bottom-h,w=p-f,k=g(t.top)+f,P=t.bottom;else if("bottom"===o)p=g(this.top),k=t.top,P=g(t.bottom)-f,y=p+f,w=this.top+h;else if("left"===o)p=g(this.right),_=this.right-h,v=p-f,M=g(t.left)+f,S=t.right;else if("right"===o)p=g(this.left),M=t.left,S=g(t.right)-f,_=p+f,v=this.left+h;else if("x"===e){if("center"===o)p=g((t.top+t.bottom)/2+.5);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}k=t.top,P=t.bottom,y=p+f,w=y+h}else if("y"===e){if("center"===o)p=g((t.left+t.right)/2);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}_=p-f,v=_-h,M=t.left,S=t.right}const D=K(s.ticks.maxTicksLimit,l),C=Math.max(1,Math.ceil(l/D));for(m=0;me.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:i+1,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");bt.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&bt.describe(e,t.descriptors)}(t,o,i),this.override&&bt.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in bt[s]&&(delete bt[s][i],this.override&&delete gt[i])}}var Ws=new class{constructor(){this.controllers=new Vs(Ps,"datasets",!0),this.elements=new Vs(Ds,"elements"),this.plugins=new Vs(Object,"plugins"),this.scales=new Vs(Bs,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):Q(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=ht(t);J(i["before"+s],[],i),e[t](i),J(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function Hs(t,e){return e||!1!==t?!0===t?{}:t:null}function js(t,e,i,s){const n=t.pluginScopeKeys(e),o=t.getOptionScopes(i,n);return t.createResolver(o,s,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function $s(t,e){const i=bt.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function Ys(t,e){return"x"===t||"y"===t?t:e.axis||("top"===(i=e.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.charAt(0).toLowerCase();var i}function Us(t){const e=t.options||(t.options={});e.plugins=K(e.plugins,{}),e.scales=function(t,e){const i=gt[t.type]||{scales:{}},s=e.scales||{},n=$s(t.type,e),o=Object.create(null),a=Object.create(null);return Object.keys(s).forEach((t=>{const e=s[t];if(!U(e))return console.error(`Invalid scale configuration for scale: ${t}`);if(e._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);const r=Ys(t,e),l=function(t,e){return t===e?"_index_":"_value_"}(r,n),h=i.scales||{};o[r]=o[r]||t,a[t]=ot(Object.create(null),[{axis:r},e,h[r],h[l]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,r=i.indexAxis||$s(n,e),l=(gt[n]||{}).scales||{};Object.keys(l).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,r),n=i[e+"AxisID"]||o[e]||e;a[n]=a[n]||Object.create(null),ot(a[n],[{axis:e},s[n],l[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];ot(e,[bt.scales[e.type],bt.scale])})),a}(t,e)}function Xs(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const qs=new Map,Ks=new Set;function Gs(t,e){let i=qs.get(t);return i||(i=e(),qs.set(t,i),Ks.add(i)),i}const Zs=(t,e,i)=>{const s=lt(e,i);void 0!==s&&t.add(s)};class Js{constructor(t){this._config=function(t){return(t=t||{}).data=Xs(t.data),Us(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=Xs(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),Us(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return Gs(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return Gs(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return Gs(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return Gs(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>Zs(r,t,e)))),e.forEach((t=>Zs(r,s,t))),e.forEach((t=>Zs(r,gt[n]||{},t))),e.forEach((t=>Zs(r,bt,t))),e.forEach((t=>Zs(r,pt,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),Ks.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,gt[e]||{},bt.datasets[e]||{},{type:e},bt,pt]}resolveNamedOptions(t,e,i,s=[""]){const n={$shared:!0},{resolver:o,subPrefixes:a}=Qs(this._resolverCache,t,s);let r=o;if(function(t,e){const{isScriptable:i,isIndexable:s}=ri(t);for(const n of e){const e=i(n),o=s(n),a=(o||e)&&t[n];if(e&&(dt(a)||tn(a))||o&&Y(a))return!0}return!1}(o,e)){n.$shared=!1;r=ai(o,i=dt(i)?i():i,this.createResolver(t,i,a))}for(const t of e)n[t]=r[t];return n}createResolver(t,e,i=[""],s){const{resolver:n}=Qs(this._resolverCache,t,i);return U(e)?ai(n,e,void 0,s):n}}function Qs(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:oi(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const tn=t=>U(t)&&Object.getOwnPropertyNames(t).reduce(((e,i)=>e||dt(t[i])),!1);const en=["top","bottom","left","right","chartArea"];function sn(t,e){return"top"===t||"bottom"===t||-1===en.indexOf(t)&&"x"===e}function nn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function on(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),J(i&&i.onComplete,[t],e)}function an(t){const e=t.chart,i=e.options.animation;J(i&&i.onProgress,[t],e)}function rn(t){return ge()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const ln={},hn=t=>{const e=rn(t);return Object.values(ln).filter((t=>t.canvas===e)).pop()};function cn(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class dn{constructor(t,e){const s=this.config=new Js(e),n=rn(t),o=hn(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas can be reused.");const r=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||ls(n)),this.platform.updateConfig(s);const l=this.platform.acquireContext(n,r.aspectRatio),h=l&&l.canvas,c=h&&h.height,d=h&&h.width;this.id=j(),this.ctx=l,this.canvas=h,this.width=d,this.height=c,this._options=r,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Ns,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=i((t=>this.update(t)),r.resizeDelay||0),this._dataChanges=[],ln[this.id]=this,l&&h?(a.listen(this,"complete",on),a.listen(this,"progress",an),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:s,_aspectRatio:n}=this;return $(t)?e&&n?n:s?i/s:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Gt(this.canvas,this.ctx),this}stop(){return a.stop(this),this}resize(t,e){a.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),J(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){Q(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=Ys(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),Q(n,(e=>{const n=e.options,o=n.id,a=Ys(o,n),r=K(n.type,e.dtype);void 0!==n.position&&sn(n.position,a)===sn(e.dposition)||(n.position=e.dposition),s[o]=!0;let l=null;if(o in i&&i[o].type===r)l=i[o];else{l=new(Ws.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[l.id]=l}l.init(n,t)})),Q(s,((t,e)=>{t||delete i[e]})),Q(i,(t=>{ni.configure(this,t,t.options),ni.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(nn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){Q(this.scales,(t=>{ni.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);ut(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){cn(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ni.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],Q(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i=t._clip,s=!i.disabled,n=this.chartArea,o={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",o)&&(s&&Qt(e,{left:!1===i.left?0:n.left-i.left,right:!1===i.right?this.width:n.right+i.right,top:!1===i.top?0:n.top-i.top,bottom:!1===i.bottom?this.height:n.bottom+i.bottom}),t.controller.draw(),s&&te(e),o.cancelable=!1,this.notifyPlugins("afterDatasetDraw",o))}getElementsAtEventForMode(t,e,i,s){const n=Ee.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ye(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);ct(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),a.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};Q(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){Q(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},Q(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!tt(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:Jt(t,this.chartArea,this._minPadding)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=ft(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,J(n.onHover,[t,a,this],this),r&&J(n.onClick,[t,a,this],this));const h=!tt(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}const un=()=>Q(dn.instances,(t=>t._plugins.invalidate())),fn=!0;function gn(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}Object.defineProperties(dn,{defaults:{enumerable:fn,value:bt},instances:{enumerable:fn,value:ln},overrides:{enumerable:fn,value:gt},registry:{enumerable:fn,value:Ws},version:{enumerable:fn,value:"3.7.0"},getChart:{enumerable:fn,value:hn},register:{enumerable:fn,value:(...t)=>{Ws.add(...t),un()}},unregister:{enumerable:fn,value:(...t)=>{Ws.remove(...t),un()}}});class pn{constructor(t){this.options=t||{}}formats(){return gn()}parse(t,e){return gn()}format(t,e){return gn()}add(t,e,i){return gn()}diff(t,e,i){return gn()}startOf(t,e,i){return gn()}endOf(t,e){return gn()}}pn.override=function(t){Object.assign(pn.prototype,t)};var mn={_date:pn};function xn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(ct(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function _n(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base=i?1:-1)}(c,e,o)*n,d===o&&(p-=c/2),h=p+c),p===e.getPixelForValue(o)){const t=Ct(c)*e.getLineWidthForValue(o)/2;p+=t,c-=t}return{size:c,base:p,head:h,center:h+c/2}}_calculateBarIndexPixels(t,e){const i=e.scale,s=this.options,n=s.skipNull,o=K(s.maxBarThickness,1/0);let a,r;if(e.grouped){const i=n?this._getStackCount(t):e.stackCount,l="flex"===s.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,{xScale:i,yScale:s}=e,n=this.getParsed(t),o=i.getLabelForValue(n.x),a=s.getLabelForValue(n.y),r=n._custom;return{label:e.label,value:"("+o+", "+a+(r?", "+r:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,r=this.resolveDataElementOptions(e,s),l=this.getSharedOptions(r),h=this.includeOptions(s,l),c=o.axis,d=a.axis;for(let r=e;r""}}}};class Dn extends Ps{constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,o,a=t=>+i[t];if(U(i[t])){const{key:t="value"}=this._parsing;a=e=>+lt(i[e],t)}for(n=t,o=t+e;nHt(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Ht(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(kt,c,u),x=g(_t,h,d),b=g(_t+kt,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(c,h,r),p=(i.width-o)/d,m=(i.height-o)/u,x=Math.max(Math.min(p,m)/2,0),b=Z(this.options.radius,x),_=(b-Math.max(b*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=f*b,this.offsetY=g*b,s.total=this.calculateTotal(),this.outerRadius=b-_*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-_*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/yt)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,f=this.resolveDataElementOptions(e,s),g=this.getSharedOptions(f),p=this.includeOptions(s,g);let m,x=this._getRotation();for(m=0;m0&&!isNaN(t)?yt*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s"spacing"!==t,_indexable:t=>"spacing"!==t},Dn.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label(t){let e=t.label;const i=": "+t.formattedValue;return Y(e)?(e=e.slice(),e[0]+=i):e+=i,e}}}}};class Cn extends Ps{initialize(){this.enableOptionSharing=!0,super.initialize()}update(t){const e=this._cachedMeta,{dataset:i,data:s=[],_dataset:n}=e,o=this.chart._animationsDisabled;let{start:a,count:r}=function(t,e,i){const s=e.length;let n=0,o=s;if(t._sorted){const{iScale:a,_parsed:r}=t,l=a.axis,{min:h,max:c,minDefined:d,maxDefined:u}=a.getUserBounds();d&&(n=jt(Math.min(re(r,a.axis,h).lo,i?s:re(e,l,a.getPixelForValue(h)).lo),0,s-1)),o=u?jt(Math.max(re(r,a.axis,c).hi+1,i?0:re(e,l,a.getPixelForValue(c)).hi+1),n,s)-n:s-n}return{start:n,count:o}}(e,s,o);this._drawStart=a,this._drawCount=r,function(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}(e)&&(a=0,r=s.length),i._chart=this.chart,i._datasetIndex=this.index,i._decimated=!!n._decimated,i.points=s;const l=this.resolveDatasetElementOptions(t);this.options.showLine||(l.borderWidth=0),l.segment=this.options.segment,this.updateElement(i,void 0,{animated:!o,options:l},t),this.updateElements(s,a,r,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a,_stacked:r,_dataset:l}=this._cachedMeta,h=this.resolveDataElementOptions(e,s),c=this.getSharedOptions(h),d=this.includeOptions(s,c),u=o.axis,f=a.axis,{spanGaps:g,segment:p}=this.options,m=Tt(g)?g:Number.POSITIVE_INFINITY,x=this.chart._animationsDisabled||n||"none"===s;let b=e>0&&this.getParsed(e-1);for(let h=e;h0&&i[u]-b[u]>m,p&&(g.parsed=i,g.raw=l.data[h]),d&&(g.options=c||this.resolveDataElementOptions(h,e.active?"active":s)),x||this.updateElement(e,h,g,s),b=i}this.updateSharedOptions(c,s,h)}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}}Cn.id="line",Cn.defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1},Cn.overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};class On extends Ps{constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=this.getDataset(),r=o.options.animation,l=this._cachedMeta.rScale,h=l.xCenter,c=l.yCenter,d=l.getIndexAngle(0)-.5*_t;let u,f=d;const g=360/this.countVisibleElements();for(u=0;u{!isNaN(t.data[s])&&this.chart.getDataVisibility(s)&&i++})),i}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?It(this.resolveDataElementOptions(t,e).angle||i):0}}On.id="polarArea",On.defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0},On.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label:t=>t.chart.data.labels[t.dataIndex]+": "+t.formattedValue}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};class An extends Dn{}An.id="pie",An.defaults={cutout:0,rotation:0,circumference:360,radius:"100%"};class Tn extends Ps{getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this.getDataset(),o=this._cachedMeta.rScale,a="reset"===s;for(let r=e;r"",label:t=>"("+t.label+", "+t.formattedValue+")"}}},scales:{x:{type:"linear"},y:{type:"linear"}}};var Rn=Object.freeze({__proto__:null,BarController:Sn,BubbleController:Pn,DoughnutController:Dn,LineController:Cn,PolarAreaController:On,PieController:An,RadarController:Tn,ScatterController:Ln});function En(t,e,i){const{startAngle:s,pixelMargin:n,x:o,y:a,outerRadius:r,innerRadius:l}=e;let h=n/r;t.beginPath(),t.arc(o,a,r,s-h,i+h),l>n?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+kt,s-kt),t.closePath(),t.clip()}function In(t,e,i,s){const n=Be(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return jt(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:jt(n.innerStart,0,a),innerEnd:jt(n.innerEnd,0,a)}}function zn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Fn(t,e,i,s,n){const{x:o,y:a,startAngle:r,pixelMargin:l,innerRadius:h}=e,c=Math.max(e.outerRadius+s+i-l,0),d=h>0?h+s+i+l:0;let u=0;const f=n-r;if(s){const t=((h>0?h-s:0)+(c>0?c-s:0))/2;u=(f-(0!==t?f*t/(t+s):f))/2}const g=(f-Math.max(.001,f*c-i/_t)/c)/2,p=r+g+u,m=n-g-u,{outerStart:x,outerEnd:b,innerStart:_,innerEnd:y}=In(e,d,c,m-p),v=c-x,w=c-b,M=p+x/v,k=m-b/w,S=d+_,P=d+y,D=p+_/S,C=m-y/P;if(t.beginPath(),t.arc(o,a,c,M,k),b>0){const e=zn(w,k,o,a);t.arc(e.x,e.y,b,k,m+kt)}const O=zn(P,m,o,a);if(t.lineTo(O.x,O.y),y>0){const e=zn(P,C,o,a);t.arc(e.x,e.y,y,m+kt,C+Math.PI)}if(t.arc(o,a,d,m-y/d,p+_/d,!0),_>0){const e=zn(S,D,o,a);t.arc(e.x,e.y,_,D+Math.PI,p-kt)}const A=zn(v,p,o,a);if(t.lineTo(A.x,A.y),x>0){const e=zn(v,M,o,a);t.arc(e.x,e.y,x,p-kt,M)}t.closePath()}function Bn(t,e,i,s,n){const{options:o}=e,{borderWidth:a,borderJoinStyle:r}=o,l="inner"===o.borderAlign;a&&(l?(t.lineWidth=2*a,t.lineJoin=r||"round"):(t.lineWidth=a,t.lineJoin=r||"bevel"),e.fullCircles&&function(t,e,i){const{x:s,y:n,startAngle:o,pixelMargin:a,fullCircles:r}=e,l=Math.max(e.outerRadius-a,0),h=e.innerRadius+a;let c;for(i&&En(t,e,o+yt),t.beginPath(),t.arc(s,n,h,o+yt,o,!0),c=0;c=yt||Ht(n,a,r),f=Yt(o,l+d,h+d);return u&&f}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius","circumference"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/2,n=(e.spacing||0)/2;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>yt?Math.floor(i/yt):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();let o=0;if(s){o=s/2;const e=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(e)*o,Math.sin(e)*o),this.circumference>=_t&&(o=s)}t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor;const a=function(t,e,i,s){const{fullCircles:n,startAngle:o,circumference:a}=e;let r=e.endAngle;if(n){Fn(t,e,i,s,o+yt);for(let e=0;er&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function Yn(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?$n:jn}Vn.id="arc",Vn.defaults={borderAlign:"center",borderColor:"#fff",borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0},Vn.defaultRoutes={backgroundColor:"backgroundColor"};const Un="function"==typeof Path2D;function Xn(t,e,i,s){Un&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Wn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=Yn(e);for(const r of n)Wn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class qn extends Ds{constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;ki(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Ni(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Wi(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?Ai:t.tension||"monotone"===t.cubicInterpolationMode?Ti:Oi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t&&"fill"!==t};class Gn extends Ds{constructor(t){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.options,{x:n,y:o}=this.getProps(["x","y"],i);return Math.pow(t-n,2)+Math.pow(e-o,2){oo(t)}))}var ro={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void ao(t);const s=t.width;t.data.datasets.forEach(((e,n)=>{const{_data:o,indexAxis:a}=e,r=t.getDatasetMeta(n),l=o||e.data;if("y"===je([a,t.options.indexAxis]))return;if("line"!==r.type)return;const h=t.scales[r.xAxisID];if("linear"!==h.type&&"time"!==h.type)return;if(t.options.parsing)return;let{start:c,count:d}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=jt(re(e,o.axis,a).lo,0,i-1)),s=h?jt(re(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(r,l);if(d<=(i.threshold||4*s))return void oo(e);let u;switch($(o)&&(e._data=l,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":u=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(l,c,d,s,i);break;case"min-max":u=function(t,e,i,s){let n,o,a,r,l,h,c,d,u,f,g=0,p=0;const m=[],x=e+i-1,b=t[e].x,_=t[x].x-b;for(n=e;nf&&(f=r,c=n),g=(p*g+o.x)/++p;else{const i=n-1;if(!$(h)&&!$(c)){const e=Math.min(h,c),s=Math.max(h,c);e!==d&&e!==i&&m.push({...t[e],x:g}),s!==d&&s!==i&&m.push({...t[s],x:g})}n>0&&i!==d&&m.push(t[i]),m.push(o),l=e,p=0,u=f=r,h=c=d=n}}return m}(l,c,d,s);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=u}))},destroy(t){ao(t)}};function lo(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=K(i&&i.target,i);return void 0===s&&(s=!!e.backgroundColor),!1!==s&&null!==s&&(!0===s?"origin":s)}(t);if(U(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return X(n)&&Math.floor(n)===n?("-"!==s[0]&&"+"!==s[0]||(n=e+n),!(n===e||n<0||n>=i)&&n):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}class ho{constructor(t){this.x=t.x,this.y=t.y,this.radius=t.radius}pathSegment(t,e,i){const{x:s,y:n,radius:o}=this;return e=e||{start:0,end:yt},t.arc(s,n,o,e.end,e.start,!0),!i.bounds}interpolate(t){const{x:e,y:i,radius:s}=this,n=t.angle;return{x:e+Math.cos(n)*s,y:i+Math.sin(n)*s,angle:n}}}function co(t){return(t.scale||{}).getPointPositionForValue?function(t){const{scale:e,fill:i}=t,s=e.options,n=e.getLabels().length,o=[],a=s.reverse?e.max:e.min,r=s.reverse?e.min:e.max;let l,h,c;if(c="start"===i?a:"end"===i?r:U(i)?i.value:e.getBaseValue(),s.grid.circular)return h=e.getPointPositionForValue(0,a),new ho({x:h.x,y:h.y,radius:e.getDistanceFromCenterForValue(c)});for(l=0;lt;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function fo(t,e,i){const s=[];for(let n=0;n{e=uo(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new qn({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function xo(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!X(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function bo(t,e,i){t.beginPath(),e.path(t),t.lineTo(e.last().x,i),t.lineTo(e.first().x,i),t.closePath(),t.clip()}function _o(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=Nt(n),o=Nt(o)),{property:t,start:n,end:o}}function yo(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function vo(t,e,i){const{top:s,bottom:n}=e.chart.chartArea,{property:o,start:a,end:r}=i||{};"x"===o&&(t.beginPath(),t.rect(a,s,r-a,n-s),t.clip())}function wo(t,e,i,s){const n=e.interpolate(i,s);n&&t.lineTo(n.x,n.y)}function Mo(t,e){const{line:i,target:s,property:n,color:o,scale:a}=e,r=function(t,e,i){const s=t.segments,n=t.points,o=e.points,a=[];for(const t of s){let{start:s,end:r}=t;r=uo(s,r,n);const l=_o(i,n[s],n[r],t.loop);if(!e.segments){a.push({source:t,target:l,start:n[s],end:n[r]});continue}const h=Wi(e,l);for(const e of h){const s=_o(i,o[e.start],o[e.end],e.loop),r=Vi(t,n,s);for(const t of r)a.push({source:t,target:e,start:{[i]:yo(l,s,"start",Math.max)},end:{[i]:yo(l,s,"end",Math.min)}})}}return a}(i,s,n);for(const{source:e,target:l,start:h,end:c}of r){const{style:{backgroundColor:r=o}={}}=e,d=!0!==s;t.save(),t.fillStyle=r,vo(t,a,d&&_o(n,h,c)),t.beginPath();const u=!!i.pathSegment(t,e);let f;if(d){u?t.closePath():wo(t,s,c,n);const e=!!s.pathSegment(t,l,{move:u,reverse:!0});f=u&&e,f||wo(t,s,h,n)}t.closePath(),t.fill(f?"evenodd":"nonzero"),t.restore()}}function ko(t,e,i){const s=po(e),{line:n,scale:o,axis:a}=e,r=n.options,l=r.fill,h=r.backgroundColor,{above:c=h,below:d=h}=l||{};s&&n.points.length&&(Qt(t,i),function(t,e){const{line:i,target:s,above:n,below:o,area:a,scale:r}=e,l=i._loop?"angle":e.axis;t.save(),"x"===l&&o!==n&&(bo(t,s,a.top),Mo(t,{line:i,target:s,color:n,scale:r,property:l}),t.restore(),t.save(),bo(t,s,a.bottom)),Mo(t,{line:i,target:s,color:o,scale:r,property:l}),t.restore()}(t,{line:n,target:s,above:c,below:d,area:i,scale:o,axis:a}),te(t))}var So={id:"filler",afterDatasetsUpdate(t,e,i){const s=(t.data.datasets||[]).length,n=[];let o,a,r,l;for(a=0;a=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&ko(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;i&&ko(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;s&&!1!==s.fill&&"beforeDatasetDraw"===i.drawTime&&ko(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const Po=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class Do extends Ds{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=J(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=He(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=Po(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,n,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const p=i+e/2+n.measureText(t.text).width;o>0&&u+s+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:s},d=Math.max(d,p),u+=s+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:o}}=this,a=Ei(o,this.left,this.width);if(this.isHorizontal()){let o=0,r=n(i,this.left+s,this.right-this.lineWidths[o]);for(const l of e)o!==l.row&&(o=l.row,r=n(i,this.left+s,this.right-this.lineWidths[o])),l.top+=this.top+t+s,l.left=a.leftForLtr(a.x(r),l.width),r+=l.width+s}else{let o=0,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height);for(const l of e)l.col!==o&&(o=l.col,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height)),l.top=r,l.left+=this.left+s,l.left=a.leftForLtr(a.x(l.left),l.width),r+=l.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Qt(t,this),this._draw(),te(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:a,labels:r}=t,l=bt.color,h=Ei(t.rtl,this.left,this.width),c=He(r.font),{color:d,padding:u}=r,f=c.size,g=f/2;let p;this.drawTitle(),s.textAlign=h.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=c.string;const{boxWidth:m,boxHeight:x,itemHeight:b}=Po(r,f),_=this.isHorizontal(),y=this._computeTitleHeight();p=_?{x:n(a,this.left+u,this.right-i[0]),y:this.top+u+y,line:0}:{x:this.left+u,y:n(a,this.top+y+u,this.bottom-e[0].height),line:0},Ii(this.ctx,t.textDirection);const v=b+u;this.legendItems.forEach(((w,M)=>{s.strokeStyle=w.fontColor||d,s.fillStyle=w.fontColor||d;const k=s.measureText(w.text).width,S=h.textAlign(w.textAlign||(w.textAlign=r.textAlign)),P=m+g+k;let D=p.x,C=p.y;h.setWidth(this.width),_?M>0&&D+P+u>this.right&&(C=p.y+=v,p.line++,D=p.x=n(a,this.left+u,this.right-i[p.line])):M>0&&C+v>this.bottom&&(D=p.x=D+e[p.line].width+u,p.line++,C=p.y=n(a,this.top+y+u,this.bottom-e[p.line].height));!function(t,e,i){if(isNaN(m)||m<=0||isNaN(x)||x<0)return;s.save();const n=K(i.lineWidth,1);if(s.fillStyle=K(i.fillStyle,l),s.lineCap=K(i.lineCap,"butt"),s.lineDashOffset=K(i.lineDashOffset,0),s.lineJoin=K(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=K(i.strokeStyle,l),s.setLineDash(K(i.lineDash,[])),r.usePointStyle){const o={radius:m*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},a=h.xPlus(t,m/2);Zt(s,o,a,e+g)}else{const o=e+Math.max((f-x)/2,0),a=h.leftForLtr(t,m),r=We(i.borderRadius);s.beginPath(),Object.values(r).some((t=>0!==t))?oe(s,{x:a,y:o,w:m,h:x,radius:r}):s.rect(a,o,m,x),s.fill(),0!==n&&s.stroke()}s.restore()}(h.x(D),C,w),D=o(S,D+m+g,_?D+P:this.right,t.rtl),function(t,e,i){se(s,i.text,t,e+b/2,c,{strikethrough:i.hidden,textAlign:h.textAlign(i.textAlign)})}(h.x(D),C,w),_?p.x+=P+u:p.y+=v})),zi(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=He(e.font),o=Ne(e.padding);if(!e.display)return;const a=Ei(t.rtl,this.left,this.width),r=this.ctx,l=e.position,h=i.size/2,c=o.top+h;let d,u=this.left,f=this.width;if(this.isHorizontal())f=Math.max(...this.lineWidths),d=this.top+c,u=n(t.align,u,this.right-f);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);d=c+n(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const g=n(l,u,u+f);r.textAlign=a.textAlign(s(l)),r.textBaseline="middle",r.strokeStyle=e.color,r.fillStyle=e.color,r.font=i.string,se(r,e.text,g,d,i)}_computeTitleHeight(){const t=this.options.title,e=He(t.font),i=Ne(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(Yt(t,this.left,this.right)&&Yt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const a=t.controller.getStyle(i?0:void 0),r=Ne(a.borderWidth);return{text:e[t.index].label,fillStyle:a.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:a.borderCapStyle,lineDash:a.borderDash,lineDashOffset:a.borderDashOffset,lineJoin:a.borderJoinStyle,lineWidth:(r.width+r.height)/4,strokeStyle:a.borderColor,pointStyle:s||a.pointStyle,rotation:a.rotation,textAlign:n||a.textAlign,borderRadius:0,datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Oo extends Ds{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=Y(i.text)?i.text.length:1;this._padding=Ne(i.padding);const n=s*He(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=n:this.width=n}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:o,options:a}=this,r=a.align;let l,h,c,d=0;return this.isHorizontal()?(h=n(r,i,o),c=e+t,l=o-i):("left"===a.position?(h=i+t,c=n(r,s,e),d=-.5*_t):(h=o-t,c=n(r,e,s),d=.5*_t),l=s-e),{titleX:h,titleY:c,maxWidth:l,rotation:d}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=He(e.font),n=i.lineHeight/2+this._padding.top,{titleX:o,titleY:a,maxWidth:r,rotation:l}=this._drawArgs(n);se(t,e.text,0,0,i,{color:e.color,maxWidth:r,rotation:l,textAlign:s(e.align),textBaseline:"middle",translation:[o,a]})}}var Ao={id:"title",_element:Oo,start(t,e,i){!function(t,e){const i=new Oo({ctx:t.ctx,options:e,chart:t});ni.configure(t,i,e),ni.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ni.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const To=new WeakMap;var Lo={id:"subtitle",start(t,e,i){const s=new Oo({ctx:t.ctx,options:i,chart:t});ni.configure(t,s,i),ni.addBox(t,s),To.set(t,s)},stop(t){ni.removeBox(t,To.get(t)),To.delete(t)},beforeUpdate(t,e,i){const s=To.get(t);ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Ro={average(t){if(!t.length)return!1;let e,i,s=0,n=0,o=0;for(e=0,i=t.length;e-1?t.split("\n"):t}function zo(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Fo(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=He(e.bodyFont),h=He(e.titleFont),c=He(e.footerFont),d=o.length,u=n.length,f=s.length,g=Ne(e.padding);let p=g.height,m=0,x=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(x+=t.beforeBody.length+t.afterBody.length,d&&(p+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),x){p+=f*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(x-f)*l.lineHeight+(x-1)*e.bodySpacing}u&&(p+=e.footerMarginTop+u*c.lineHeight+(u-1)*e.footerSpacing);let b=0;const _=function(t){m=Math.max(m,i.measureText(t).width+b)};return i.save(),i.font=h.string,Q(t.title,_),i.font=l.string,Q(t.beforeBody.concat(t.afterBody),_),b=e.displayColors?a+2+e.boxPadding:0,Q(s,(t=>{Q(t.before,_),Q(t.lines,_),Q(t.after,_)})),b=0,i.font=c.string,Q(t.footer,_),i.restore(),m+=g.width,{width:m,height:p}}function Bo(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Vo(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Bo(t,e,i,s),yAlign:s}}function Wo(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=We(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:jt(g,0,s.width-e.width),y:jt(p,0,s.height-e.height)}}function No(t,e,i){const s=Ne(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ho(t){return Eo([],Io(t))}function jo(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}class $o extends Ds{constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart||t._chart,this._chart=this.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const e=this.chart,i=this.options.setContext(this.getContext()),s=i.enabled&&e.options.animation&&i.animations,n=new gs(this.chart,s);return s._cacheable&&(this._cachedAnimations=Object.freeze(n)),n}getContext(){return this.$context||(this.$context=(t=this.chart.getContext(),e=this,i=this._tooltipItems,Ye(t,{tooltip:e,tooltipItems:i,type:"tooltip"})));var t,e,i}getTitle(t,e){const{callbacks:i}=e,s=i.beforeTitle.apply(this,[t]),n=i.title.apply(this,[t]),o=i.afterTitle.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}getBeforeBody(t,e){return Ho(e.callbacks.beforeBody.apply(this,[t]))}getBody(t,e){const{callbacks:i}=e,s=[];return Q(t,(t=>{const e={before:[],lines:[],after:[]},n=jo(i,t);Eo(e.before,Io(n.beforeLabel.call(this,t))),Eo(e.lines,n.label.call(this,t)),Eo(e.after,Io(n.afterLabel.call(this,t))),s.push(e)})),s}getAfterBody(t,e){return Ho(e.callbacks.afterBody.apply(this,[t]))}getFooter(t,e){const{callbacks:i}=e,s=i.beforeFooter.apply(this,[t]),n=i.footer.apply(this,[t]),o=i.afterFooter.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),Q(l,(e=>{const i=jo(t.callbacks,e);s.push(i.labelColor.call(this,e)),n.push(i.labelPointStyle.call(this,e)),o.push(i.labelTextColor.call(this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Ro[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Fo(this,i),a=Object.assign({},t,e),r=Vo(this.chart,i,a),l=Wo(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=We(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Ei(i.rtl,this.x,this.width);for(t.x=No(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=He(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,oe(t,{x:e,y:g,w:l,h:r,radius:a}),t.fill(),t.stroke(),t.fillStyle=o.backgroundColor,t.beginPath(),oe(t,{x:i,y:g+1,w:l-2,h:r-2,radius:a}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,l,r),t.strokeRect(e,g,l,r),t.fillStyle=o.backgroundColor,t.fillRect(i,g+1,l-2,r-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=He(i.bodyFont);let d=c.lineHeight,u=0;const f=Ei(i.rtl,this.x,this.width),g=function(i){e.fillText(i,f.x(t.x+u),t.y+d/2),t.y+=d+n},p=f.textAlign(o);let m,x,b,_,y,v,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=No(this,p,i),e.fillStyle=i.bodyColor,Q(this.beforeBody,g),u=a&&"right"!==p?"center"===o?l/2+h:l+2+h:0,_=0,v=s.length;_0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Ro[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Fo(this,t),a=Object.assign({},i,this._size),r=Vo(e,t,a),l=Wo(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=Ne(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ii(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),zi(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!tt(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!tt(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e;const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Ro[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}$o.positioners=Ro;var Yo={id:"tooltip",_element:$o,positioners:Ro,afterInit(t,e,i){i&&(t.tooltip=new $o({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip,i={tooltip:e};!1!==t.notifyPlugins("beforeTooltipDraw",i)&&(e&&e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i))},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:{beforeTitle:H,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]},Uo=Object.freeze({__proto__:null,Decimation:ro,Filler:So,Legend:Co,SubTitle:Lo,Title:Ao,Tooltip:Yo});function Xo(t,e,i,s){const n=t.indexOf(e);if(-1===n)return((t,e,i,s)=>("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}class qo extends Bs{constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if($(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:jt(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:Xo(i,t,K(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){const e=this.getLabels();return t>=0&&te.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}}function Ko(t,e,{horizontal:i,minRotation:s}){const n=It(s),o=(i?Math.sin(n):Math.cos(n))||.001,a=.75*e*(""+t).length;return Math.min(e/o,a)}qo.id="category",qo.defaults={ticks:{callback:qo.prototype.getLabelForValue}};class Go extends Bs{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,e){return $(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:e,maxDefined:i}=this.getUserBounds();let{min:s,max:n}=this;const o=t=>s=e?s:t,a=t=>n=i?n:t;if(t){const t=Ct(s),e=Ct(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=1;(n>=Number.MAX_SAFE_INTEGER||s<=Number.MIN_SAFE_INTEGER)&&(e=Math.abs(.05*n)),a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const s=function(t,e){const i=[],{bounds:s,step:n,min:o,max:a,precision:r,count:l,maxTicks:h,maxDigits:c,includeBounds:d}=t,u=n||1,f=h-1,{min:g,max:p}=e,m=!$(o),x=!$(a),b=!$(l),_=(p-g)/(c+1);let y,v,w,M,k=Ot((p-g)/f/u)*u;if(k<1e-14&&!m&&!x)return[{value:g},{value:p}];M=Math.ceil(p/k)-Math.floor(g/k),M>f&&(k=Ot(M*k/f/u)*u),$(r)||(y=Math.pow(10,r),k=Math.ceil(k*y)/y),"ticks"===s?(v=Math.floor(g/k)*k,w=Math.ceil(p/k)*k):(v=g,w=p),m&&x&&n&&Rt((a-o)/n,k/1e3)?(M=Math.round(Math.min((a-o)/k,h)),k=(a-o)/M,v=o,w=a):b?(v=m?o:v,w=x?a:w,M=l-1,k=(w-v)/M):(M=(w-v)/k,M=Lt(M,Math.round(M),k/1e3)?Math.round(M):Math.ceil(M));const S=Math.max(Ft(k),Ft(v));y=Math.pow(10,$(r)?S:r),v=Math.round(v*y)/y,w=Math.round(w*y)/y;let P=0;for(m&&(d&&v!==o?(i.push({value:o}),v0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=X(t)?Math.max(0,t):null,this.max=X(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t,a=(t,e)=>Math.pow(10,Math.floor(Dt(t))+e);i===s&&(i<=0?(n(1),o(10)):(n(a(i,-1)),o(a(s,1)))),i<=0&&n(a(s,-1)),s<=0&&o(a(i,1)),this._zero&&this.min!==this._suggestedMin&&i===a(this.min,0)&&n(a(i,-1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=function(t,e){const i=Math.floor(Dt(e.max)),s=Math.ceil(e.max/Math.pow(10,i)),n=[];let o=q(t.min,Math.pow(10,Math.floor(Dt(e.min)))),a=Math.floor(Dt(o)),r=Math.floor(o/Math.pow(10,a)),l=a<0?Math.pow(10,Math.abs(a)):1;do{n.push({value:o,major:Jo(o)}),++r,10===r&&(r=1,++a,l=a>=0?1:l),o=Math.round(r*Math.pow(10,a)*l)/l}while(an?{start:e-i,end:e}:{start:e,end:e+i}}function ia(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],n=[],o=t._pointLabels.length,a=t.options.pointLabels,r=a.centerPointLabels?_t/o:0;for(let d=0;de.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function na(t){return 0===t||180===t?"center":t<180?"left":"right"}function oa(t,e,i){return"right"===i?t-=e:"center"===i&&(t-=e/2),t}function aa(t,e,i){return 90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e),t}function ra(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,yt);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;o{const i=J(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?ia(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return Nt(t*(yt/(this._pointLabels.length||1))+It(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if($(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if($(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=s.setContext(t.getPointLabelContext(n)),o=He(e.font),{x:a,y:r,textAlign:l,left:h,top:c,right:d,bottom:u}=t._pointLabelItems[n],{backdropColor:f}=e;if(!$(f)){const t=Ne(e.backdropPadding);i.fillStyle=f,i.fillRect(h-t.left,c-t.top,d-h+t.width,u-c+t.height)}se(i,t._pointLabels[n],a,r+o.lineHeight/2,o,{color:e.color,textAlign:l,textBaseline:"middle"})}}(this,n),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e){a=this.getDistanceFromCenterForValue(t.value);!function(t,e,i,s){const n=t.ctx,o=e.circular,{color:a,lineWidth:r}=e;!o&&!s||!a||!r||i<0||(n.save(),n.strokeStyle=a,n.lineWidth=r,n.setLineDash(e.borderDash),n.lineDashOffset=e.borderDashOffset,n.beginPath(),ra(t,i,o,s),n.closePath(),n.stroke(),n.restore())}(this,s.setContext(this.getContext(e-1)),a,n)}})),i.display){for(t.save(),o=n-1;o>=0;o--){const s=i.setContext(this.getPointLabelContext(o)),{color:n,lineWidth:l}=s;l&&n&&(t.lineWidth=l,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,a=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),r=this.getPointPosition(o,a),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(r.x,r.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=He(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=Ne(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}se(t,s.label,0,-n,l,{color:r.color})})),t.restore()}drawTitle(){}}la.id="radialLinear",la.defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Os.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:t=>t,padding:5,centerPointLabels:!1}},la.defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"},la.descriptors={angleLines:{_fallback:"grid"}};const ha={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ca=Object.keys(ha);function da(t,e){return t-e}function ua(t,e){if($(e))return null;const i=t._adapter,{parser:s,round:n,isoWeekday:o}=t._parseOpts;let a=e;return"function"==typeof s&&(a=s(a)),X(a)||(a="string"==typeof s?i.parse(a,s):i.parse(a)),null===a?null:(n&&(a="week"!==n||!Tt(o)&&!0!==o?i.startOf(a,n):i.startOf(a,"isoWeek",o)),+a)}function fa(t,e,i,s){const n=ca.length;for(let o=ca.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function pa(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class ma extends Bs{constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e){const i=t.time||(t.time={}),s=this._adapter=new mn._date(t.adapters.date);ot(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:ua(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:a}=this.getUserBounds();function r(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),a||isNaN(t.max)||(n=Math.max(n,t.max))}o&&a||(r(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||r(this.getMinMax(!1))),s=X(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=X(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=he(s,n,this.max);return this._unit=e.unit||(i.autoSkip?fa(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=ca.length-1;o>=ca.indexOf(i);o--){const i=ca[o];if(ha[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return ca[i?ca.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=ca.indexOf(t)+1,i=ca.length;e1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const f="data"===s.ticks.source&&this.getDataTimestamps();for(c=u,d=0;ct-e)).map((t=>+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.time.displayFormats,a=this._unit,r=this._majorUnit,l=a&&o[a],h=r&&o[r],c=i[e],d=r&&h&&c&&c.major,u=this._adapter.format(t,s||(d?h:l)),f=n.ticks.callback;return f?J(f,[u,e,i],this):u}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=re(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=re(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}ma.id="time",ma.defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",major:{enabled:!1}}};class ba extends ma{constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=xa(e,this.min),this._tableRange=xa(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;ot({chart:e,initial:i.initial,numSteps:n,currentStep:Math.min(a-i.start,n)}))}_refresh(){this._request||(this._running=!0,this._request=requestAnimFrame.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(r=Date.now()){let o=0;this._charts.forEach((a,s)=>{if(a.running&&a.items.length){const n=a.items;let t=n.length-1,e=!1,i;for(;0<=t;--t)(i=n[t])._active?(i._total>a.duration&&(a.duration=i._total),i.tick(r),e=!0):(n[t]=n[n.length-1],n.pop());e&&(s.draw(),this._notify(s,a,r,"progress")),n.length||(a.running=!1,this._notify(s,a,r,"complete"),a.initial=!1),o+=n.length}}),this._lastDate=r,0===o&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return 0Math.max(t,e._duration),0),this._refresh())}running(t){if(!this._running)return!1;t=this._charts.get(t);return!!(t&&t.running&&t.items.length)}stop(e){const i=this._charts.get(e);if(i&&i.items.length){const a=i.items;let t=a.length-1;for(;0<=t;--t)a[t].cancel();i.items=[],this._notify(e,i,Date.now(),"complete")}}remove(t){return this._charts.delete(t)}}var animator=new Animator;const transparent="transparent",interpolators={boolean(t,e,i){return.5{i.push({res:t,rej:e})})}_notify(t){var e=t?"res":"rej";const i=this._promises||[];for(let t=0;t{const t=s[e];if(isObject(t)){const i={};for(const a of n)i[a]=t[a];(isArray(t.properties)&&t.properties||[e]).forEach(t=>{t!==e&&r.has(t)||r.set(t,i)})}})}}_animateOptions(t,e){const i=e.options;e=resolveTargetOptions(t,i);if(!e)return[];e=this._createAnimations(e,i);return i.$shared&&awaitAll(t.options.$animations,i).then(()=>{t.options=i},()=>{}),e}_createAnimations(e,i){const a=this._properties,s=[],n=e.$animations||(e.$animations={});var t=Object.keys(i),r=Date.now();let o;for(o=t.length-1;0<=o;--o){const d=t[o];if("$"!==d.charAt(0))if("options"===d)s.push(...this._animateOptions(e,i));else{var l=i[d];let t=n[d];var h=a.get(d);if(t){if(h&&t.active()){t.update(h,l,r);continue}t.cancel()}h&&h.duration?(n[d]=t=new Animation(h,e,d,l),s.push(t)):e[d]=l}}return s}update(t,e){{if(0!==this._properties.size)return(t=this._createAnimations(t,e)).length?(animator.add(this._chart,t),!0):void 0;Object.assign(t,e)}}}function awaitAll(e,t){const i=[];var a=Object.keys(t);for(let t=0;ti[t].axis===e).shift()}function createDatasetContext(t,e){return createContext(t,{active:!1,dataset:void 0,datasetIndex:e,index:e,mode:"default",type:"dataset"})}function createDataContext(t,e,i){return createContext(t,{active:!1,dataIndex:e,parsed:void 0,raw:void 0,element:i,index:e,mode:"default",type:"data"})}function clearStacks(t,e){var i=t.controller.index,a=t.vScale&&t.vScale.axis;if(a)for(const s of e=e||t._parsed){const n=s._stacks;if(!n||void 0===n[a]||void 0===n[a][i])return;delete n[a][i],void 0!==n[a]._visualValues&&void 0!==n[a]._visualValues[i]&&delete n[a]._visualValues[i]}}const isDirectUpdateMode=t=>"reset"===t||"none"===t,cloneIfNotShared=(t,e)=>e?t:Object.assign({},t),createStack=(t,e,i)=>t&&!e.hidden&&e._stacked&&{keys:getSortedDatasetIndices(i,!0),values:null};class DatasetController{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=isStacked(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&clearStacks(this._cachedMeta),this.index=t}linkScales(){var t=this.chart;const e=this._cachedMeta;var i=this.getDataset(),a=(t,e,i,a)=>"x"===t?e:"r"===t?a:i,s=e.xAxisID=valueOrDefault(i.xAxisID,getFirstScaleId(t,"x")),n=e.yAxisID=valueOrDefault(i.yAxisID,getFirstScaleId(t,"y")),i=e.rAxisID=valueOrDefault(i.rAxisID,getFirstScaleId(t,"r")),t=e.indexAxis,r=e.iAxisID=a(t,s,n,i),a=e.vAxisID=a(t,n,s,i);e.xScale=this.getScaleForId(s),e.yScale=this.getScaleForId(n),e.rScale=this.getScaleForId(i),e.iScale=this.getScaleForId(r),e.vScale=this.getScaleForId(a)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){var e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){var t=this._cachedMeta;this._data&&unlistenArrayEvents(this._data,this),t._stacked&&clearStacks(t)}_dataCheck(){const t=this.getDataset();var e=t.data||(t.data=[]),i=this._data;if(isObject(e))this._data=convertObjectDataToArray(e);else if(i!==e){if(i){unlistenArrayEvents(i,this);const a=this._cachedMeta;clearStacks(a),a._parsed=[]}e&&Object.isExtensible(e)&&listenArrayEvents(e,this),this._syncList=[],this._data=e}}addElements(){const t=this._cachedMeta;this._dataCheck(),this.datasetElementType&&(t.dataset=new this.datasetElementType)}buildOrUpdateElements(t){const e=this._cachedMeta;var i=this.getDataset();let a=!1;this._dataCheck();var s=e._stacked;e._stacked=isStacked(e.vScale,e),e.stack!==i.stack&&(a=!0,clearStacks(e),e.stack=i.stack),this._resyncElements(t),!a&&s===e._stacked||updateStacks(this,e._parsed)}configure(){const t=this.chart.config;var e=t.datasetScopeKeys(this._type),e=t.getOptionScopes(this.getDataset(),e,!0);this.options=t.createResolver(e,this.getContext()),this._parsing=this.options.parsing,this._cachedDataOpts={}}parse(t,e){const{_cachedMeta:i,_data:a}=this;var{iScale:s,_stacked:n}=i;const r=s.axis;let o=0===t&&e===a.length||i._sorted,l=0t||dthis.getContext(i,a,e),h);return d.$shared&&(d.$shared=o,s[n]=Object.freeze(cloneIfNotShared(d,o))),d}_resolveAnimations(t,e,i){var a=this.chart;const s=this._cachedDataOpts;var n="animation-"+e,r=s[n];if(r)return r;let o;if(!1!==a.options.animation){const l=this.chart.config;r=l.datasetAnimationScopeKeys(this._type,e),r=l.getOptionScopes(this.getDataset(),r);o=l.createResolver(r,this.getContext(t,i,e))}r=new Animations(a,o&&o.animations);return o&&o._cacheable&&(s[n]=Object.freeze(r)),r}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||isDirectUpdateMode(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){var t=this.resolveDataElementOptions(t,e),i=this._sharedOptions,a=this.getSharedOptions(t),i=this.includeOptions(e,a)||a!==i;return this.updateSharedOptions(a,e,t),{sharedOptions:a,includeOptions:i}}updateElement(t,e,i,a){isDirectUpdateMode(a)?Object.assign(t,i):this._resolveAnimations(e,a).update(t,i)}updateSharedOptions(t,e,i){t&&!isDirectUpdateMode(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,a){t.active=a;var s=this.getStyle(e,a);this._resolveAnimations(e,i,a).update(t,{options:!a&&this.getSharedOptions(s)||s})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){var e,i,a,s=this._data,n=this._cachedMeta.data;for([e,i,a]of this._syncList)this[e](i,a);this._syncList=[];var n=n.length,s=s.length,r=Math.min(s,n);r&&this.parse(0,r),n{for(t.length+=e,r=t.length-1;r>=n;r--)t[r]=t[r-e]};for(o(s),r=t;rt-e))}return a._cache.$bar}function computeMinSampleSize(t){const e=t.iScale;var i=getAllScaleValues(e,t.type);let a=e._length,s,n,r,o;var l=()=>{32767!==r&&-32768!==r&&(defined(o)&&(a=Math.min(a,Math.abs(r-o)||a)),o=r)};for(s=0,n=i.length;sMath.abs(n)&&(r=n,o=a),e[i.axis]=o,e._custom={barStart:r,barEnd:o,start:s,end:t,min:a,max:n}}function parseValue(t,e,i,a){return isArray(t)?parseFloatBar(t,e,i,a):e[i.axis]=i.parse(t,a),e}function parseArrayOrPrimitive(t,e,i,a){const s=t.iScale;var n=t.vScale,r=s.getLabels(),o=s===n;const l=[];let h,d,c,u;for(d=(h=i)+a;h=i?1:-1)}function borderProps(t){let e,i,a,s,n;return a=t.horizontal?(e=t.base>t.x,i="left","right"):(e=t.baset.controller.options.grouped),s=e.options.stacked;const n=[];for(const r of a)if((void 0===i||!(t=>{var e=t.controller.getParsed(i),e=e&&e[t.vScale.axis];if(isNullOrUndef(e)||isNaN(e))return!0})(r))&&((!1===s||-1===n.indexOf(r.stack)||void 0===s&&void 0===r.stack)&&n.push(r.stack),r.index===t))break;return n.length||n.push(void 0),n}_getStackCount(t){return this._getStacks(void 0,t).length}_getStackIndex(t,e,i){const a=this._getStacks(t,i);t=void 0!==e?a.indexOf(e):-1;return-1===t?a.length-1:t}_getRuler(){var t=this.options,e=this._cachedMeta;const i=e.iScale,a=[];let s,n;for(s=0,n=e.data.length;s_angleBetween(t,u,g,!0)?1:Math.max(e,e*a,i,i*a),d=(t,e,i)=>_angleBetween(t,u,g,!0)?-1:Math.min(e,e*a,i,i*a),c=h(0,t,o),h=h(HALF_PI,e,l),t=d(PI,t,o),o=d(PI+HALF_PI,e,l);i=(c-t)/2,s=(h-o)/2,n=-(c+t)/2,r=-(h+o)/2}return{ratioX:i,ratioY:s,offsetX:n,offsetY:r}}class DoughnutController extends DatasetController{static id="doughnut";static defaults={datasetElementType:!1,dataElementType:"arc",animation:{animateRotate:!0,animateScale:!1},animations:{numbers:{type:"number",properties:["circumference","endAngle","innerRadius","outerRadius","startAngle","x","y","offset","borderWidth","spacing"]}},cutout:"50%",rotation:0,circumference:360,radius:"100%",spacing:0,indexAxis:"r"};static descriptors={_scriptable:t=>"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(s){const t=s.data;if(t.labels.length&&t.datasets.length){const{pointStyle:n,color:r}=s.legend.options["labels"];return t.labels.map((t,e)=>{const i=s.getDatasetMeta(0);var a=i.controller.getStyle(e);return{text:t,fillStyle:a.backgroundColor,strokeStyle:a.borderColor,fontColor:r,lineWidth:a.borderWidth,pointStyle:n,hidden:!s.getDataVisibility(e),index:e}})}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(a,s){const n=this.getDataset().data,r=this._cachedMeta;if(!1===this._parsing)r._parsed=n;else{let t=t=>+n[t];if(isObject(n[a])){const{key:o="value"}=this._parsing;t=t=>+resolveObjectKey(n[t],o)}let e,i;for(i=(e=a)+s;e=v?M.skip=!0:(_=this.getParsed(t),y=isNullOrUndef(_[u]),k=M[c]=n.getPixelForValue(_[c],t),S=M[u]=s||y?r.getBasePixel():r.getPixelForValue(o?this.applyStack(r,_,o):_[u],t),M.skip=isNaN(k)||isNaN(S)||y,M.stop=0f,p&&(M.parsed=_,M.raw=l.data[t]),d&&(M.options=h||this.resolveDataElementOptions(t,D.active?"active":a)),m||this.updateElement(D,t,M,a),b=_)}}getMaxOverflow(){var t=this._cachedMeta,e=t.dataset,e=e.options&&e.options.borderWidth||0;const i=t.data||[];if(!i.length)return e;var t=i[0].size(this.resolveDataElementOptions(0)),a=i[i.length-1].size(this.resolveDataElementOptions(i.length-1));return Math.max(e,t,a)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}}class PolarAreaController extends DatasetController{static id="polarArea";static defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(s){const t=s.data;if(t.labels.length&&t.datasets.length){const{pointStyle:n,color:r}=s.legend.options["labels"];return t.labels.map((t,e)=>{const i=s.getDatasetMeta(0);var a=i.controller.getStyle(e);return{text:t,fillStyle:a.backgroundColor,strokeStyle:a.borderColor,fontColor:r,lineWidth:a.borderWidth,pointStyle:n,hidden:!s.getDataVisibility(e),index:e}})}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){var e=this._cachedMeta,i=this.chart,a=i.data.labels||[],e=formatNumber(e._parsed[t].r,i.options.locale);return{label:a[t]||"",value:e}}parseObjectData(t,e,i,a){return _parseObjectDataRadialScale.bind(this)(t,e,i,a)}update(t){var e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,a={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach((t,e)=>{var i=this.getParsed(e).r;!isNaN(i)&&this.chart.getDataVisibility(e)&&(ia.max&&(a.max=i))}),a}_updateRadius(){const t=this.chart;var e=t.chartArea,i=t.options,e=Math.min(e.right-e.left,e.bottom-e.top),e=Math.max(e/2,0),i=(e-Math.max(i.cutoutPercentage?e/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=e-i*this.index,this.innerRadius=this.outerRadius-i}updateElements(a,t,e,s){var n="reset"===s;const r=this.chart;var o=r.options.animation;const l=this._cachedMeta.rScale;var h=l.xCenter,d=l.yCenter,c=l.getIndexAngle(0)-.5*PI;let u=c,g;var p=360/this.countVisibleElements();for(g=0;g{!isNaN(this.getParsed(e).r)&&this.chart.getDataVisibility(e)&&i++}),i}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?toRadians(this.resolveDataElementOptions(t,e).angle||i):0}}class PieController extends DoughnutController{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}}class RadarController extends DatasetController{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale;var i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,a){return _parseObjectDataRadialScale.bind(this)(t,e,i,a)}update(t){const e=this._cachedMeta,i=e.dataset;var a=e.data||[],s=e.iScale.getLabels();if(i.points=a,"resize"!==t){const n=this.resolveDatasetElementOptions(t);this.options.showLine||(n.borderWidth=0);s={_loop:!0,_fullLoop:s.length===a.length,options:n};this.updateElement(i,void 0,s,t)}this.updateElements(a,0,a.length,t)}updateElements(e,i,a,s){const n=this._cachedMeta.rScale;var r="reset"===s;for(let t=i;tm,f&&(D.parsed=_,D.raw=h.data[t]),c&&(D.options=d||this.resolveDataElementOptions(t,b.active?"active":s)),v||this.updateElement(b,t,D,s),x=_}this.updateSharedOptions(d,s,t)}getMaxOverflow(){var t=this._cachedMeta;const i=t.data||[];if(!this.options.showLine){let e=0;for(let t=i.length-1;0<=t;--t)e=Math.max(e,i[t].size(this.resolveDataElementOptions(t))/2);return 0{t[o](a[s],n)&&(r.push({element:t,datasetIndex:e,index:i}),l=l||t.inRange(a.x,a.y,n))}),e&&!l?[]:r}var Interaction={evaluateInteractionItems:evaluateInteractionItems,modes:{index(t,e,i,a){var e=getRelativePosition(e,t),s=i.axis||"x",n=i.includeInvisible||!1;const r=i.intersect?getIntersectItems(t,e,s,a,n):getNearestItems(t,e,s,!1,a,n),o=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach(t=>{var e=r[0].index,i=t.data[e];i&&!i.skip&&o.push({element:i,datasetIndex:t.index,index:e})}),o):[]},dataset(t,e,i,a){var e=getRelativePosition(e,t),s=i.axis||"xy",n=i.includeInvisible||!1;let r=i.intersect?getIntersectItems(t,e,s,a,n):getNearestItems(t,e,s,!1,a,n);if(0t.pos===e)}function filterDynamicPositionByAxis(t,e){return t.filter(t=>-1===STATIC_POSITIONS.indexOf(t.pos)&&t.box.axis===e)}function sortByWeight(t,a){return t.sort((t,e)=>{var i=a?e:t,t=a?t:e;return i.weight===t.weight?i.index-t.index:i.weight-t.weight})}function wrapBoxes(t){const e=[];let i,a,s,n,r,o;for(i=0,a=(t||[]).length;it.box.fullSize),!0);const i=sortByWeight(filterByPosition(e,"left"),!0),a=sortByWeight(filterByPosition(e,"right")),s=sortByWeight(filterByPosition(e,"top"),!0);var n=sortByWeight(filterByPosition(e,"bottom")),r=filterDynamicPositionByAxis(e,"x"),o=filterDynamicPositionByAxis(e,"y");return{fullSize:t,leftAndTop:i.concat(s),rightAndBottom:a.concat(o).concat(n).concat(r),chartArea:filterByPosition(e,"chartArea"),vertical:i.concat(a).concat(o),horizontal:s.concat(n).concat(r)}}function getCombinedMax(t,e,i,a){return Math.max(t[i],e[i])+Math.max(t[a],e[a])}function updateMaxPadding(t,e){t.top=Math.max(t.top,e.top),t.left=Math.max(t.left,e.left),t.bottom=Math.max(t.bottom,e.bottom),t.right=Math.max(t.right,e.right)}function updateDims(t,e,i,a){const{pos:s,box:n}=i;var r=t.maxPadding;if(!isObject(s)){i.size&&(t[s]-=i.size);const l=a[i.stack]||{size:0,count:1};l.size=Math.max(l.size,i.horizontal?n.height:n.width),i.size=l.size/l.count,t[s]+=i.size}n.getPadding&&updateMaxPadding(r,n.getPadding());var a=Math.max(0,e.outerWidth-getCombinedMax(r,t,"left","right")),e=Math.max(0,e.outerHeight-getCombinedMax(r,t,"top","bottom")),r=a!==t.w,o=e!==t.h;return t.w=a,t.h=e,i.horizontal?{same:r,other:o}:{same:o,other:r}}function handleMaxPadding(i){const a=i.maxPadding;function t(t){var e=Math.max(a[t]-i[t],0);return i[t]+=e,e}i.y+=t("top"),i.x+=t("left"),t("right"),t("bottom")}function getMargins(t,i){const a=i.maxPadding;function e(t){const e={left:0,top:0,right:0,bottom:0};return t.forEach(t=>{e[t]=Math.max(i[t],a[t])}),e}return e(t?["left","right"]:["top","bottom"])}function fitBoxes(t,e,i,a){const s=[];let n,r,o,l,h,d;for(n=0,r=t.length,h=0;n{"function"==typeof t.beforeLayout&&t.beforeLayout()}),d.reduce((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1,0)||1),t=Object.freeze({outerWidth:t,outerHeight:e,padding:s,availableWidth:n,availableHeight:r,vBoxMaxWidth:n/2/h,hBoxMaxHeight:r/2}),e=Object.assign({},s);updateMaxPadding(e,toPadding(a));const c=Object.assign({maxPadding:e,w:n,h:r,x:s.left,y:s.top},s);h=setLayoutDims(d.concat(l),t);fitBoxes(o.fullSize,c,t,h),fitBoxes(d,c,t,h),fitBoxes(l,c,t,h)&&fitBoxes(d,c,t,h),handleMaxPadding(c),placeBoxes(o.leftAndTop,c,t,h),c.x+=c.w,c.y+=c.h,placeBoxes(o.rightAndBottom,c,t,h),i.chartArea={left:c.left,top:c.top,right:c.left+c.w,bottom:c.top+c.h,height:c.h,width:c.w},each(o.chartArea,t=>{const e=t.box;Object.assign(e,i.chartArea),e.update(c.w,c.h,{left:0,top:0,right:0,bottom:0})})}}};class BasePlatform{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,a){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,a?Math.floor(e/a):i)}}isAttached(t){return!0}updateConfig(t){}}class BasicPlatform extends BasePlatform{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const EXPANDO_KEY="$chartjs",EVENT_TYPES={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},isNullOrEmpty=t=>null===t||""===t;function initCanvas(t,e){const i=t.style;var a=t.getAttribute("height"),s=t.getAttribute("width");return t[EXPANDO_KEY]={initial:{height:a,width:s,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",isNullOrEmpty(s)&&void 0!==(s=readUsedSize(t,"width"))&&(t.width=s),isNullOrEmpty(a)&&(""===t.style.height?t.height=t.width/(e||2):void 0!==(s=readUsedSize(t,"height"))&&(t.height=s)),t}const eventListenerOptions=!!supportsEventListenerOptions&&{passive:!0};function addListener(t,e,i){t.addEventListener(e,i,eventListenerOptions)}function removeListener(t,e,i){t.canvas.removeEventListener(e,i,eventListenerOptions)}function fromNativeEvent(t,e){var i=EVENT_TYPES[t.type]||t.type,{x:a,y:s}=getRelativePosition(t,e);return{type:i,chart:e,native:t,x:void 0!==a?a:null,y:void 0!==s?s:null}}function nodeListContains(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function createAttachObserver(t,e,a){const s=t.canvas,i=new MutationObserver(t=>{let e=!1;for(const i of t)e=(e=e||nodeListContains(i.addedNodes,s))&&!nodeListContains(i.removedNodes,s);e&&a()});return i.observe(document,{childList:!0,subtree:!0}),i}function createDetachObserver(t,e,a){const s=t.canvas,i=new MutationObserver(t=>{let e=!1;for(const i of t)e=(e=e||nodeListContains(i.removedNodes,s))&&!nodeListContains(i.addedNodes,s);e&&a()});return i.observe(document,{childList:!0,subtree:!0}),i}const drpListeningCharts=new Map;let oldDevicePixelRatio=0;function onWindowResize(){const i=window.devicePixelRatio;i!==oldDevicePixelRatio&&(oldDevicePixelRatio=i,drpListeningCharts.forEach((t,e)=>{e.currentDevicePixelRatio!==i&&t()}))}function listenDevicePixelRatioChanges(t,e){drpListeningCharts.size||window.addEventListener("resize",onWindowResize),drpListeningCharts.set(t,e)}function unlistenDevicePixelRatioChanges(t){drpListeningCharts.delete(t),drpListeningCharts.size||window.removeEventListener("resize",onWindowResize)}function createResizeObserver(t,e,a){var i=t.canvas;const s=i&&_getParentNode(i);if(s){const n=throttled((t,e)=>{var i=s.clientWidth;a(t,e),i{var t=t[0],e=t.contentRect.width,t=t.contentRect.height;0===e&&0===t||n(e,t)});return r.observe(s),listenDevicePixelRatioChanges(t,n),r}}function releaseObserver(t,e,i){i&&i.disconnect(),"resize"===e&&unlistenDevicePixelRatioChanges(t)}function createProxyAndListen(e,t,i){var a=e.canvas,s=throttled(t=>{null!==e.ctx&&i(fromNativeEvent(t,e))},e);return addListener(a,t,s),s}class DomPlatform extends BasePlatform{acquireContext(t,e){var i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(initCanvas(t,e),i):null}releaseContext(t){const i=t.canvas;if(!i[EXPANDO_KEY])return!1;const a=i[EXPANDO_KEY].initial,e=(["height","width"].forEach(t=>{var e=a[t];isNullOrUndef(e)?i.removeAttribute(t):i.setAttribute(t,e)}),a.style||{});return Object.keys(e).forEach(t=>{i.style[t]=e[t]}),i.width=i.width,delete i[EXPANDO_KEY],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const a=t.$proxies||(t.$proxies={});const s={attach:createAttachObserver,detach:createDetachObserver,resize:createResizeObserver}[e]||createProxyAndListen;a[e]=s(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={});var a=i[e];if(a){const s={attach:releaseObserver,detach:releaseObserver,resize:releaseObserver}[e]||removeListener;s(t,e,a),i[e]=void 0}}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,a){return getMaximumSize(t,e,i,a)}isAttached(t){t=_getParentNode(t);return!(!t||!t.isConnected)}}function _detectPlatform(t){return!_isDomSupported()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?BasicPlatform:DomPlatform}class Element{static defaults={};static defaultRoutes=void 0;x;y;active=!1;options;$animations;tooltipPosition(t){var{x:t,y:e}=this.getProps(["x","y"],t);return{x:t,y:e}}hasValue(){return isNumber(this.x)&&isNumber(this.y)}getProps(t,e){const i=this.$animations;if(!e||!i)return this;const a={};return t.forEach(t=>{a[t]=i[t]&&i[t].active()?i[t]._to:this[t]}),a}}function autoSkip(i,a){var s=i.options.ticks,i=determineMaxTicks(i),i=Math.min(s.maxTicksLimit||i,i),n=s.major.enabled?getMajorIndices(a):[],s=n.length,r=n[0],o=n[s-1],l=[];if(i"left"===t?"right":"right"===t?"left":t,offsetFromEdge=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i,getTicksLimit=(t,e)=>Math.min(e||t,t);function sample(t,e){const i=[];var a=t.length/e,s=t.length;let n=0;for(;nr+1e-6)))return o}function garbageCollect(t,s){each(t,t=>{const e=t.gc;var i=e.length/2;let a;if(ss?s:a,s=n&&a>s?a:s,{min:finiteOrDefault(a,finiteOrDefault(s,a)),max:finiteOrDefault(s,finiteOrDefault(a,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){callback(this.options.beforeUpdate,[this])}update(t,e,i){var{beginAtZero:a,grace:s,ticks:n}=this.options,r=n.sampleSize,t=(this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=_addGrace(this,s,a),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks(),r({width:n[t]||0,height:r[t]||0});return{first:k(0),last:k(e-1),widest:k(i),highest:k(y),widths:n,heights:r}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);t=this._startPixel+t*this._length;return _int16Range(this._alignToPixels?_alignPixel(this.chart,t,0):t)}getDecimalForPixel(t){t=(t-this._startPixel)/this._length;return this._reversePixels?1-t:t}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){var{min:t,max:e}=this;return t<0&&e<0?e:0t.value===e);return 0<=a?t.setContext(this.getContext(a)).lineWidth:0}drawGrid(t){var e=this.options.grid;const a=this.ctx;var i=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let s,n;var r=(t,e,i)=>{i.width&&i.color&&(a.save(),a.lineWidth=i.width,a.strokeStyle=i.color,a.setLineDash(i.borderDash||[]),a.lineDashOffset=i.borderDashOffset,a.beginPath(),a.moveTo(t.x,t.y),a.lineTo(e.x,e.y),a.stroke(),a.restore())};if(e.display)for(s=0,n=i.length;s{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:t,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){var e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID";const a=[];let s,n;for(s=0,n=e.length;s{const e=t.split(".");var i=e.pop(),a=[r].concat(e).join(".");const s=o[t].split(".");var t=s.pop(),n=s.join(".");defaults.route(a,i,n,t)})}function isIChartComponent(t){return"id"in t&&"defaults"in t}class Registry{constructor(){this.controllers=new TypedRegistry(DatasetController,"datasets",!0),this.elements=new TypedRegistry(Element,"elements"),this.plugins=new TypedRegistry(Object,"plugins"),this.scales=new TypedRegistry(Scale,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(i,t,a){[...t].forEach(t=>{const e=a||this._getRegistryForType(t);a||e.isForType(t)||e===this.plugins&&t.id?this._exec(i,e,t):each(t,t=>{var e=a||this._getRegistryForType(t);this._exec(i,e,t)})})}_exec(t,e,i){var a=_capitalize(t);callback(i["before"+a],[],i),e[t](i),callback(i["after"+a],[],i)}_getRegistryForType(e){for(let t=0;tt.filter(e=>!i.some(t=>e.plugin.id===t.plugin.id));this._notify(a(e,i),t,"stop"),this._notify(a(i,e),t,"start")}}function allPlugins(t){const e={},i=[];var a=Object.keys(registry.plugins.items);for(let t=0;tt.xAxisID===e||t.yAxisID===e);if(t.length)return getAxisFromDataset(e,"x",t[0])||getAxisFromDataset(e,"y",t[0])}return{}}function mergeScaleConfig(r,e){const n=overrides[r.type]||{scales:{}},o=e.scales||{},l=getIndexAxis(r.type,e),h=Object.create(null);return Object.keys(o).forEach(t=>{var e=o[t];if(!isObject(e))return console.error("Invalid scale configuration for scale: "+t);if(e._proxy)return console.warn("Ignoring resolver passed as options for scale: "+t);var i=determineAxis(t,e,retrieveAxisFromDatasets(t,r),defaults.scales[e.type]),a=getDefaultScaleIDFromAxis(i,l),s=n.scales||{};h[t]=mergeIf(Object.create(null),[{axis:i},e,s[i],s[a]])}),r.data.datasets.forEach(a=>{var t=a.type||r.type;const s=a.indexAxis||getIndexAxis(t,e),n=(overrides[t]||{}).scales||{};Object.keys(n).forEach(t=>{var e=getAxisFromDefaultScaleID(t,s),i=a[e+"AxisID"]||e;h[i]=h[i]||Object.create(null),mergeIf(h[i],[{axis:e},o[i],n[t]])})}),Object.keys(h).forEach(t=>{t=h[t];mergeIf(t,[defaults.scales[t.type],defaults.scale])}),h}function initOptions(t){const e=t.options||(t.options={});e.plugins=valueOrDefault(e.plugins,{}),e.scales=mergeScaleConfig(t,e)}function initData(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}function initConfig(t){return(t=t||{}).data=initData(t.data),initOptions(t),t}const keyCache=new Map,keysCached=new Set;function cachedKeys(t,e){let i=keyCache.get(t);return i||(i=e(),keyCache.set(t,i),keysCached.add(i)),i}const addIfFound=(t,e,i)=>{e=resolveObjectKey(e,i);void 0!==e&&t.add(e)};class Config{constructor(t){this._config=initConfig(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=initData(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){var t=this._config;this.clearCache(),initOptions(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return cachedKeys(t,()=>[["datasets."+t,""]])}datasetAnimationScopeKeys(t,e){return cachedKeys(t+".transition."+e,()=>[[`datasets.${t}.transitions.`+e,"transitions."+e],["datasets."+t,""]])}datasetElementScopeKeys(t,e){return cachedKeys(t+"-"+e,()=>[[`datasets.${t}.elements.`+e,"datasets."+t,"elements."+e,""]])}pluginScopeKeys(t){const e=t.id;return cachedKeys(this.type+"-plugin-"+e,()=>[["plugins."+e,...t.additionalOptionScopes||[]]])}_cachedScopes(t,e){const i=this._scopeCache;let a=i.get(t);return a&&!e||(a=new Map,i.set(t,a)),a}getOptionScopes(e,t,i){const{options:a,type:s}=this,n=this._cachedScopes(e,i);i=n.get(t);if(i)return i;const r=new Set,o=(t.forEach(t=>{e&&(r.add(e),t.forEach(t=>addIfFound(r,e,t))),t.forEach(t=>addIfFound(r,a,t)),t.forEach(t=>addIfFound(r,overrides[s]||{},t)),t.forEach(t=>addIfFound(r,defaults,t)),t.forEach(t=>addIfFound(r,descriptors,t))}),Array.from(r));return 0===o.length&&o.push(Object.create(null)),keysCached.has(t)&&n.set(t,o),o}chartOptionScopes(){var{options:t,type:e}=this;return[t,overrides[e]||{},defaults.datasets[e]||{},{type:e},defaults,descriptors]}resolveNamedOptions(t,e,i,a=[""]){const s={$shared:!0};var{resolver:a,subPrefixes:n}=getResolver(this._resolverCache,t,a);let r=a;needContext(a,e)&&(s.$shared=!1,i=isFunction(i)?i():i,t=this.createResolver(t,i,n),r=_attachContext(a,i,t));for(const o of e)s[o]=r[o];return s}createResolver(t,e,i=[""],a){t=getResolver(this._resolverCache,t,i).resolver;return isObject(e)?_attachContext(t,e,void 0,a):t}}function getResolver(t,e,i){let a=t.get(e);a||(a=new Map,t.set(e,a));t=i.join();let s=a.get(t);return s||(e=_createResolver(e,i),s={resolver:e,subPrefixes:i.filter(t=>!t.toLowerCase().includes("hover"))},a.set(t,s)),s}const hasFunction=i=>isObject(i)&&Object.getOwnPropertyNames(i).reduce((t,e)=>t||isFunction(i[e]),!1);function needContext(t,e){const{isScriptable:i,isIndexable:a}=_descriptors(t);for(const o of e){var s=i(o),n=a(o),r=(n||s)&&t[o];if(s&&(isFunction(r)||hasFunction(r))||n&&isArray(r))return!0}return!1}var version="4.3.0";const KNOWN_POSITIONS=["top","bottom","left","right","chartArea"];function positionIsHorizontal(t,e){return"top"===t||"bottom"===t||-1===KNOWN_POSITIONS.indexOf(t)&&"x"===e}function compare2Level(i,a){return function(t,e){return t[i]===e[i]?t[a]-e[a]:t[i]-e[i]}}function onAnimationsComplete(t){const e=t.chart;var i=e.options.animation;e.notifyPlugins("afterRender"),callback(i&&i.onComplete,[t],e)}function onAnimationProgress(t){var e=t.chart,i=e.options.animation;callback(i&&i.onProgress,[t],e)}function getCanvas(t){return _isDomSupported()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t=t&&t.canvas?t.canvas:t}const instances={},getChart=t=>{const e=getCanvas(t);return Object.values(instances).filter(t=>t.canvas===e).pop()};function moveNumericKeys(t,e,i){for(const n of Object.keys(t)){var a,s=+n;e<=s&&(a=t[n],delete t[n],(0this.update(t),t.resizeDelay||0),this._dataChanges=[],instances[this.id]=this,e&&a?(animator.listen(this,"complete",onAnimationsComplete),animator.listen(this,"progress",onAnimationProgress),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){var{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:a,_aspectRatio:s}=this;return isNullOrUndef(t)?e&&s?s:a?i/a:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return registry}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():retinaScale(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return clearCanvas(this.canvas,this.ctx),this}stop(){return animator.stop(this),this}resize(t,e){animator.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){var i=this.options,a=this.canvas,s=i.maintainAspectRatio&&this.aspectRatio,a=this.platform.getMaximumSize(a,t,e,s),t=i.devicePixelRatio||this.platform.getDevicePixelRatio(),e=this.width?"resize":"attach";this.width=a.width,this.height=a.height,this._aspectRatio=this.aspectRatio,retinaScale(this,t,!0)&&(this.notifyPlugins("resize",{size:a}),callback(i.onResize,[this,a],this),this.attached&&this._doResize(e)&&this.render())}ensureScalesHaveIDs(){var t=this.options.scales||{};each(t,(t,e)=>{t.id=e})}buildOrUpdateScales(){const o=this.options,a=o.scales,l=this.scales,h=Object.keys(l).reduce((t,e)=>(t[e]=!1,t),{});let t=[];a&&(t=t.concat(Object.keys(a).map(t=>{var e=a[t],t=determineAxis(t,e),i="r"===t,t="x"===t;return{options:e,dposition:i?"chartArea":t?"bottom":"left",dtype:i?"radialLinear":t?"category":"linear"}}))),each(t,t=>{const e=t.options;var i=e.id,a=determineAxis(i,e),s=valueOrDefault(e.type,t.dtype);void 0!==e.position&&positionIsHorizontal(e.position,a)===positionIsHorizontal(t.dposition)||(e.position=t.dposition),h[i]=!0;let n=null;if(i in l&&l[i].type===s)n=l[i];else{const r=registry.getScale(s);n=new r({id:i,type:s,ctx:this.ctx,chart:this}),l[n.id]=n}n.init(e,o)}),each(h,(t,e)=>{t||delete l[e]}),each(l,t=>{layouts.configure(this,t,t.options),layouts.addBox(this,t)})}_updateMetasets(){const t=this._metasets;var e=this.data.datasets.length,i=t.length;if(t.sort((t,e)=>t.index-e.index),ei.length&&delete this._stacks,t.forEach((e,t)=>{0===i.filter(t=>t===e._dataset).length&&this._destroyDatasetMeta(t)})}buildOrUpdateControllers(){const e=[];var i=this.data.datasets;let a,t;for(this._removeUnreferencedMetasets(),a=0,t=i.length;a{this.getDatasetMeta(e).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();var a=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!a.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1!==this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0})){const r=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let i=0;for(let t=0,e=this.data.datasets.length;t{t.reset()}),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(compare2Level("z","_idx"));var{_active:a,_lastEvent:t}=this;t?this._eventHandler(t,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}}_updateScales(){each(this.scales,t=>{layouts.removeBox(this,t)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){var t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);setsEqual(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){var t,e,i,a=this["_hiddenIndices"];for({method:t,start:e,count:i}of this._getUniformDataChanges()||[]){var s="_removeElements"===t?-i:i;moveNumericKeys(a,e,s)}}_getUniformDataChanges(){const t=this._dataChanges;if(t&&t.length){this._dataChanges=[];var e=this.data.datasets.length,i=e=>new Set(t.filter(t=>t[0]===e).map((t,e)=>e+","+t.splice(1).join(","))),a=i(0);for(let t=1;tt.split(",")).map(t=>({method:t[1],start:+t[2],count:+t[3]}))}}_updateLayout(t){if(!1!==this.notifyPlugins("beforeLayout",{cancelable:!0})){layouts.update(this,this.width,this.height,t);t=this.chartArea;const e=t.width<=0||t.height<=0;this._layers=[],each(this.boxes,t=>{e&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))},this),this._layers.forEach((t,e)=>{t._idx=e}),this.notifyPlugins("afterLayout")}}_updateDatasets(i){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:i,cancelable:!0})){for(let t=0,e=this.data.datasets.length;tt&&t._dataset===e).pop();return a||(a={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(a)),a}getContext(){return this.$context||(this.$context=createContext(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){var e=this.data.datasets[t];if(!e)return!1;t=this.getDatasetMeta(t);return"boolean"==typeof t.hidden?!t.hidden:!e.hidden}setDatasetVisibility(t,e){const i=this.getDatasetMeta(t);i.hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(e,t,i){const a=i?"show":"hide",s=this.getDatasetMeta(e),n=s.controller._resolveAnimations(void 0,a);defined(t)?(s.data[t].hidden=!i,this.update()):(this.setDatasetVisibility(e,i),n.update(s,{visible:i}),this.update(t=>t.datasetIndex===e?a:void 0))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),animator.remove(this),t=0,e=this.data.datasets.length;t{a.addEventListener(this,t,e),i[t]=e},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};each(this.options.events,t=>e(t,s))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const i=this._responsiveListeners,a=this.platform,t=(t,e)=>{a.addEventListener(this,t,e),i[t]=e},e=(t,e)=>{i[t]&&(a.removeEventListener(this,t,e),delete i[t])},s=(t,e)=>{this.canvas&&this.resize(t,e)};let n;const r=()=>{e("attach",r),this.attached=!0,this.resize(),t("resize",s),t("detach",n)};n=()=>{this.attached=!1,e("resize",s),this._stop(),this._resize(0,0),t("attach",r)},(a.isAttached(this.canvas)?r:n)()}unbindEvents(){each(this._listeners,(t,e)=>{this.platform.removeEventListener(this,e,t)}),this._listeners={},each(this._responsiveListeners,(t,e)=>{this.platform.removeEventListener(this,e,t)}),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){var a=i?"set":"remove";let s,n,r,o;for("dataset"===e&&(s=this.getDatasetMeta(t[0].datasetIndex)).controller["_"+a+"DatasetHoverStyle"](),r=0,o=t.length;r{var i=this.getDatasetMeta(t);if(i)return{datasetIndex:t,element:i.data[e],index:e};throw new Error("No dataset found at index "+t)});_elementsEqual(t,e)||(this._active=t,this._lastEvent=null,this._updateHoverStyles(t,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(e){return 1===this._plugins._cache.filter(t=>t.plugin.id===e).length}_updateHoverStyles(t,e,i){var a=this.options.hover,s=(t,i)=>t.filter(e=>!i.some(t=>e.datasetIndex===t.datasetIndex&&e.index===t.index)),n=s(e,t),i=i?t:s(t,e);n.length&&this.updateHoverStyle(n,a.mode,!1),i.length&&a.mode&&this.updateHoverStyle(i,a.mode,!0)}_eventHandler(e,t){const i={event:e,replay:t,cancelable:!0,inChartArea:this.isPointInArea(e)};var a=t=>(t.options.events||this.options.events).includes(e.native.type);if(!1!==this.notifyPlugins("beforeEvent",i,a))return t=this._handleEvent(e,t,i.inChartArea),i.cancelable=!1,this.notifyPlugins("afterEvent",i,a),(t||i.changed)&&this.render(),this}_handleEvent(t,e,i){var{_active:a=[],options:s}=this,n=this._getActiveElements(t,a,i,e),r=_isClickEvent(t),o=determineLastEvent(t,this._lastEvent,i,r),i=(i&&(this._lastEvent=null,callback(s.onHover,[t,n,this],this),r&&callback(s.onClick,[t,n,this],this)),!_elementsEqual(n,a));return(i||e)&&(this._active=n,this._updateHoverStyles(n,a,e)),this._lastEvent=o,i}_getActiveElements(t,e,i,a){if("mouseout"===t.type)return[];if(!i)return e;i=this.options.hover;return this.getElementsAtEventForMode(t,i.mode,i,a)}}function invalidatePlugins(){return each(Chart.instances,t=>t._plugins.invalidate())}function clipArc(t,e,i){var{startAngle:e,pixelMargin:a,x:s,y:n,outerRadius:r,innerRadius:o}=e,l=a/r;t.beginPath(),t.arc(s,n,r,e-l,i+l),a{var e=(i-Math.min(s,t))*a/2;return _limitValue(t,0,Math.min(s,e))};return{outerStart:n(t.outerStart),outerEnd:n(t.outerEnd),innerStart:_limitValue(t.innerStart,0,e),innerEnd:_limitValue(t.innerEnd,0,e)}}function rThetaToXY(t,e,i,a){return{x:i+t*Math.cos(e),y:a+t*Math.sin(e)}}function pathArc(t,e,i,a,s,n){var{x:r,y:o,startAngle:l,pixelMargin:h,innerRadius:d}=e,c=Math.max(e.outerRadius+a+i-h,0),h=0"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){var a=this.getProps(["x","y"],i),{angle:a,distance:t}=getAngleFromPoint(a,{x:t,y:e}),{startAngle:e,endAngle:i,innerRadius:s,outerRadius:n,circumference:r}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),o=(this.options.spacing+this.options.borderWidth)/2,r=valueOrDefault(r,i-e),r=TAU<=r||_angleBetween(a,e,i),a=_isBetween(t,s+o,n+o);return r&&a}getCenterPoint(t){var{x:t,y:e,startAngle:i,endAngle:a,innerRadius:s,outerRadius:n}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:o}=this.options,i=(i+a)/2,a=(s+n+o+r)/2;return{x:t+Math.cos(i)*a,y:e+Math.sin(i)*a}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){var e,{options:i,circumference:a}=this,s=(i.offset||0)/4,n=(i.spacing||0)/2,r=i.circular;this.pixelMargin="inner"===i.borderAlign?.33:0,this.fullCircles=TAU(r+(h?o-t:t))%n,k=()=>{f!==m&&(t.lineTo(d,m),t.lineTo(d,f),t.lineTo(d,v))};for(l&&(g=s[y(0)],t.moveTo(g.x,g.y)),u=0;u<=o;++u)(g=s[y(u)]).skip||(x=g.x,b=g.y,(_=0|x)===p?(bm&&(m=b),d=(c*d+x)/++c):(k(),t.lineTo(x,b),p=_,c=0,f=m=b),v=b);k()}function _getSegmentMethod(t){var e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?fastPathSegment:pathSegment}function _getInterpolationMethod(t){return t.stepped?_steppedInterpolation:t.tension||"monotone"===t.cubicInterpolationMode?_bezierInterpolation:_pointInLine}function strokePathWithCache(t,e,i,a){let s=e._path;s||(s=e._path=new Path2D,e.path(s,i,a)&&s.closePath()),setStyle(t,e.options),t.stroke(s)}function strokePathDirect(t,e,i,a){var{segments:s,options:n}=e;const r=_getSegmentMethod(e);for(const o of s)setStyle(t,n,o.style),t.beginPath(),r(t,e,o,{start:i,end:i+a-1})&&t.closePath(),t.stroke()}const usePath2D="function"==typeof Path2D;function draw(t,e,i,a){(usePath2D&&!e.options.segment?strokePathWithCache:strokePathDirect)(t,e,i,a)}class LineElement extends Element{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){var i,a=this.options;!a.tension&&"monotone"!==a.cubicInterpolationMode||a.stepped||this._pointsUpdated||(i=a.spanGaps?this._loop:this._fullLoop,_updateBezierControlPoints(this._points,a,t,i,e),this._pointsUpdated=!0)}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=_computeSegments(this,this.options.segment))}first(){var t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){var t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(i,a){var s=this.options,n=i[a],r=this.points,o=_boundSegments(this,{property:a,start:n,end:n});if(o.length){const c=[],u=_getInterpolationMethod(s);let t,e;for(t=0,e=o.length;tt.replace("rgb(","rgba(").replace(")",", 0.5)"));function getBorderColor(t){return BORDER_COLORS[t%BORDER_COLORS.length]}function getBackgroundColor(t){return BACKGROUND_COLORS[t%BACKGROUND_COLORS.length]}function colorizeDefaultDataset(t,e){return t.borderColor=getBorderColor(e),t.backgroundColor=getBackgroundColor(e),++e}function colorizeDoughnutDataset(t,e){return t.backgroundColor=t.data.map(()=>getBorderColor(e++)),e}function colorizePolarAreaDataset(t,e){return t.backgroundColor=t.data.map(()=>getBackgroundColor(e++)),e}function getColorizer(i){let a=0;return(t,e)=>{e=i.getDatasetMeta(e).controller;e instanceof DoughnutController?a=colorizeDoughnutDataset(t,a):e instanceof PolarAreaController?a=colorizePolarAreaDataset(t,a):e&&(a=colorizeDefaultDataset(t,a))}}function containsColorsDefinitions(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}function containsColorsDefinition(t){return t&&(t.borderColor||t.backgroundColor)}var plugin_colors={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(i.enabled){const{data:{datasets:s},options:n}=t.config;var a=n["elements"];!i.forceOverride&&(containsColorsDefinitions(s)||containsColorsDefinition(n)||a&&containsColorsDefinitions(a))||(i=getColorizer(t),s.forEach(i))}}};function lttbDecimation(a,s,n,t,e){var i=e.samples||t;if(n<=i)return a.slice(s,s+n);const r=[];var o=(n-2)/(i-2);let l=0;e=s+n-1;let h=s,d,c,u,g,p;for(r[l++]=a[h],d=0;du&&(u=g,c=a[i],p=i);r[l++]=c,h=p}return r[l++]=a[e],r}function minMaxDecimation(t,e,i,a){let s=0,n=0,r,o,l,h,d,c,u,g,p,f;const m=[];var v=t[e].x,x=t[e+i-1].x-v;for(r=e;rf&&(f=h,u=r),s=(n*s+o.x)/++n):(b=r-1,isNullOrUndef(c)||isNullOrUndef(u)||(_=Math.min(c,u),y=Math.max(c,u),_!==g&&_!==b&&m.push({...t[_],x:s}),y!==g&&y!==b&&m.push({...t[y],x:s})),0{cleanDecimatedDataset(t)})}function getStartAndCountOfVisiblePointsSimplified(t,e){var i=e.length;let a=0,s;const n=t["iScale"];var{min:t,max:r,minDefined:o,maxDefined:l}=n.getUserBounds();return o&&(a=_limitValue(_lookupByKey(e,n.axis,t).lo,0,i-1)),s=l?_limitValue(_lookupByKey(e,n.axis,r).hi+1,a,i)-a:i-a,{start:a,count:s}}var plugin_decimation={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(o,t,l)=>{if(l.enabled){const h=o.width;o.data.datasets.forEach((e,t)=>{var{_data:i,indexAxis:a}=e,t=o.getDatasetMeta(t),s=i||e.data;if("y"!==resolve([a,o.options.indexAxis])&&t.controller.supportsDecimation){a=o.scales[t.xAxisID];if(("linear"===a.type||"time"===a.type)&&!o.options.parsing){var{start:n,count:r}=getStartAndCountOfVisiblePointsSimplified(t,s);if(r<=(l.threshold||4*h))cleanDecimatedDataset(e);else{isNullOrUndef(i)&&(e._data=s,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}}));let t;switch(l.algorithm){case"lttb":t=lttbDecimation(s,n,r,h,l);break;case"min-max":t=minMaxDecimation(s,n,r,h);break;default:throw new Error(`Unsupported decimation algorithm '${l.algorithm}'`)}e._decimated=t}}}})}else cleanDecimatedData(o)},destroy(t){cleanDecimatedData(t)}};function _segments(t,e,i){var a=t.segments,s=t.points,n=e.points;const r=[];for(const c of a){var{start:o,end:l}=c,l=_findSegmentEnd(o,l,s),h=_getBounds(i,s[o],s[l],c.loop);if(e.segments)for(const u of _boundSegments(e,h)){var d=_getBounds(i,n[u.start],n[u.end],u.loop);for(const g of _boundSegment(c,s,d))r.push({source:g,target:u,start:{[i]:_getEdge(h,d,"start",Math.max)},end:{[i]:_getEdge(h,d,"end",Math.min)}})}else r.push({source:c,target:h,start:s[o],end:s[l]})}return r}function _getBounds(i,a,s,t){if(!t){let t=a[i],e=s[i];return"angle"===i&&(t=_normalizeAngle(t),e=_normalizeAngle(e)),{property:i,start:t,end:e}}}function _pointsFromSegments(t,e){const{x:i=null,y:a=null}=t||{},s=e.points,n=[];return e.segments.forEach(({start:t,end:e})=>{e=_findSegmentEnd(t,e,s);t=s[t],e=s[e];null!==a?(n.push({x:t.x,y:a}),n.push({x:e.x,y:a})):null!==i&&(n.push({x:i,y:t.y}),n.push({x:i,y:e.y}))}),n}function _findSegmentEnd(t,e,i){for(;t{let{boxHeight:i=e,boxWidth:a=e}=t;return t.usePointStyle&&(i=Math.min(i,e),a=t.pointStyleWidth||Math.min(a,e)),{boxWidth:a,boxHeight:i,itemHeight:Math.max(e,i)}},itemsEqual=(t,e)=>null!==t&&null!==e&&t.datasetIndex===e.datasetIndex&&t.index===e.index;class Legend extends Element{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const i=this.options.labels||{};let t=callback(i.generateLabels,[this.chart],this)||[];i.filter&&(t=t.filter(t=>i.filter(t,this.chart.data))),i.sort&&(t=t.sort((t,e)=>i.sort(t,e,this.chart.data))),this.options.reverse&&t.reverse(),this.legendItems=t}fit(){const{options:i,ctx:a}=this;if(i.display){var s=i.labels,n=toFont(s.font),r=n.size,o=this._computeTitleHeight(),{boxWidth:s,itemHeight:l}=getBoxSize(s,r);let t,e;a.font=n.string,this.isHorizontal()?(t=this.maxWidth,e=this._fitRows(o,r,s,l)+10):(e=this.maxHeight,t=this._fitCols(o,n,s,l)+10),this.width=Math.min(t,i.maxWidth||this.maxWidth),this.height=Math.min(e,i.maxHeight||this.maxHeight)}else this.width=this.height=0}_fitRows(t,i,a,s){const{ctx:n,maxWidth:r,options:{labels:{padding:o}}}=this,l=this.legendHitBoxes=[],h=this.lineWidths=[0],d=s+o;let c=t,u=(n.textAlign="left",n.textBaseline="middle",-1),g=-d;return this.legendItems.forEach((t,e)=>{t=a+i/2+n.measureText(t.text).width;(0===e||h[h.length-1]+t+2*o>r)&&(c+=d,h[h.length-(0{var{itemWidth:t,itemHeight:i}=calculateItemSize(s,a,r,t,n);0d&&(c+=u+o,h.push({width:u,height:g}),p+=u+o,f++,u=g=0),l[e]={left:p,top:g,col:f,width:t,height:i},u=Math.max(u,t),g+=i+o}),c+=u,h.push({width:u,height:g}),c}adjustHitBoxes(){if(this.options.display){var i=this._computeTitleHeight(),{legendHitBoxes:a,options:{align:s,labels:{padding:n},rtl:t}}=this;const r=getRtlAdapter(t,this.left,this.width);if(this.isHorizontal()){let t=0,e=_alignStartEnd(s,this.left+n,this.right-this.lineWidths[t]);for(const o of a)t!==o.row&&(t=o.row,e=_alignStartEnd(s,this.left+n,this.right-this.lineWidths[t])),o.top+=this.top+i+n,o.left=r.leftForLtr(r.x(e),o.width),e+=o.width+n}else{let t=0,e=_alignStartEnd(s,this.top+i+n,this.bottom-this.columnSizes[t].height);for(const l of a)l.col!==t&&(t=l.col,e=_alignStartEnd(s,this.top+i+n,this.bottom-this.columnSizes[t].height)),l.top=e,l.left+=this.left+n,l.left=r.leftForLtr(r.x(l.left),l.width),e+=l.height+n}}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){var t;this.options.display&&(t=this.ctx,clipArea(t,this),this._draw(),unclipArea(t))}_draw(){const{options:u,columnSizes:g,lineWidths:p,ctx:f}=this,{align:m,labels:v}=u,x=defaults.color,b=getRtlAdapter(u.rtl,this.left,this.width),_=toFont(v.font),y=v["padding"],k=_.size,S=k/2;let D;this.drawTitle(),f.textAlign=b.textAlign("left"),f.textBaseline="middle",f.lineWidth=.5,f.font=_.string;const{boxWidth:M,boxHeight:P,itemHeight:w}=getBoxSize(v,k),A=this.isHorizontal(),C=this._computeTitleHeight(),O=(D=A?{x:_alignStartEnd(m,this.left+y,this.right-p[0]),y:this.top+y+C,line:0}:{x:this.left+y,y:_alignStartEnd(m,this.top+C+y,this.bottom-g[0].height),line:0},overrideTextDirection(this.ctx,u.textDirection),w+y);this.legendItems.forEach((t,e)=>{f.strokeStyle=t.fontColor,f.fillStyle=t.fontColor;var i=f.measureText(t.text).width,a=b.textAlign(t.textAlign||(t.textAlign=v.textAlign)),i=M+S+i;let s=D.x,n=D.y;b.setWidth(this.width),A?0this.right&&(n=D.y+=O,D.line++,s=D.x=_alignStartEnd(m,this.left+y,this.right-p[D.line])):0this.bottom&&(s=D.x=s+g[D.line].width+y,D.line++,n=D.y=_alignStartEnd(m,this.top+C+y,this.bottom-g[D.line].height));var r,o,l,h,d,c,e=b.x(s);e=e,h=n,d=t,isNaN(M)||M<=0||isNaN(P)||P<0||(f.save(),r=valueOrDefault(d.lineWidth,1),f.fillStyle=valueOrDefault(d.fillStyle,x),f.lineCap=valueOrDefault(d.lineCap,"butt"),f.lineDashOffset=valueOrDefault(d.lineDashOffset,0),f.lineJoin=valueOrDefault(d.lineJoin,"miter"),f.lineWidth=r,f.strokeStyle=valueOrDefault(d.strokeStyle,x),f.setLineDash(valueOrDefault(d.lineDash,[])),v.usePointStyle?(o={radius:P*Math.SQRT2/2,pointStyle:d.pointStyle,rotation:d.rotation,borderWidth:r},l=b.xPlus(e,M/2),c=h+S,drawPointLegend(f,o,l,c,v.pointStyleWidth&&M)):(o=h+Math.max((k-P)/2,0),l=b.leftForLtr(e,M),c=toTRBLCorners(d.borderRadius),f.beginPath(),Object.values(c).some(t=>0!==t)?addRoundedRectPath(f,{x:l,y:o,w:M,h:P,radius:c}):f.rect(l,o,M,P),f.fill(),0!==r&&f.stroke()),f.restore()),s=_textX(a,s+M+S,A?s+i:this.right,u.rtl),h=b.x(s),e=n,d=t,renderText(f,d.text,h,e+w/2,_,{strikethrough:d.hidden,textAlign:b.textAlign(d.textAlign)}),A?D.x+=i+y:"string"!=typeof t.text?(c=_.lineHeight,D.y+=calculateLegendItemHeight(t,c)):D.y+=O}),restoreTextDirection(this.ctx,u.textDirection)}drawTitle(){var a=this.options,s=a.title,n=toFont(s.font),r=toPadding(s.padding);if(s.display){const h=getRtlAdapter(a.rtl,this.left,this.width),d=this.ctx;var o=s.position,l=n.size/2,r=r.top+l;let t,e=this.left,i=this.width;this.isHorizontal()?(i=Math.max(...this.lineWidths),t=this.top+r,e=_alignStartEnd(a.align,e,this.right-i)):(l=this.columnSizes.reduce((t,e)=>Math.max(t,e.height),0),t=r+_alignStartEnd(a.align,this.top,this.bottom-l-a.labels.padding-this._computeTitleHeight()));r=_alignStartEnd(o,e,e+i);d.textAlign=h.textAlign(_toLeftRightCenter(o)),d.textBaseline="middle",d.strokeStyle=s.color,d.fillStyle=s.color,d.font=n.string,renderText(d,s.text,r,t,n)}}_computeTitleHeight(){var t=this.options.title,e=toFont(t.font),i=toPadding(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,a,s;if(_isBetween(t,this.left,this.right)&&_isBetween(e,this.top,this.bottom))for(s=this.legendHitBoxes,i=0;it.length>e.length?t:e)),e+i.size/2+a.measureText(s).width}function calculateItemHeight(t,e,i){let a=t;return a="string"!=typeof e.text?calculateLegendItemHeight(e,i):a}function calculateLegendItemHeight(t,e){return e*(t.text?t.text.length+.5:0)}function isListened(t,e){return!("mousemove"!==t&&"mouseout"!==t||!e.onHover&&!e.onLeave)||!(!e.onClick||"click"!==t&&"mouseup"!==t)}var plugin_legend={id:"legend",_element:Legend,start(t,e,i){var a=t.legend=new Legend({ctx:t.ctx,options:i,chart:t});layouts.configure(t,a,i),layouts.addBox(t,a)},stop(t){layouts.removeBox(t,t.legend),delete t.legend},beforeUpdate(t,e,i){const a=t.legend;layouts.configure(t,a,i),a.options=i},afterUpdate(t){const e=t.legend;e.buildLabels(),e.adjustHitBoxes()},afterEvent(t,e){e.replay||t.legend.handleEvent(e.event)},defaults:{display:!0,position:"top",align:"center",fullSize:!0,reverse:!1,weight:1e3,onClick(t,e,i){var a=e.datasetIndex;const s=i.chart;s.isDatasetVisible(a)?(s.hide(a),e.hidden=!0):(s.show(a),e.hidden=!1)},onHover:null,onLeave:null,labels:{color:t=>t.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const a=t.data.datasets,{usePointStyle:s,pointStyle:n,textAlign:r,color:o,useBorderRadius:l,borderRadius:h}=t.legend.options["labels"];return t._getSortedDatasetMetas().map(t=>{var e=t.controller.getStyle(s?0:void 0),i=toPadding(e.borderWidth);return{text:a[t.index].label,fillStyle:e.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:(i.width+i.height)/4,strokeStyle:e.borderColor,pointStyle:n||e.pointStyle,rotation:e.rotation,textAlign:r||e.textAlign,borderRadius:l&&(h||e.borderRadius),datasetIndex:t.index}},this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Title extends Element{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){var i=this.options;this.left=0,this.top=0,i.display?(this.width=this.right=t,this.height=this.bottom=e,t=isArray(i.text)?i.text.length:1,this._padding=toPadding(i.padding),e=t*toFont(i.font).lineHeight+this._padding.height,this.isHorizontal()?this.height=e:this.width=e):this.width=this.height=this.right=this.bottom=0}isHorizontal(){var t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){var{top:e,left:i,bottom:a,right:s,options:n}=this,r=n.align;let o=0,l,h,d;return l=this.isHorizontal()?(h=_alignStartEnd(r,i,s),d=e+t,s-i):(o="left"===n.position?(h=i+t,d=_alignStartEnd(r,a,e),-.5*PI):(h=s-t,d=_alignStartEnd(r,e,a),.5*PI),a-e),{titleX:h,titleY:d,maxWidth:l,rotation:o}}draw(){var t,e,i,a,s,n=this.ctx,r=this.options;r.display&&(e=(t=toFont(r.font)).lineHeight/2+this._padding.top,{titleX:e,titleY:i,maxWidth:a,rotation:s}=this._drawArgs(e),renderText(n,r.text,0,0,t,{color:r.color,maxWidth:a,rotation:s,textAlign:_toLeftRightCenter(r.align),textBaseline:"middle",translation:[e,i]}))}}function createTitle(t,e){var i=new Title({ctx:t.ctx,options:e,chart:t});layouts.configure(t,i,e),layouts.addBox(t,i),t.titleBlock=i}var plugin_title={id:"title",_element:Title,start(t,e,i){createTitle(t,i)},stop(t){var e=t.titleBlock;layouts.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const a=t.titleBlock;layouts.configure(t,a,i),a.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const map=new WeakMap;var plugin_subtitle={id:"subtitle",start(t,e,i){var a=new Title({ctx:t.ctx,options:i,chart:t});layouts.configure(t,a,i),layouts.addBox(t,a),map.set(t,a)},stop(t){layouts.removeBox(t,map.get(t)),map.delete(t)},beforeUpdate(t,e,i){const a=map.get(t);layouts.configure(t,a,i),a.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const positioners={average(t){if(!t.length)return!1;let e,i,a=0,s=0,n=0;for(e=0,i=t.length;et+e.before.length+e.lines.length+e.after.length,0);v+=t.beforeBody.length+t.afterBody.length,c&&(f+=c*h.lineHeight+(c-1)*e.titleSpacing+e.titleMarginBottom),v&&(c=e.displayColors?Math.max(o,l.lineHeight):l.lineHeight,f+=g*c+(v-g)*l.lineHeight+(v-1)*e.bodySpacing),u&&(f+=e.footerMarginTop+u*d.lineHeight+(u-1)*e.footerSpacing);let x=0;function b(t){m=Math.max(m,i.measureText(t).width+x)}return i.save(),i.font=h.string,each(t.title,b),i.font=l.string,each(t.beforeBody.concat(t.afterBody),b),x=e.displayColors?r+2+e.boxPadding:0,each(a,t=>{each(t.before,b),each(t.lines,b),each(t.after,b)}),x=0,i.font=d.string,each(t.footer,b),i.restore(),{width:m+=p.width,height:f}}function determineYAlign(t,e){var{y:e,height:i}=e;return et.height-i/2?"bottom":"center"}function doesNotFitWithAlign(t,e,i,a){var{x:a,width:s}=a,i=i.caretSize+i.caretPadding;return"left"===t&&a+s+i>e.width||("right"===t&&a-s-i<0||void 0)}function determineXAlign(t,e,i,a){var{x:s,width:n}=i,{width:r,chartArea:{left:o,right:l}}=t;let h="center";return"center"===a?h=s<=(o+l)/2?"left":"right":s<=n/2?h="left":r-n/2<=s&&(h="right"),h=doesNotFitWithAlign(h,t,e,i)?"center":h}function determineAlignment(t,e,i){var a=i.yAlign||e.yAlign||determineYAlign(t,i);return{xAlign:i.xAlign||e.xAlign||determineXAlign(t,e,i,a),yAlign:a}}function alignX(t,e){let{x:i,width:a}=t;return"right"===e?i-=a:"center"===e&&(i-=a/2),i}function alignY(t,e,i){let{y:a,height:s}=t;return"top"===e?a+=i:a-="bottom"===e?s+i:s/2,a}function getBackgroundPoint(t,e,i,a){var{caretSize:t,caretPadding:s,cornerRadius:n}=t,{xAlign:i,yAlign:r}=i,s=t+s,{topLeft:n,topRight:o,bottomLeft:l,bottomRight:h}=toTRBLCorners(n);let d=alignX(e,i);var c=alignY(e,r,s);return"center"===r?"left"===i?d+=s:"right"===i&&(d-=s):"left"===i?d-=Math.max(n,l)+t:"right"===i&&(d+=Math.max(o,h)+t),{x:_limitValue(d,0,a.width-e.width),y:_limitValue(c,0,a.height-e.height)}}function getAlignedX(t,e,i){i=toPadding(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-i.right:t.x+i.left}function getBeforeAfterBodyLines(t){return pushOrConcat([],splitNewlines(t))}function createTooltipContext(t,e,i){return createContext(t,{tooltip:e,tooltipItems:i,type:"tooltip"})}function overrideCallbacks(t,e){e=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return e?t.override(e):t}const defaultCallbacks={beforeTitle:noop,title(t){if(0{var e={before:[],lines:[],after:[]},i=overrideCallbacks(a,t);pushOrConcat(e.before,splitNewlines(invokeCallbackWithFallback(i,"beforeLabel",this,t))),pushOrConcat(e.lines,invokeCallbackWithFallback(i,"label",this,t)),pushOrConcat(e.after,splitNewlines(invokeCallbackWithFallback(i,"afterLabel",this,t))),s.push(e)}),s}getAfterBody(t,e){return getBeforeAfterBodyLines(invokeCallbackWithFallback(e.callbacks,"afterBody",this,t))}getFooter(t,e){var e=e["callbacks"],i=invokeCallbackWithFallback(e,"beforeFooter",this,t),a=invokeCallbackWithFallback(e,"footer",this,t),e=invokeCallbackWithFallback(e,"afterFooter",this,t),t=pushOrConcat([],splitNewlines(i));return t=pushOrConcat(t,splitNewlines(a)),pushOrConcat(t,splitNewlines(e))}_createItems(a){var t=this._active;const s=this.chart.data,i=[],n=[],r=[];let e=[],o,l;for(o=0,l=t.length;oa.filter(t,e,i,s))),a.itemSort&&(e=e.sort((t,e)=>a.itemSort(t,e,s))),each(e,t=>{var e=overrideCallbacks(a.callbacks,t);i.push(invokeCallbackWithFallback(e,"labelColor",this,t)),n.push(invokeCallbackWithFallback(e,"labelPointStyle",this,t)),r.push(invokeCallbackWithFallback(e,"labelTextColor",this,t))}),this.labelColors=i,this.labelPointStyles=n,this.labelTextColors=r,this.dataPoints=e}update(t,e){const i=this.options.setContext(this.getContext());var a,s,n,r=this._active;let o,l=[];r.length?(r=positioners[i.position].call(this,r,this._eventPosition),l=this._createItems(i),this.title=this.getTitle(l,i),this.beforeBody=this.getBeforeBody(l,i),this.body=this.getBody(l,i),this.afterBody=this.getAfterBody(l,i),this.footer=this.getFooter(l,i),a=this._size=getTooltipSize(this,i),n=Object.assign({},r,a),s=determineAlignment(this.chart,i,n),n=getBackgroundPoint(i,n,s,this.chart),this.xAlign=s.xAlign,this.yAlign=s.yAlign,o={opacity:1,x:n.x,y:n.y,width:a.width,height:a.height,caretX:r.x,caretY:r.y}):0!==this.opacity&&(o={opacity:0}),this._tooltipItems=l,this.$context=void 0,o&&this._resolveAnimations().update(this,o),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,a){t=this.getCaretPosition(t,i,a);e.lineTo(t.x1,t.y1),e.lineTo(t.x2,t.y2),e.lineTo(t.x3,t.y3)}getCaretPosition(t,e,i){var{xAlign:a,yAlign:s}=this,{caretSize:i,cornerRadius:n}=i,{topLeft:n,topRight:r,bottomLeft:o,bottomRight:l}=toTRBLCorners(n),{x:t,y:h}=t,{width:e,height:d}=e;let c,u,g,p,f,m;return"center"===s?(f=h+d/2,m="left"===a?(c=t,u=c-i,p=f+i,f-i):(c=t+e,u=c+i,p=f-i,f+i),g=c):(u="left"===a?t+Math.max(n,o)+i:"right"===a?t+e-Math.max(r,l)-i:this.caretX,g="top"===s?(p=h,f=p-i,c=u-i,u+i):(p=h+d,f=p+i,c=u+i,u-i),m=p),{x1:c,x2:u,x3:g,y1:p,y2:f,y3:m}}drawTitle(t,e,i){var a=this.title,s=a.length;let n,r,o;if(s){const l=getRtlAdapter(i.rtl,this.x,this.width);for(t.x=getAlignedX(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",n=toFont(i.titleFont),r=i.titleSpacing,e.fillStyle=i.titleColor,e.font=n.string,o=0;o0!==t)?(t.beginPath(),t.fillStyle=s.multiKeyBackground,addRoundedRectPath(t,{x:d,y:e,w:h,h:l,radius:n}),t.fill(),t.stroke(),t.fillStyle=r.backgroundColor,t.beginPath(),addRoundedRectPath(t,{x:o,y:e+1,w:h-2,h:l-2,radius:n}),t.fill()):(t.fillStyle=s.multiKeyBackground,t.fillRect(d,e,h,l),t.strokeRect(d,e,h,l),t.fillStyle=r.backgroundColor,t.fillRect(o,e+1,h-2,l-2))),t.fillStyle=this.labelTextColors[i]}drawBody(e,i,t){var a=this["body"];const{bodySpacing:s,bodyAlign:n,displayColors:r,boxHeight:o,boxWidth:l,boxPadding:h}=t;var d=toFont(t.bodyFont);let c=d.lineHeight,u=0;const g=getRtlAdapter(t.rtl,this.x,this.width);function p(t){i.fillText(t,g.x(e.x+u),e.y+c/2),e.y+=c+s}var f=g.textAlign(n);let m,v,x,b,_,y,k;for(i.textAlign=n,i.textBaseline="middle",i.font=d.string,e.x=getAlignedX(this,f,t),i.fillStyle=t.bodyColor,each(this.beforeBody,p),u=r&&"right"!==f?"center"===n?l/2+h:l+2+h:0,b=0,y=a.length;b{var i=this.chart.getDatasetMeta(t);if(i)return{datasetIndex:t,element:i.data[e],index:e};throw new Error("Cannot find a dataset at index "+t)}),i=!_elementsEqual(i,t),a=this._positionChanged(t,e);(i||a)&&(this._active=t,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;var a=this.options,s=this._active||[],i=this._getActiveElements(t,s,e,i),n=this._positionChanged(i,t),s=e||!_elementsEqual(i,s)||n;return s&&(this._active=i,(a.enabled||a.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),s}_getActiveElements(t,e,i,a){var s=this.options;if("mouseout"===t.type)return[];if(!a)return e;const n=this.chart.getElementsAtEventForMode(t,s.mode,s,i);return s.reverse&&n.reverse(),n}_positionChanged(t,e){var{caretX:i,caretY:a,options:s}=this,s=positioners[s.position].call(this,t,e);return!1!==s&&(i!==s.x||a!==s.y)}}var plugin_tooltip={id:"tooltip",_element:Tooltip,positioners:positioners,afterInit(t,e,i){i&&(t.tooltip=new Tooltip({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;var i;e&&e._willRender()&&(!(i={tooltip:e})!==t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0})&&(e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)))},afterEvent(t,e){var i;t.tooltip&&(i=e.replay,t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0))},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:defaultCallbacks},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]},plugins=Object.freeze({__proto__:null,Colors:plugin_colors,Decimation:plugin_decimation,Filler:index,Legend:plugin_legend,SubTitle:plugin_subtitle,Title:plugin_title,Tooltip:plugin_tooltip});const addIfString=(t,e,i,a)=>("string"==typeof e?(i=t.push(e)-1,a.unshift({index:i,label:e})):isNaN(e)&&(i=null),i);function findOrAddLabel(t,e,i,a){var s=t.indexOf(e);return-1===s?addIfString(t,e,i,a):s!==t.lastIndexOf(e)?i:s}const validIndex=(t,e)=>null===t?null:_limitValue(Math.round(t),0,e);function _getLabelForValue(t){var e=this.getLabels();return 0<=t&&te.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}}function generateTicks$1(t,e){const i=[];var{bounds:a,step:s,min:n,max:r,precision:o,count:l,maxTicks:h,maxDigits:d,includeBounds:c}=t,u=s||1,g=h-1,{min:e,max:p}=e,f=!isNullOrUndef(n),m=!isNullOrUndef(r),v=!isNullOrUndef(l),d=(p-e)/(d+1);let x=niceNum((p-e)/g/u)*u,b,_,y,k;if(x<1e-14&&!f&&!m)return[{value:e},{value:p}];(k=Math.ceil(p/x)-Math.floor(e/x))>g&&(x=niceNum(k*x/g/u)*u),isNullOrUndef(o)||(b=Math.pow(10,o),x=Math.ceil(x*b)/b),y="ticks"===a?(_=Math.floor(e/x)*x,Math.ceil(p/x)*x):(_=e,p),f&&m&&s&&almostWhole((r-n)/s,x/1e3)?(k=Math.round(Math.min((r-n)/x,h)),x=(r-n)/k,_=n,y=r):v?(_=f?n:_,y=m?r:y,k=l-1,x=(y-_)/k):(k=(y-_)/x,k=almostEquals(k,Math.round(k),x/1e3)?Math.round(k):Math.ceil(k));g=Math.max(_decimalPlaces(x),_decimalPlaces(_));b=Math.pow(10,isNullOrUndef(o)?g:o),_=Math.round(_*b)/b,y=Math.round(y*b)/b;let S=0;for(f&&(c&&_!==n?(i.push({value:n}),_a=e?a:t,l=t=>s=i?s:t;t&&(r=sign(a),n=sign(s),r<0&&n<0?l(0):0Math.floor(log10(t)),changeExponent=(t,e)=>Math.pow(10,log10Floor(t)+e);function isMajor(t){return 1==t/Math.pow(10,log10Floor(t))}function steps(t,e,i){i=Math.pow(10,i),t=Math.floor(t/i);return Math.ceil(e/i)-t}function startExp(t,e){var i=e-t;let a=log10Floor(i);for(;10n?Math.pow(10,s):0,s=Math.round((e-l)*r)/r,h=Math.floor((e-l)/o/10)*o*10;let d=Math.floor((s-h)/Math.pow(10,n)),c=finiteOrDefault(t.min,Math.round((l+h+d*Math.pow(10,n))*r)/r);for(;ca=e?a:t,n=t=>s=i?s:t;a===s&&(a<=0?(t(1),n(10)):(t(changeExponent(a,-1)),n(changeExponent(s,1)))),a<=0&&t(changeExponent(s,-1)),s<=0&&n(changeExponent(a,1)),this.min=a,this.max=s}buildTicks(){var t=this.options;const e=generateTicks({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&_setMinAndMaxByKey(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":formatNumber(t,this.chart.options.locale,this.options.ticks.format)}configure(){var t=this.min;super.configure(),this._startValue=log10(t),this._valueRange=log10(this.max)-log10(t)}getPixelForValue(t){return null===(t=void 0!==t&&0!==t?t:this.min)||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(log10(t)-this._startValue)/this._valueRange)}getValueForPixel(t){t=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+t*this._valueRange)}}function getTickBackdropHeight(t){var e=t.ticks;return e.display&&t.display?(t=toPadding(e.backdropPadding),valueOrDefault(e.font&&e.font.size,defaults.font.size)+t.height):0}function measureLabelSize(t,e,i){return i=isArray(i)?i:[i],{w:_longestText(t,e.string,i),h:i.length*e.lineHeight}}function determineLimits(t,e,i,a,s){return t===a||t===s?{start:e-i/2,end:e+i/2}:te.r&&(r=(a.end-e.r)/n,t.r=Math.max(t.r,e.r+r)),s.starte.b&&(o=(s.end-e.b)/i,t.b=Math.max(t.b,e.b+o))}function createPointLabelItem(t,e,i){var a=t.drawingArea,{extra:i,additionalAngle:s,padding:n,size:r}=i,t=t.getPointPosition(e,a+i+n,s),e=Math.round(toDegrees(_normalizeAngle(t.angle+HALF_PI))),a=yForAngle(t.y,r.h,e),i=getTextAlignForAngle(e),n=leftForTextAlign(t.x,r.w,i);return{visible:!0,x:t.x,y:a,textAlign:i,left:n,top:a,right:n+r.w,bottom:a+r.h}}function isNotOverlapped(t,e){if(!e)return!0;var{left:t,top:i,right:a,bottom:s}=t;return!(_isPointInArea({x:t,y:i},e)||_isPointInArea({x:t,y:s},e)||_isPointInArea({x:a,y:i},e)||_isPointInArea({x:a,y:s},e))}function buildPointLabelItems(e,i,a){const s=[];var n=e._pointLabels.length,t=e.options,{centerPointLabels:r,display:o}=t.pointLabels;const l={extra:getTickBackdropHeight(t)/2,additionalAngle:r?PI/n:0};let h;for(let t=0;t0!==t)?(t.beginPath(),addRoundedRectPath(t,{x:l,y:s,w:r,h:i,radius:a}),t.fill()):t.fillRect(l,s,r,i))}function drawPointLabels(e,i){const{ctx:a,options:{pointLabels:s}}=e;for(let t=i-1;0<=t;t--){var n,r,o,l,h=e._pointLabelItems[t];h.visible&&(drawPointLabelBox(a,n=s.setContext(e.getPointLabelContext(t)),h),r=toFont(n.font),{x:h,y:o,textAlign:l}=h,renderText(a,e._pointLabels[t],h,o+r.lineHeight/2,r,{color:n.color,textAlign:l,textBaseline:"middle"}))}}function pathRadiusLine(e,i,t,a){const s=e["ctx"];if(t)s.arc(e.xCenter,e.yCenter,i,0,TAU);else{var n=e.getPointPosition(0,i);s.moveTo(n.x,n.y);for(let t=1;t{t=callback(this.options.pointLabels.callback,[t,e],this);return t||0===t?t:""}).filter((t,e)=>this.chart.getDataVisibility(e))}fit(){var t=this.options;t.display&&t.pointLabels.display?fitWithPointLabels(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,a){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-a)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,a))}getIndexAngle(t){var e=TAU/(this._pointLabels.length||1),i=this.options.startAngle||0;return _normalizeAngle(t*e+toRadians(i))}getDistanceFromCenterForValue(t){if(isNullOrUndef(t))return NaN;var e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(isNullOrUndef(t))return NaN;t/=this.drawingArea/(this.max-this.min);return this.options.reverse?this.max-t:this.min+t}getPointLabelContext(t){var e=this._pointLabels||[];if(0<=t&&t{0!==e&&(o=this.getDistanceFromCenterForValue(t.value),t=this.getContext(e),e=a.setContext(t),t=s.setContext(t),drawRadiusLine(this,e,o,n,t))}),i.display){for(t.save(),r=n-1;0<=r;r--){var h=i.setContext(this.getPointLabelContext(r)),{color:d,lineWidth:c}=h;c&&d&&(t.lineWidth=c,t.strokeStyle=d,t.setLineDash(h.borderDash),t.lineDashOffset=h.borderDashOffset,o=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),l=this.getPointPosition(r,o),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const r=this.ctx,o=this.options,l=o.ticks;if(l.display){var t=this.getIndexAngle(0);let s,n;r.save(),r.translate(this.xCenter,this.yCenter),r.rotate(t),r.textAlign="center",r.textBaseline="middle",this.ticks.forEach((t,e)=>{var i,a;0===e&&!o.reverse||(i=l.setContext(this.getContext(e)),a=toFont(i.font),s=this.getDistanceFromCenterForValue(this.ticks[e].value),i.showLabelBackdrop&&(r.font=a.string,n=r.measureText(t.label).width,r.fillStyle=i.backdropColor,e=toPadding(i.backdropPadding),r.fillRect(-n/2-e.left,-s-a.size/2-e.top,n+e.width,a.size+e.height)),renderText(r,t.label,0,-s,a,{color:i.color}))}),r.restore()}}drawTitle(){}}const INTERVALS={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},UNITS=Object.keys(INTERVALS);function sorter(t,e){return t-e}function parse(t,e){if(isNullOrUndef(e))return null;const i=t._adapter,{parser:a,round:s,isoWeekday:n}=t._parseOpts;let r=e;return"function"==typeof a&&(r=a(r)),null===(r=isNumberFinite(r)?r:"string"==typeof a?i.parse(r,a):i.parse(r))?null:+(r=s?"week"!==s||!isNumber(n)&&!0!==n?i.startOf(r,s):i.startOf(r,"isoWeek",n):r)}function determineUnitForAutoTicks(e,i,a,s){var n=UNITS.length;for(let t=UNITS.indexOf(e);t=UNITS.indexOf(a);t--){var r=UNITS[t];if(INTERVALS[r].common&&e._adapter.diff(n,s,r)>=i-1)return r}return UNITS[a?UNITS.indexOf(a):0]}function determineMajorUnit(i){for(let t=UNITS.indexOf(i)+1,e=UNITS.length;t=e?i[a]:i[s]]=!0):t[e]=!0}function setMajorTicks(t,e,i,a){const s=t._adapter;var t=+s.startOf(e[0].value,a),n=e[e.length-1].value;let r,o;for(r=t;r<=n;r=+s.add(r,1,a))0<=(o=i[r])&&(e[o].major=!0);return e}function ticksFromTimestamps(t,e,i){const a=[],s={};var n=e.length;let r,o;for(r=0;r+t.value))}initOffsets(t=[]){let e=0,i=0;this.options.offset&&t.length&&(a=this.getDecimalForValue(t[0]),e=1===t.length?1-a:(this.getDecimalForValue(t[1])-a)/2,a=this.getDecimalForValue(t[t.length-1]),i=1===t.length?a:(a-this.getDecimalForValue(t[t.length-2]))/2);var a=t.length<3?.5:.25;e=_limitValue(e,0,a),i=_limitValue(i,0,a),this._offsets={start:e,end:i,factor:1/(e+1+i)}}_generate(){const t=this._adapter;var e=this.min,i=this.max,a=this.options,s=a.time,n=s.unit||determineUnitForAutoTicks(s.minUnit,e,i,this._getLabelCapacity(e)),r=valueOrDefault(a.ticks.stepSize,1),s="week"===n&&s.isoWeekday,o=isNumber(s)||!0===s,l={};let h=e,d,c;if(o&&(h=+t.startOf(h,"isoWeek",s)),h=+t.startOf(h,o?"day":n),t.diff(i,e,n)>1e5*r)throw new Error(e+" and "+i+" are too far apart with stepSize of "+r+" "+n);var u="data"===a.ticks.source&&this.getDataTimestamps();for(d=h,c=0;dt-e).map(t=>+t)}getLabelForValue(t){const e=this._adapter;var i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){var i=this.options.time.displayFormats,a=this._unit,e=e||i[a];return this._adapter.format(t,e)}_tickFormatFunction(t,e,i,a){var s=this.options,n=s.ticks.callback;if(n)return callback(n,[t,e,i],this);var n=s.time.displayFormats,s=this._unit,r=this._majorUnit,s=s&&n[s],n=r&&n[r],i=i[e],e=r&&n&&i&&i.major;return this._adapter.format(t,a||(e?n:s))}generateTickLabels(t){let e,i,a;for(e=0,i=t.length;e=t[a].pos&&e<=t[s].pos&&({lo:a,hi:s}=_lookupByKey(t,"pos",e)),{pos:n,time:o}=t[a],{pos:r,time:l}=t[s]):(e>=t[a].time&&e<=t[s].time&&({lo:a,hi:s}=_lookupByKey(t,"time",e)),{time:n,pos:o}=t[a],{time:r,pos:l}=t[s]);i=r-n;return i?o+(l-o)*(e-n)/i:o}class TimeSeriesScale extends TimeScale{static id="timeseries";static defaults=TimeScale.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){var t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=interpolate(e,this.min),this._tableRange=interpolate(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){var{min:e,max:i}=this;const a=[],s=[];let n,r,o,l,h;for(n=0,r=t.length;n=e&&l<=i&&a.push(l);if(a.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(n=0,r=a.length;n