PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.3
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.3
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / assets / js / dist / admin / admin-statistic.js

admin-statistic.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.3, at assets/js/dist/admin/admin-statistic.js

23,676 lines 858.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ var __webpack_modules__ = ({
3
4 /***/ "./assets/src/js/admin/statistics/api.js"
5 /*!***********************************************!*\
6 !*** ./assets/src/js/admin/statistics/api.js ***!
7 \***********************************************/
8 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9
10 "use strict";
11 __webpack_require__.r(__webpack_exports__);
12 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
13 /* harmony export */ getStatsConfig: () => (/* binding */ getStatsConfig),
14 /* harmony export */ getStatsI18n: () => (/* binding */ getStatsI18n),
15 /* harmony export */ lpStatsFetch: () => (/* binding */ lpStatsFetch)
16 /* harmony export */ });
17 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
18 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
19 /**
20 * Statistics dashboard fetch wrapper + escaping helper.
21 *
22 * Every statistics request goes through lpStatsFetch so the localized globals
23 * (lpDataAdmin for REST root/nonce, lpAdminStatisticSettings for config) are
24 * read in exactly one file, and lpFetchAPI's blind spots are normalized here:
25 * it never rejects on HTTP error codes, so anything but status 'success'
26 * is routed to the error callback.
27 *
28 * @since 4.4.2
29 * @version 1.0.0
30 */
31
32
33
34 const getStatsConfig = () => window.lpAdminStatisticSettings || {};
35 const getStatsI18n = (key, fallback = '') => {
36 const {
37 i18n = {}
38 } = getStatsConfig();
39 return i18n[key] || fallback;
40 };
41
42 /**
43 * Fetch a statistics endpoint with the global filter state applied.
44 *
45 * @param {string} endpoint Route below the statistics namespace, e.g. 'filter-options'.
46 * @param {Object} extraArgs Query args merged over the state (tab-specific params).
47 * @param {Object} functions { before, success, error, completed } — success only
48 * fires on status 'success'; error receives an Error.
49 */
50 const lpStatsFetch = (endpoint, extraArgs = {}, functions = {}) => {
51 const lpDataAdmin = window.lpDataAdmin || {};
52 const restNamespace = getStatsConfig().restNamespace || 'lp/v1/statistics';
53 const url = lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpAddQueryArgs(`${lpDataAdmin.lp_rest_url || '/wp-json/'}${restNamespace}/${endpoint}`, {
54 ..._state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.get(),
55 ...extraArgs
56 });
57 const onError = 'function' === typeof functions.error ? functions.error : err => console.error('LP Statistics:', err);
58 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpFetchAPI(url, {
59 headers: {
60 'X-WP-Nonce': lpDataAdmin.nonce || ''
61 }
62 }, {
63 ...functions,
64 success: response => {
65 if (response && 'success' === response.status) {
66 // Broadcast the server-resolved range so the filter bar can
67 // reconcile its toggle label ( fixes the past-midnight case ).
68 const range = response.data && response.data.range;
69 if (range && range.label) {
70 document.dispatchEvent(new CustomEvent(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_RANGE_RESOLVED, {
71 detail: range
72 }));
73 }
74 if ('function' === typeof functions.success) {
75 functions.success(response);
76 }
77 } else {
78 onError(new Error(response && response.message || getStatsI18n('loadError', 'Request failed.')));
79 }
80 },
81 error: onError
82 });
83 };
84
85 /***/ },
86
87 /***/ "./assets/src/js/admin/statistics/chart.js"
88 /*!*************************************************!*\
89 !*** ./assets/src/js/admin/statistics/chart.js ***!
90 \*************************************************/
91 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
92
93 "use strict";
94 __webpack_require__.r(__webpack_exports__);
95 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
96 /* harmony export */ granularityLabelFormatter: () => (/* binding */ granularityLabelFormatter),
97 /* harmony export */ intlFormat: () => (/* binding */ intlFormat),
98 /* harmony export */ renderLineChart: () => (/* binding */ renderLineChart)
99 /* harmony export */ });
100 /* harmony import */ var chart_js_auto__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! chart.js/auto */ "./node_modules/chart.js/auto/auto.js");
101 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
102 /**
103 * Line chart renderer wrapping Chart.js — single or dual-axis.
104 *
105 * Pure renderer: no fetching, no state mutation. Reuses an existing chart
106 * instance ( Chart.getChart ) instead of recreating, like the legacy
107 * initStatisticChart did.
108 *
109 * @since 4.4.2
110 * @version 1.0.0
111 */
112
113
114
115 const DEFAULT_COLORS = ['#2271b1', '#00a32a'];
116 const EMPTY_STATE_CLASS = 'lp-stats-chart-empty';
117
118 /**
119 * Show/hide the empty state next to the canvas.
120 *
121 * @param {Element} canvas
122 * @param {boolean} show
123 */
124 const toggleEmptyState = (canvas, show) => {
125 const wrapper = canvas.parentElement;
126 if (!wrapper) {
127 return;
128 }
129 let elEmpty = wrapper.querySelector(`.${EMPTY_STATE_CLASS}`);
130 if (show && !elEmpty) {
131 elEmpty = document.createElement('p');
132 elEmpty.className = EMPTY_STATE_CLASS;
133 elEmpty.textContent = (0,_api_js__WEBPACK_IMPORTED_MODULE_1__.getStatsI18n)('noData', 'No data for this period.');
134 wrapper.appendChild(elEmpty);
135 }
136 if (elEmpty) {
137 elEmpty.style.display = show ? '' : 'none';
138 }
139 canvas.style.display = show ? 'none' : 'block';
140 };
141
142 /**
143 * One-off locale date formatting. Fine for a handful of dates ( labels, a
144 * custom-range caption ); for per-label chart axes build a single formatter
145 * and reuse it instead ( see granularityLabelFormatter ).
146 *
147 * @param {Date} date
148 * @param {Object} options Intl.DateTimeFormat options.
149 * @return {string}
150 */
151 const intlFormat = (date, options) => new Intl.DateTimeFormat(undefined, options).format(date);
152
153 /**
154 * Do all 'Y-m-d' day labels fall inside a single calendar month?
155 * When they cross a month boundary the axis must show the month, otherwise
156 * "30, 1, 2" is ambiguous.
157 *
158 * @param {Array} labels
159 * @return {boolean}
160 */
161 const daysWithinOneMonth = labels => {
162 const months = labels.map(label => String(label).slice(0, 7));
163 return months.every(m => m === months[0]);
164 };
165
166 /**
167 * Axis label formatter for a chart payload's `granularity` marker
168 * ( PeriodRange->granularity, set server-side by PeriodResolver ):
169 *
170 * - hour int 0–23 → "14h"
171 * - day 'Y-m-d' → "Tue 14" ( ≤ 7 points, single month ) / "Jul 14"
172 * - month 'mm-YYYY' → "Jul 26"-style short month + 2-digit year
173 *
174 * The returned closure captures a single Intl formatter ( built once here, not
175 * per label ), so a 90-point chart formats against one instance. Unparsable
176 * labels pass through untouched — never throws.
177 *
178 * @param {string} granularity Marker from the payload.
179 * @param {Array} labels Full label set ( picks the day format density ).
180 * @return {Function|null} ( label ) => string, or null for unknown markers.
181 */
182 const granularityLabelFormatter = (granularity, labels = []) => {
183 switch (granularity) {
184 case 'hour':
185 return label => `${label}h`;
186 case 'day':
187 {
188 // Weekday reads best for a short, single-month range; anything
189 // crossing a month shows the month so labels like "Jun 30 / Jul 1"
190 // stay unambiguous.
191 const options = labels.length <= 7 && daysWithinOneMonth(labels) ? {
192 weekday: 'short',
193 day: 'numeric'
194 } : {
195 month: 'short',
196 day: 'numeric'
197 };
198 const fmt = new Intl.DateTimeFormat(undefined, options);
199 return label => {
200 const date = new Date(`${label}T00:00:00`);
201 return isNaN(date.getTime()) ? String(label) : fmt.format(date);
202 };
203 }
204 case 'month':
205 {
206 // Labels are 'mm-YYYY'.
207 const fmt = new Intl.DateTimeFormat(undefined, {
208 month: 'short',
209 year: '2-digit'
210 });
211 return label => {
212 const parts = String(label).split('-');
213 const month = parseInt(parts[0], 10);
214 if (2 === parts.length && month >= 1 && month <= 12) {
215 return fmt.format(new Date(parseInt(parts[1], 10), month - 1, 1));
216 }
217 return String(label);
218 };
219 }
220 default:
221 // Unknown markers render as-is; Chart.js stringifies them for the axis.
222 return null;
223 }
224 };
225
226 /**
227 * Render (or update) a line chart.
228 *
229 * @param {string} canvasSelector e.g. '#net-sales-chart-content'.
230 * @param {Object} chartData { labels, datasets: [ { label, data, color, yAxisID } ], xLabel,
231 * granularity? — enables the shared axis label formatter }.
232 * @param {Object} config { yCurrency?: boolean (default true when 2 datasets),
233 * formatLabel?: ( label, index ) => string — overrides granularity }.
234 * @return {Chart|null} Chart instance, or null when canvas missing / no data.
235 */
236 const renderLineChart = (canvasSelector, chartData = {}, config = {}) => {
237 var _config$yCurrency;
238 const canvas = document.querySelector(canvasSelector);
239 if (!canvas) {
240 return null;
241 }
242 const {
243 datasets = [],
244 xLabel = '',
245 granularity = ''
246 } = chartData;
247 let {
248 labels = []
249 } = chartData;
250 const hasData = datasets.length > 0 && datasets.some(dataset => (dataset.data || []).length > 0);
251 if (!hasData) {
252 const existing = chart_js_auto__WEBPACK_IMPORTED_MODULE_0__["default"].getChart(canvas);
253 if (existing) {
254 existing.destroy();
255 }
256 toggleEmptyState(canvas, true);
257 return null;
258 }
259 toggleEmptyState(canvas, false);
260 const formatLabel = 'function' === typeof config.formatLabel ? config.formatLabel : granularityLabelFormatter(granularity, labels);
261 if (formatLabel) {
262 labels = labels.map((label, index) => formatLabel(label, index));
263 }
264 const isDual = datasets.length > 1;
265 const yCurrency = (_config$yCurrency = config.yCurrency) !== null && _config$yCurrency !== void 0 ? _config$yCurrency : isDual;
266 const currencySymbol = (0,_api_js__WEBPACK_IMPORTED_MODULE_1__.getStatsConfig)().currencySymbol || '';
267 const chartDatasets = datasets.map((dataset, index) => {
268 const color = dataset.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length];
269 return {
270 label: dataset.label || '',
271 data: dataset.data || [],
272 borderColor: color,
273 backgroundColor: color,
274 borderWidth: 2,
275 yAxisID: dataset.yAxisID || (isDual && index > 0 ? 'y1' : 'y')
276 };
277 });
278 const scales = {
279 y: {
280 min: 0,
281 position: 'left',
282 ticks: yCurrency ? {
283 callback: value => currencySymbol + value
284 } : {}
285 },
286 x: {
287 title: {
288 display: !!xLabel,
289 text: xLabel,
290 align: 'end'
291 }
292 }
293 };
294 if (isDual) {
295 scales.y1 = {
296 min: 0,
297 position: 'right',
298 grid: {
299 drawOnChartArea: false
300 },
301 ticks: {
302 precision: 0
303 }
304 };
305 }
306 const existing = chart_js_auto__WEBPACK_IMPORTED_MODULE_0__["default"].getChart(canvas);
307 if (existing) {
308 // Axis set changed (1 ↔ 2 lines) is easier rebuilt than migrated.
309 if (existing.data.datasets.length !== chartDatasets.length) {
310 existing.destroy();
311 } else {
312 existing.data.labels = labels;
313 chartDatasets.forEach((dataset, index) => {
314 existing.data.datasets[index].data = dataset.data;
315 existing.data.datasets[index].label = dataset.label;
316 });
317 existing.config.options.scales.x.title.text = xLabel;
318 existing.update();
319 return existing;
320 }
321 }
322 return new chart_js_auto__WEBPACK_IMPORTED_MODULE_0__["default"](canvas, {
323 type: 'line',
324 data: {
325 labels,
326 datasets: chartDatasets
327 },
328 options: {
329 responsive: true,
330 maintainAspectRatio: false,
331 aspectRatio: 0.8,
332 plugins: {
333 legend: {
334 display: isDual
335 }
336 },
337 scales
338 }
339 });
340 };
341
342 /***/ },
343
344 /***/ "./assets/src/js/admin/statistics/csv.js"
345 /*!***********************************************!*\
346 !*** ./assets/src/js/admin/statistics/csv.js ***!
347 \***********************************************/
348 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
349
350 "use strict";
351 __webpack_require__.r(__webpack_exports__);
352 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
353 /* harmony export */ buildCsvFilename: () => (/* binding */ buildCsvFilename),
354 /* harmony export */ exportCsv: () => (/* binding */ exportCsv)
355 /* harmony export */ });
356 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
357 /**
358 * Client-side CSV export ( Blob + BOM ).
359 *
360 * RFC-4180 escaping plus a CSV-injection guard: values starting with
361 * = + - @ get a leading apostrophe so Excel never executes them.
362 *
363 * @since 4.4.2
364 * @version 1.0.0
365 */
366
367
368 const sanitizeSegment = segment => {
369 const clean = String(segment !== null && segment !== void 0 ? segment : '').toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
370 return clean || 'data';
371 };
372
373 /**
374 * `learnpress-{tab}-{table}-{filtertype}.csv`, all segments sanitized.
375 *
376 * @param {string} tab
377 * @param {string} table
378 * @return {string} Filename.
379 */
380 const buildCsvFilename = (tab, table) => {
381 const {
382 filtertype
383 } = _state_js__WEBPACK_IMPORTED_MODULE_0__.lpStatsState.get();
384 return `learnpress-${sanitizeSegment(tab)}-${sanitizeSegment(table)}-${sanitizeSegment(filtertype)}.csv`;
385 };
386 const escapeCell = value => {
387 let str = null == value ? '' : String(value);
388 if (/^[=+\-@]/.test(str)) {
389 str = `'${str}`;
390 }
391 if (/[",\n\r]/.test(str)) {
392 str = `"${str.replace(/"/g, '""')}"`;
393 }
394 return str;
395 };
396
397 /**
398 * Build and download a CSV from a data-table handle.
399 *
400 * @param {string} filename Full filename (see buildCsvFilename).
401 * @param {Array} columns Column definitions ({ key, label, csv? }).
402 * @param {Array} rows Row objects.
403 */
404 const exportCsv = (filename, columns = [], rows = []) => {
405 if (!columns.length) {
406 return;
407 }
408 const lines = [columns.map(column => escapeCell(column.label)).join(',')];
409 rows.forEach(row => {
410 lines.push(columns.map(column => {
411 const value = 'function' === typeof column.csv ? column.csv(row) : row[column.key];
412 return escapeCell(value);
413 }).join(','));
414 });
415
416 // BOM keeps Excel reading UTF-8 (Vietnamese titles etc.).
417 const blob = new Blob(['\u{FEFF}' + lines.join('\r\n')], {
418 type: 'text/csv;charset=utf-8;'
419 });
420 const url = URL.createObjectURL(blob);
421 const link = document.createElement('a');
422 link.href = url;
423 link.download = filename;
424 document.body.appendChild(link);
425 link.click();
426 document.body.removeChild(link);
427 URL.revokeObjectURL(url);
428 };
429
430 /***/ },
431
432 /***/ "./assets/src/js/admin/statistics/data-table.js"
433 /*!******************************************************!*\
434 !*** ./assets/src/js/admin/statistics/data-table.js ***!
435 \******************************************************/
436 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
437
438 "use strict";
439 __webpack_require__.r(__webpack_exports__);
440 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
441 /* harmony export */ renderDataTable: () => (/* binding */ renderDataTable)
442 /* harmony export */ });
443 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
444 /**
445 * Data table renderer — createElement/textContent only, no innerHTML.
446 *
447 * Emits the plugin's shared table markup ( .lp-table-wrap > table.lp-list-table,
448 * per TableListTemplate ) so the dashboard widgets match every other LearnPress
449 * table. The extra lp-stats-table class carries the stats-only behaviours
450 * ( row hover/highlight, clickable performance rows, empty state ).
451 *
452 * Column definition:
453 * { key, label,
454 * format?: ( value, row ) => string|Node // Node for links etc.
455 * badge?: ( row ) => 'green'|'yellow'|'red'|'' // wraps the cell value
456 * csv?: ( row ) => string // plain value for CSV export (Nodes can't export)
457 * }
458 *
459 * @since 4.4.2
460 * @version 1.1.0
461 */
462
463
464
465 /**
466 * @param {Element} elContainer Container emptied and refilled.
467 * @param {Array} columns Column definitions.
468 * @param {Array} rows Row objects keyed by column key.
469 * @param {Object} options { emptyText?: string }.
470 * @return {Object} { columns, rows } handle for csv/modal reuse.
471 */
472 const renderDataTable = (elContainer, columns = [], rows = [], options = {}) => {
473 if (!elContainer) {
474 return {
475 columns,
476 rows
477 };
478 }
479 elContainer.textContent = '';
480 const wrap = document.createElement('div');
481 wrap.className = 'lp-table-wrap';
482 const table = document.createElement('table');
483 table.className = 'lp-list-table lp-stats-table';
484 const thead = document.createElement('thead');
485 const headRow = document.createElement('tr');
486 columns.forEach(column => {
487 var _column$label;
488 const th = document.createElement('th');
489 th.textContent = (_column$label = column.label) !== null && _column$label !== void 0 ? _column$label : '';
490 headRow.appendChild(th);
491 });
492 thead.appendChild(headRow);
493 table.appendChild(thead);
494 const tbody = document.createElement('tbody');
495 if (!rows.length) {
496 const tr = document.createElement('tr');
497 const td = document.createElement('td');
498 td.colSpan = columns.length || 1;
499 td.className = 'lp-stats-table__empty';
500 td.textContent = options.emptyText || (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.getStatsI18n)('noData', 'No data for this period.');
501 tr.appendChild(td);
502 tbody.appendChild(tr);
503 } else {
504 rows.forEach(row => {
505 const tr = document.createElement('tr');
506 columns.forEach(column => {
507 const td = document.createElement('td');
508 const raw = row[column.key];
509 const output = 'function' === typeof column.format ? column.format(raw, row) : raw;
510 let cellNode;
511 if (output instanceof Node) {
512 cellNode = output;
513 } else {
514 cellNode = document.createTextNode(null == output ? '' : String(output));
515 }
516 const badgeColor = 'function' === typeof column.badge ? column.badge(row) : '';
517 if (badgeColor) {
518 const badge = document.createElement('span');
519 badge.className = `lp-badge lp-badge--${badgeColor}`;
520 badge.appendChild(cellNode);
521 td.appendChild(badge);
522 } else {
523 td.appendChild(cellNode);
524 }
525 tr.appendChild(td);
526 });
527 tbody.appendChild(tr);
528 });
529 }
530 table.appendChild(tbody);
531 wrap.appendChild(table);
532 elContainer.appendChild(wrap);
533 return {
534 columns,
535 rows
536 };
537 };
538
539 /***/ },
540
541 /***/ "./assets/src/js/admin/statistics/filter-bar.js"
542 /*!******************************************************!*\
543 !*** ./assets/src/js/admin/statistics/filter-bar.js ***!
544 \******************************************************/
545 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
546
547 "use strict";
548 __webpack_require__.r(__webpack_exports__);
549 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
550 /* harmony export */ LpStatsFilterBar: () => (/* binding */ LpStatsFilterBar),
551 /* harmony export */ lpStatsFilterBar: () => (/* binding */ lpStatsFilterBar)
552 /* harmony export */ });
553 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
554 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
555 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
556 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
557 /**
558 * Statistics dashboard global filter bar.
559 *
560 * WC-style date-range dropdown ( Presets/Custom tabs + Compare to ) +
561 * instructor/category scope selects + CSV export trigger.
562 *
563 * Preset and compare selections apply immediately; the Custom tab applies on
564 * Update. Mutates state only through lpStatsState.set(); tab modules listen
565 * for the filter-changed event and never talk to this class directly.
566 *
567 * The toggle label is derived from state, not set imperatively per handler:
568 * LP_STATS_FILTER_CHANGED paints an optimistic label the instant the filter
569 * moves, and LP_STATS_RANGE_RESOLVED ( echoed by every stats payload ) then
570 * reconciles it to the server-resolved label — which is what keeps a panel
571 * left open past midnight from showing a stale "to date" range.
572 *
573 * Preset range labels come pre-resolved from the server ( dateRange.presets in
574 * lpAdminStatisticSettings ) — the only client-side date formatting is the
575 * custom range, via Intl.
576 *
577 * @since 4.4.2
578 * @version 2.1.0
579 */
580
581
582
583
584
585 class LpStatsFilterBar {
586 static selectors = {
587 elContainer: '.lp-statistics-filter-bar',
588 elDaterange: '.lp-stats-daterange',
589 elToggle: '.lp-stats-daterange__toggle',
590 elToggleLabel: '.lp-stats-daterange__label',
591 elPanel: '.lp-stats-daterange__panel',
592 elTab: '.lp-stats-daterange__tab',
593 elTabpanel: '.lp-stats-daterange__tabpanel',
594 elPresetRadio: 'input[name="lp-stats-preset"]',
595 elCompareRadio: 'input[name="lp-stats-compare"]',
596 elCustomFrom: '.lp-stats-daterange__from',
597 elCustomTo: '.lp-stats-daterange__to',
598 elBtnUpdate: '.lp-stats-daterange__update',
599 elSelectInstructor: '.lp-stats-filter-instructor',
600 elSelectCategory: '.lp-stats-filter-category',
601 elBtnExport: '.lp-stats-export-csv'
602 };
603 init() {
604 this.elContainer = document.querySelector(LpStatsFilterBar.selectors.elContainer);
605 if (!this.elContainer) {
606 return;
607 }
608 this.loadFilterOptions();
609 this.events();
610 }
611 events() {
612 if (LpStatsFilterBar._loadedEvents) {
613 return;
614 }
615 LpStatsFilterBar._loadedEvents = this;
616 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
617 selector: LpStatsFilterBar.selectors.elToggle,
618 class: this,
619 callBack: this.togglePanel.name
620 }, {
621 selector: LpStatsFilterBar.selectors.elTab,
622 class: this,
623 callBack: this.switchTab.name
624 },
625 // Presets commit on a real pointer click. Chromium also fires a click
626 // on arrow-key radio navigation, but keyboard-synthesized clicks carry
627 // detail 0 — changePreset ignores those so arrows browse; keyboard
628 // commit is the Enter/Space keydown handler below. ( Committing on
629 // 'change' would apply + close + refetch on every arrow keystroke. )
630 {
631 selector: LpStatsFilterBar.selectors.elPresetRadio,
632 class: this,
633 callBack: this.changePreset.name
634 }, {
635 selector: LpStatsFilterBar.selectors.elBtnUpdate,
636 class: this,
637 callBack: this.applyCustomRange.name
638 }, {
639 selector: LpStatsFilterBar.selectors.elBtnExport,
640 class: this,
641 callBack: this.exportCsv.name
642 }]);
643
644 // Keyboard commit for the browsed preset ( Enter or Space on the focused
645 // radio ); arrow keys move the selection without committing.
646 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keydown', [{
647 selector: LpStatsFilterBar.selectors.elPresetRadio,
648 class: this,
649 callBack: this.changePreset.name,
650 conditionBeforeCallBack: args => 'Enter' === args.e.key || ' ' === args.e.key
651 }]);
652 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{
653 selector: LpStatsFilterBar.selectors.elCompareRadio,
654 class: this,
655 callBack: this.changeCompare.name
656 }, {
657 selector: LpStatsFilterBar.selectors.elSelectInstructor,
658 class: this,
659 callBack: this.changeScope.name
660 }, {
661 selector: LpStatsFilterBar.selectors.elSelectCategory,
662 class: this,
663 callBack: this.changeScope.name
664 }]);
665
666 // Outside click / Esc close the popover.
667 document.addEventListener('click', event => {
668 if (this.isPanelOpen() && !event.target.closest(LpStatsFilterBar.selectors.elDaterange)) {
669 this.closePanel();
670 }
671 });
672 document.addEventListener('keydown', event => {
673 if ('Escape' === event.key && this.isPanelOpen()) {
674 this.closePanel(true);
675 }
676 });
677
678 // Toggle label follows state: an optimistic label the moment the filter
679 // moves, then the authoritative server label when the payload lands.
680 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, event => {
681 this.setToggleLabel(this.labelForState(event.detail));
682 });
683 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_RANGE_RESOLVED, event => {
684 this.setToggleLabel(event.detail?.label);
685 });
686 }
687
688 // Popover open/close + tabs.
689
690 panel() {
691 return this.elContainer.querySelector(LpStatsFilterBar.selectors.elPanel);
692 }
693 isPanelOpen() {
694 const elPanel = this.panel();
695 return !!elPanel && !elPanel.hidden;
696 }
697 togglePanel(args) {
698 const btn = args.target.closest(LpStatsFilterBar.selectors.elToggle);
699 if (!btn || !this.elContainer.contains(btn)) {
700 return;
701 }
702 const elPanel = this.panel();
703 if (!elPanel) {
704 // Toggle rendered without its panel ( template override ) — no-op,
705 // like closePanel(), instead of throwing on a null deref.
706 return;
707 }
708 if (!elPanel.hidden) {
709 this.closePanel();
710 return;
711 }
712 elPanel.hidden = false;
713 btn.setAttribute('aria-expanded', 'true');
714
715 // Focus-trap-lite: land on the checked preset ( or the active tab ).
716 const checked = elPanel.querySelector(`${LpStatsFilterBar.selectors.elPresetRadio}:checked`);
717 const fallback = elPanel.querySelector(`${LpStatsFilterBar.selectors.elTab}.active`);
718 (checked && checked.offsetParent ? checked : fallback)?.focus();
719 }
720
721 /**
722 * @param {boolean} refocus Return focus to the toggle ( Esc ), not on outside click.
723 */
724 closePanel(refocus = false) {
725 const elPanel = this.panel();
726 if (!elPanel) {
727 return;
728 }
729 elPanel.hidden = true;
730 const elToggle = this.elContainer.querySelector(LpStatsFilterBar.selectors.elToggle);
731 elToggle?.setAttribute('aria-expanded', 'false');
732 if (refocus) {
733 elToggle?.focus();
734 }
735 }
736 switchTab(args) {
737 const btn = args.target.closest(LpStatsFilterBar.selectors.elTab);
738 if (!btn || !this.elContainer.contains(btn)) {
739 return;
740 }
741 const tab = btn.dataset.tab;
742 this.elContainer.querySelectorAll(LpStatsFilterBar.selectors.elTab).forEach(el => {
743 const active = el === btn;
744 el.classList.toggle('active', active);
745 el.setAttribute('aria-selected', active ? 'true' : 'false');
746 });
747 this.elContainer.querySelectorAll(LpStatsFilterBar.selectors.elTabpanel).forEach(el => {
748 el.hidden = el.dataset.tabpanel !== tab;
749 });
750 }
751
752 // Selection → state.
753
754 changePreset(args) {
755 const radio = args.target.closest(LpStatsFilterBar.selectors.elPresetRadio);
756 if (!radio || !this.elContainer.contains(radio)) {
757 return;
758 }
759
760 // A click with detail 0 is keyboard-synthesized ( arrow navigation, or
761 // Space ) — let the user browse; the Enter/Space keydown binding is what
762 // commits from the keyboard. Real pointer clicks have detail >= 1.
763 if ('click' === args.e.type && !args.e.detail) {
764 return;
765 }
766
767 // Label updates via the filter-changed listener ( derived from state ).
768 this.closePanel(true);
769 _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.set({
770 filtertype: radio.value,
771 date: ''
772 });
773 }
774 changeCompare(args) {
775 const radio = args.target.closest(LpStatsFilterBar.selectors.elCompareRadio);
776 if (!radio || !this.elContainer.contains(radio)) {
777 return;
778 }
779
780 // Popover stays open: compare is a modifier, not a range choice.
781 _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.set({
782 compare: radio.value
783 });
784 }
785 applyCustomRange(args) {
786 const btn = args.target.closest(LpStatsFilterBar.selectors.elBtnUpdate);
787 if (!btn || !this.elContainer.contains(btn)) {
788 return;
789 }
790 const from = this.elContainer.querySelector(LpStatsFilterBar.selectors.elCustomFrom)?.value;
791 const to = this.elContainer.querySelector(LpStatsFilterBar.selectors.elCustomTo)?.value;
792 if (!from || !to) {
793 return;
794 }
795
796 // Uncheck any preset — the window is now the custom pair.
797 this.elContainer.querySelectorAll(LpStatsFilterBar.selectors.elPresetRadio).forEach(el => {
798 el.checked = false;
799 });
800 const [start, end] = [from, to].sort();
801 // Label updates via the filter-changed listener ( derived from state ).
802 this.closePanel(true);
803 _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.set({
804 filtertype: 'custom',
805 date: `${start}+${end}`
806 });
807 }
808
809 // Toggle label.
810
811 setToggleLabel(label) {
812 const elLabel = this.elContainer.querySelector(LpStatsFilterBar.selectors.elToggleLabel);
813 if (elLabel && label) {
814 elLabel.textContent = label;
815 }
816 }
817
818 /**
819 * Optimistic toggle label for the current filter state — a preset's
820 * server-resolved label, or "Custom (range)" for a custom window. The
821 * authoritative label arrives later via LP_STATS_RANGE_RESOLVED.
822 *
823 * @param {Object} filters { filtertype, date } from lpStatsState.
824 */
825 labelForState({
826 filtertype,
827 date
828 } = {}) {
829 if ('custom' === filtertype && date) {
830 const [start, end] = date.split('+');
831 if (start && end) {
832 return `${(0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('custom', 'Custom')} (${this.customRangeLabel(start, end)})`;
833 }
834 }
835 return this.presetLabel(filtertype);
836 }
837
838 /**
839 * "Month to date (Jul 1 – 14)" from the server-resolved preset table.
840 *
841 * @param {string} value Preset id.
842 */
843 presetLabel(value) {
844 const {
845 presets = []
846 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)().dateRange || {};
847 const preset = presets.find(entry => entry.value === value);
848 if (!preset) {
849 return value;
850 }
851 return preset.rangeLabel ? `${preset.name} (${preset.rangeLabel})` : preset.name;
852 }
853
854 /**
855 * Locale-formatted custom range, densest unambiguous form
856 * ( "Jul 1 – 14", "Apr 1 – Jun 30", "Dec 29, 2025 – Jan 4, 2026" ).
857 *
858 * @param {string} start 'Y-m-d'.
859 * @param {string} end 'Y-m-d'.
860 */
861 customRangeLabel(start, end) {
862 const dateFrom = new Date(`${start}T00:00:00`);
863 const dateTo = new Date(`${end}T00:00:00`);
864 if (isNaN(dateFrom.getTime()) || isNaN(dateTo.getTime())) {
865 return `${start} – ${end}`;
866 }
867 const sameYear = dateFrom.getFullYear() === dateTo.getFullYear();
868 const sameMonth = sameYear && dateFrom.getMonth() === dateTo.getMonth();
869 if (sameMonth) {
870 const startPart = (0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateFrom, {
871 month: 'short',
872 day: 'numeric'
873 });
874 return start === end ? startPart : `${startPart} – ${(0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateTo, {
875 day: 'numeric'
876 })}`;
877 }
878 if (sameYear) {
879 const options = {
880 month: 'short',
881 day: 'numeric'
882 };
883 return `${(0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateFrom, options)} – ${(0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateTo, options)}`;
884 }
885 const options = {
886 month: 'short',
887 day: 'numeric',
888 year: 'numeric'
889 };
890 return `${(0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateFrom, options)} – ${(0,_chart_js__WEBPACK_IMPORTED_MODULE_3__.intlFormat)(dateTo, options)}`;
891 }
892
893 // Scope selects + export ( unchanged behavior ).
894
895 /**
896 * Populate the two scope selects from the filter-options endpoint,
897 * then restore any deep-linked selection already held by the state.
898 */
899 loadFilterOptions() {
900 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('filter-options', {}, {
901 success: response => {
902 const {
903 instructors = [],
904 categories = []
905 } = response.data || {};
906 this.fillSelect(LpStatsFilterBar.selectors.elSelectInstructor, instructors, _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.get().instructor_id);
907 this.fillSelect(LpStatsFilterBar.selectors.elSelectCategory, categories, _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.get().category_id);
908 }
909 });
910 }
911
912 /**
913 * Append { id, name } options — createElement + textContent only,
914 * names are user-controlled.
915 *
916 * @param {string} selector Select element selector inside the bar.
917 * @param {Array} items [ { id, name } ].
918 * @param {number} selected Id to preselect (deep link), 0 for "All".
919 */
920 fillSelect(selector, items, selected = 0) {
921 const elSelect = this.elContainer.querySelector(selector);
922 if (!elSelect) {
923 return;
924 }
925 items.forEach(item => {
926 const option = document.createElement('option');
927 option.value = item.id;
928 option.textContent = item.name;
929 elSelect.appendChild(option);
930 });
931 if (selected) {
932 elSelect.value = String(selected);
933 // Unknown deep-link id → back to "All", state follows the visible truth.
934 if (elSelect.value !== String(selected)) {
935 elSelect.value = '0';
936 }
937 }
938 }
939 changeScope(args) {
940 const elSelect = args.target.closest('select');
941 if (!elSelect || !this.elContainer.contains(elSelect)) {
942 return;
943 }
944 const elInstructor = this.elContainer.querySelector(LpStatsFilterBar.selectors.elSelectInstructor);
945 const elCategory = this.elContainer.querySelector(LpStatsFilterBar.selectors.elSelectCategory);
946 _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.set({
947 instructor_id: parseInt(elInstructor?.value, 10) || 0,
948 category_id: parseInt(elCategory?.value, 10) || 0
949 });
950 }
951 exportCsv(args) {
952 const btn = args.target.closest(LpStatsFilterBar.selectors.elBtnExport);
953 if (!btn || !this.elContainer.contains(btn)) {
954 return;
955 }
956 document.dispatchEvent(new CustomEvent(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV));
957 }
958 }
959 const lpStatsFilterBar = new LpStatsFilterBar();
960
961 /***/ },
962
963 /***/ "./assets/src/js/admin/statistics/kpi.js"
964 /*!***********************************************!*\
965 !*** ./assets/src/js/admin/statistics/kpi.js ***!
966 \***********************************************/
967 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
968
969 "use strict";
970 __webpack_require__.r(__webpack_exports__);
971 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
972 /* harmony export */ renderKpi: () => (/* binding */ renderKpi)
973 /* harmony export */ });
974 /**
975 * KPI card renderer — pure DOM fill, no fetch.
976 *
977 * Payload shape comes from PeriodHelper::kpi_payload() on the server:
978 * { value, prev_value, change_pct } plus optional client extras
979 * { formatted, subline }. change_pct null → delta hidden (no wrong deltas).
980 *
981 * @since 4.4.2
982 * @version 1.0.0
983 */
984
985 /**
986 * @param {Element} elCard The .lp-kpi-card root.
987 * @param {Object} payload KPI payload.
988 */
989 const renderKpi = (elCard, payload = {}) => {
990 if (!elCard) {
991 return;
992 }
993 const elValue = elCard.querySelector('.lp-kpi-value');
994 const elDelta = elCard.querySelector('.lp-kpi-delta');
995 const elSubline = elCard.querySelector('.lp-kpi-subline');
996 if (elValue) {
997 var _payload$formatted;
998 const value = (_payload$formatted = payload.formatted) !== null && _payload$formatted !== void 0 ? _payload$formatted : payload.value;
999 elValue.textContent = null == value || '' === value ? '–' : String(value);
1000 }
1001 if (elDelta) {
1002 elDelta.classList.remove('is-up', 'is-down');
1003 if ('number' === typeof payload.change_pct) {
1004 const isUp = payload.change_pct >= 0;
1005 elDelta.classList.add(isUp ? 'is-up' : 'is-down');
1006 elDelta.textContent = `${isUp ? '▲' : '▼'} ${Math.abs(payload.change_pct)}%`;
1007 } else {
1008 elDelta.textContent = '';
1009 }
1010 }
1011 if (elSubline) {
1012 var _payload$subline;
1013 elSubline.textContent = (_payload$subline = payload.subline) !== null && _payload$subline !== void 0 ? _payload$subline : '';
1014 }
1015 };
1016
1017 /***/ },
1018
1019 /***/ "./assets/src/js/admin/statistics/report-modal.js"
1020 /*!********************************************************!*\
1021 !*** ./assets/src/js/admin/statistics/report-modal.js ***!
1022 \********************************************************/
1023 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1024
1025 "use strict";
1026 __webpack_require__.r(__webpack_exports__);
1027 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1028 /* harmony export */ LpStatsReportModal: () => (/* binding */ LpStatsReportModal),
1029 /* harmony export */ lpStatsReportModal: () => (/* binding */ lpStatsReportModal)
1030 /* harmony export */ });
1031 /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js");
1032 /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_0__);
1033 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
1034 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
1035 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
1036 /**
1037 * Report popup controller — SweetAlert2 shell over a server-rendered table.
1038 *
1039 * The table is built in PHP ( AdminStatisticsReportTable ) via TableListTemplate
1040 * and delivered through TemplateAJAX: open() injects the popup body, points the
1041 * .lp-target at the requested report + current filters, and triggers loadAJAX to
1042 * fetch it. Pagination is handled by loadAJAX.js ( .page-numbers ). Search
1043 * re-queries the server ( debounced, resets to page 1 ); export asks the server
1044 * for the full CSV and downloads it.
1045 *
1046 * @since 4.4.2
1047 * @version 3.0.0
1048 */
1049
1050
1051
1052
1053
1054 class LpStatsReportModal {
1055 static selectors = {
1056 template: '#lp-tmpl-stats-report-modal',
1057 elContainer: '.lp-stats-report-modal',
1058 elSearch: '.lp-stats-report-modal__search',
1059 elExport: '.lp-stats-report-modal__export',
1060 elTarget: '.lp-target'
1061 };
1062 constructor() {
1063 this.title = '';
1064 this.tableId = '';
1065 }
1066 init() {
1067 this.events();
1068 }
1069 events() {
1070 if (LpStatsReportModal._loadedEvents) {
1071 return;
1072 }
1073 LpStatsReportModal._loadedEvents = this;
1074
1075 // Debounced ONCE here — never create a debounce inside a handler.
1076 this.debouncedSearch = lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.debounce(() => this.applySearch(), 400);
1077 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.eventHandlers('click', [{
1078 selector: LpStatsReportModal.selectors.elExport,
1079 class: this,
1080 callBack: this.exportCsv.name
1081 }]);
1082 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.eventHandlers('input', [{
1083 selector: LpStatsReportModal.selectors.elSearch,
1084 class: this,
1085 callBack: this.onSearchInput.name
1086 }]);
1087 }
1088
1089 /**
1090 * @return {Object|null} window.lpAJAXG when it exposes the API we need.
1091 */
1092 getAjaxHandle() {
1093 const handle = window.lpAJAXG;
1094 if (!handle || 'function' !== typeof handle.getDataSetCurrent || 'function' !== typeof handle.setDataSetCurrent || 'function' !== typeof handle.fetchAJAX || 'function' !== typeof handle.showHideLoading) {
1095 return null;
1096 }
1097 return handle;
1098 }
1099 getModalPopup() {
1100 return (sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().getPopup) ? sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().getPopup() : null;
1101 }
1102 getModalContent() {
1103 const popup = this.getModalPopup();
1104 if (!popup) {
1105 return null;
1106 }
1107 return popup.querySelector(LpStatsReportModal.selectors.elContainer);
1108 }
1109 getTarget() {
1110 const content = this.getModalContent();
1111 return content ? content.querySelector(LpStatsReportModal.selectors.elTarget) : null;
1112 }
1113 getModalHtml() {
1114 const template = document.querySelector(LpStatsReportModal.selectors.template);
1115 return template ? template.innerHTML : '';
1116 }
1117 isOpen() {
1118 return !!this.getModalContent();
1119 }
1120
1121 /**
1122 * @param {Object} report { report, title, tableId?, orderStatus? }
1123 * - report: server report slug ( e.g. 'top_courses' ).
1124 * - orderStatus: cancelled/failed deep-link for the exceptions report.
1125 */
1126 open(report = {}) {
1127 const modalHtml = this.getModalHtml();
1128 if (!modalHtml || !report.report) {
1129 return;
1130 }
1131 this.init();
1132 this.title = report.title || '';
1133 this.tableId = report.tableId || report.report;
1134 sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().fire({
1135 title: this.title,
1136 html: modalHtml,
1137 // Large by default; the custom class lets the SCSS push it (near) full size.
1138 width: '100%',
1139 customClass: {
1140 popup: 'lp-stats-report-popup'
1141 },
1142 showConfirmButton: false,
1143 showCloseButton: true,
1144 didOpen: () => this.loadReport(report)
1145 });
1146 }
1147 close() {
1148 sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().close();
1149 }
1150
1151 /**
1152 * Seed the .lp-target with report + current filters and fetch page 1.
1153 *
1154 * @param {Object} report
1155 */
1156 loadReport(report) {
1157 const target = this.getTarget();
1158 const handle = this.getAjaxHandle();
1159 if (!target || !handle) {
1160 if (target) {
1161 target.innerHTML = (0,_api_js__WEBPACK_IMPORTED_MODULE_3__.getStatsI18n)('loadError', 'Request failed.');
1162 }
1163 return;
1164 }
1165 const dataSend = handle.getDataSetCurrent(target);
1166 dataSend.args = {
1167 ...(dataSend.args || {}),
1168 ..._state_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsState.get(),
1169 report: report.report,
1170 search: '',
1171 paged: 1,
1172 // Report-specific args ( e.g. instructor_id ) win over the global filters.
1173 ...(report.args || {})
1174 };
1175 if (report.orderStatus) {
1176 dataSend.args.order_status = report.orderStatus;
1177 }
1178 handle.setDataSetCurrent(target, dataSend);
1179 this.reloadTarget(target, dataSend);
1180 }
1181 onSearchInput() {
1182 this.debouncedSearch();
1183 }
1184 applySearch() {
1185 const content = this.getModalContent();
1186 const target = this.getTarget();
1187 const handle = this.getAjaxHandle();
1188 if (!content || !target || !handle) {
1189 return;
1190 }
1191 const elSearch = content.querySelector(LpStatsReportModal.selectors.elSearch);
1192 const dataSend = handle.getDataSetCurrent(target);
1193 dataSend.args = dataSend.args || {};
1194 dataSend.args.search = (elSearch?.value || '').trim();
1195 dataSend.args.paged = 1;
1196 handle.setDataSetCurrent(target, dataSend);
1197 this.reloadTarget(target, dataSend);
1198 }
1199
1200 /**
1201 * Loading indicator + AJAX fetch, swapping the target's innerHTML.
1202 *
1203 * @param {Element} target
1204 * @param {Object} dataSend
1205 */
1206 reloadTarget(target, dataSend) {
1207 const handle = this.getAjaxHandle();
1208 if (!handle) {
1209 return;
1210 }
1211 handle.showHideLoading(target, 1);
1212 handle.fetchAJAX(dataSend, {
1213 success: response => {
1214 const {
1215 status,
1216 message,
1217 data
1218 } = response;
1219 if ('success' === status) {
1220 target.innerHTML = data.content || '';
1221 } else {
1222 target.innerHTML = message || (0,_api_js__WEBPACK_IMPORTED_MODULE_3__.getStatsI18n)('loadError', 'Request failed.');
1223 }
1224 },
1225 error: err => {
1226 // eslint-disable-next-line no-console
1227 console.error('LP Statistics report:', err);
1228 },
1229 completed: () => handle.showHideLoading(target, 0)
1230 });
1231 }
1232
1233 /**
1234 * Ask the server for the full ( capped ) CSV and download it.
1235 */
1236 exportCsv(args) {
1237 const content = this.getModalContent();
1238 const target = this.getTarget();
1239 const handle = this.getAjaxHandle();
1240 if (!content || !target || !handle) {
1241 return;
1242 }
1243 const btn = args?.target?.closest(LpStatsReportModal.selectors.elExport);
1244 if (!btn || btn.classList.contains('loading')) {
1245 return;
1246 }
1247
1248 // Clone the current request but hit the CSV callback.
1249 const current = handle.getDataSetCurrent(target);
1250 const dataSend = {
1251 ...current,
1252 args: {
1253 ...(current.args || {})
1254 },
1255 callback: {
1256 ...(current.callback || {}),
1257 method: 'render_report_csv'
1258 }
1259 };
1260 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(btn, 1);
1261 handle.fetchAJAX(dataSend, {
1262 success: response => {
1263 const {
1264 status,
1265 data
1266 } = response;
1267 if ('success' === status && data && data.csv) {
1268 this.download(data.filename || 'learnpress-report.csv', data.csv);
1269 }
1270 },
1271 error: err => {
1272 // eslint-disable-next-line no-console
1273 console.error('LP Statistics export:', err);
1274 },
1275 completed: () => lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(btn, 0)
1276 });
1277 }
1278
1279 /**
1280 * @param {string} filename
1281 * @param {string} csv
1282 */
1283 download(filename, csv) {
1284 // BOM keeps Excel reading UTF-8 (Vietnamese titles etc.).
1285 const blob = new Blob(['\u{FEFF}' + csv], {
1286 type: 'text/csv;charset=utf-8;'
1287 });
1288 const url = URL.createObjectURL(blob);
1289 const link = document.createElement('a');
1290 link.href = url;
1291 link.download = filename;
1292 document.body.appendChild(link);
1293 link.click();
1294 document.body.removeChild(link);
1295 URL.revokeObjectURL(url);
1296 }
1297 }
1298 const lpStatsReportModal = new LpStatsReportModal();
1299
1300 /***/ },
1301
1302 /***/ "./assets/src/js/admin/statistics/state.js"
1303 /*!*************************************************!*\
1304 !*** ./assets/src/js/admin/statistics/state.js ***!
1305 \*************************************************/
1306 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1307
1308 "use strict";
1309 __webpack_require__.r(__webpack_exports__);
1310 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1311 /* harmony export */ LP_STATS_EXPORT_CSV: () => (/* binding */ LP_STATS_EXPORT_CSV),
1312 /* harmony export */ LP_STATS_FILTER_CHANGED: () => (/* binding */ LP_STATS_FILTER_CHANGED),
1313 /* harmony export */ LP_STATS_RANGE_RESOLVED: () => (/* binding */ LP_STATS_RANGE_RESOLVED),
1314 /* harmony export */ LpStatsState: () => (/* binding */ LpStatsState),
1315 /* harmony export */ lpStatsState: () => (/* binding */ lpStatsState)
1316 /* harmony export */ });
1317 /**
1318 * Statistics dashboard shared filter state.
1319 *
1320 * The singleton is the ONLY mutation path: modules call lpStatsState.set()
1321 * and every tab module re-renders on the 'lp-stats:filter-changed' event.
1322 * Tab-specific deep-link params (e.g. order_status) are read by their own
1323 * tab module — only the four global filters live here.
1324 *
1325 * On every set() the five filters are written back to the URL (replaceState,
1326 * no history spam) so the current view is always copy/paste shareable; other
1327 * query params (page, tab, order_status, …) are preserved untouched.
1328 *
1329 * @since 4.4.2
1330 * @version 1.2.0
1331 */
1332
1333 const LP_STATS_FILTER_CHANGED = 'lp-stats:filter-changed';
1334 const LP_STATS_EXPORT_CSV = 'lp-stats:export-csv';
1335 // Server-resolved range echoed by a stats payload ( data.range ). Carries the
1336 // authoritative toggle label so the filter bar can reconcile its optimistic one.
1337 const LP_STATS_RANGE_RESOLVED = 'lp-stats:range-resolved';
1338 const COMPARE_DEFAULT = 'previous_period';
1339 class LpStatsState {
1340 constructor() {
1341 const params = new URL(window.location.href).searchParams;
1342 this.filters = {
1343 filtertype: params.get('filtertype') || 'today',
1344 date: params.get('date') || '',
1345 compare: 'previous_year' === params.get('compare') ? 'previous_year' : COMPARE_DEFAULT,
1346 instructor_id: parseInt(params.get('instructor_id'), 10) || 0,
1347 category_id: parseInt(params.get('category_id'), 10) || 0
1348 };
1349 }
1350 get() {
1351 return {
1352 ...this.filters
1353 };
1354 }
1355 set(partial = {}) {
1356 this.filters = {
1357 ...this.filters,
1358 ...partial
1359 };
1360 this.syncUrl();
1361 document.dispatchEvent(new CustomEvent(LP_STATS_FILTER_CHANGED, {
1362 detail: this.get()
1363 }));
1364 }
1365
1366 /**
1367 * Reflect the current filters in the URL without pushing a history entry.
1368 * Defaults (today / empty date / id 0) are dropped to keep URLs clean;
1369 * unrelated params (page, tab, order_status, …) are left as-is.
1370 */
1371 syncUrl() {
1372 if (!window.history || typeof window.history.replaceState !== 'function') {
1373 return;
1374 }
1375 const url = new URL(window.location.href);
1376 const params = url.searchParams;
1377 const {
1378 filtertype,
1379 date,
1380 compare,
1381 instructor_id: instructorId,
1382 category_id: categoryId
1383 } = this.filters;
1384 this.writeParam(params, 'filtertype', filtertype && filtertype !== 'today' ? filtertype : '');
1385 this.writeParam(params, 'date', date);
1386 this.writeParam(params, 'compare', compare && compare !== COMPARE_DEFAULT ? compare : '');
1387 this.writeParam(params, 'instructor_id', instructorId > 0 ? String(instructorId) : '');
1388 this.writeParam(params, 'category_id', categoryId > 0 ? String(categoryId) : '');
1389 window.history.replaceState(null, '', url.toString());
1390 }
1391
1392 /**
1393 * Set the param when a truthy value is given, otherwise remove it.
1394 */
1395 writeParam(params, key, value) {
1396 if (value) {
1397 params.set(key, value);
1398 } else {
1399 params.delete(key);
1400 }
1401 }
1402 }
1403 const lpStatsState = new LpStatsState();
1404
1405 /***/ },
1406
1407 /***/ "./assets/src/js/admin/statistics/tab-courses.js"
1408 /*!*******************************************************!*\
1409 !*** ./assets/src/js/admin/statistics/tab-courses.js ***!
1410 \*******************************************************/
1411 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1412
1413 "use strict";
1414 __webpack_require__.r(__webpack_exports__);
1415 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1416 /* harmony export */ LpStatsTabCourses: () => (/* binding */ LpStatsTabCourses),
1417 /* harmony export */ lpStatsTabCourses: () => (/* binding */ lpStatsTabCourses)
1418 /* harmony export */ });
1419 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
1420 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
1421 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
1422 /* harmony import */ var _kpi_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./kpi.js */ "./assets/src/js/admin/statistics/kpi.js");
1423 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
1424 /* harmony import */ var _data_table_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./data-table.js */ "./assets/src/js/admin/statistics/data-table.js");
1425 /* harmony import */ var _report_modal_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
1426 /* harmony import */ var _csv_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./csv.js */ "./assets/src/js/admin/statistics/csv.js");
1427 /**
1428 * Courses tab module.
1429 *
1430 * Fetches the `dashboard` payload and renders KPIs, course performance,
1431 * published-courses chart, health checks, inventory, popups and CSV export.
1432 *
1433 * @since 4.4.2
1434 * @version 1.0.0
1435 */
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445 const sprintfLite = (template, value) => String(template).replace(/%[ds]/, String(value)).replace(/%%/g, '%');
1446 class LpStatsTabCourses {
1447 static selectors = {
1448 elContainer: '.lp-stats-tab-courses',
1449 elChartCanvas: '#course-chart-content',
1450 elTablePerformance: '.lp-stats-table-course-performance',
1451 elTableInventory: '.lp-stats-table-content-inventory',
1452 elBtnViewAllPerformance: '.lp-stats-view-all-performance',
1453 elPerformanceRow: '.lp-stats-course-performance-row',
1454 elHealthCheckCount: '.lp-stats-health-check__count',
1455 elSkeleton: '.lp-skeleton-animation'
1456 };
1457 static kpiCards = {
1458 published: '.lp-kpi-published',
1459 pending_review: '.lp-kpi-pending-review',
1460 future: '.lp-kpi-future',
1461 enrollments: '.lp-kpi-enrollments',
1462 avg_completion: '.lp-kpi-avg-completion',
1463 courses_without_enrollment: '.lp-kpi-courses-without-enrollment'
1464 };
1465 constructor() {
1466 this.elContainer = null;
1467 this.isRequesting = false;
1468 this.pendingReload = false;
1469 this.tables = {};
1470 }
1471 init() {
1472 this.elContainer = document.querySelector(LpStatsTabCourses.selectors.elContainer);
1473 if (!this.elContainer) {
1474 return;
1475 }
1476 this.events();
1477 this.loadData();
1478 }
1479 events() {
1480 if (LpStatsTabCourses._loadedEvents) {
1481 return;
1482 }
1483 LpStatsTabCourses._loadedEvents = this;
1484 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
1485 selector: LpStatsTabCourses.selectors.elBtnViewAllPerformance,
1486 class: this,
1487 callBack: this.viewAllPerformance.name
1488 }, {
1489 selector: LpStatsTabCourses.selectors.elPerformanceRow,
1490 class: this,
1491 callBack: this.openCourseEdit.name
1492 }]);
1493 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, () => this.loadData());
1494 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV, () => this.exportTables());
1495 }
1496 toggleSkeletons(show) {
1497 this.elContainer.querySelectorAll(LpStatsTabCourses.selectors.elSkeleton).forEach(el => {
1498 el.style.display = show ? 'block' : 'none';
1499 });
1500 }
1501 loadData() {
1502 if (this.isRequesting) {
1503 this.pendingReload = true;
1504 return;
1505 }
1506 this.isRequesting = true;
1507 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('course-statistics', {}, {
1508 before: () => this.toggleSkeletons(true),
1509 success: response => this.render(response.data),
1510 error: err => {
1511 console.error('LP Statistics courses:', err);
1512 this.render(null);
1513 },
1514 completed: () => {
1515 this.toggleSkeletons(false);
1516 this.isRequesting = false;
1517 if (this.pendingReload) {
1518 this.pendingReload = false;
1519 this.loadData();
1520 }
1521 }
1522 });
1523 }
1524 render(data) {
1525 if (!data?.dashboard) {
1526 console.error('LP Statistics courses: dashboard payload missing.');
1527 data = {
1528 chart_data: {},
1529 dashboard: {}
1530 };
1531 }
1532 const dashboard = data.dashboard || {};
1533 this.renderKpis(dashboard.kpis || {});
1534 this.renderTables(dashboard);
1535 // Prefer the scoped chart from the dashboard payload so instructor/category
1536 // changes redraw the chart; fall back to the legacy unscoped series.
1537 this.renderChart(dashboard.chart || data.chart_data || {});
1538 this.renderHealthChecks(dashboard.health_checks || {});
1539 }
1540 renderKpis(kpis) {
1541 Object.entries(LpStatsTabCourses.kpiCards).forEach(([key, selector]) => {
1542 const elCard = this.elContainer.querySelector(selector);
1543 const payload = {
1544 ...(kpis[key] || {})
1545 };
1546 if ('published' === key) {
1547 var _payload$added_in_per;
1548 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('addedThisPeriod', '%d added this period'), (_payload$added_in_per = payload.added_in_period) !== null && _payload$added_in_per !== void 0 ? _payload$added_in_per : 0);
1549 }
1550 if ('pending_review' === key) {
1551 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('needsInstructorAction', 'Needs instructor action');
1552 }
1553 if ('future' === key) {
1554 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('scheduledReleases', 'Scheduled releases');
1555 }
1556 if ('avg_completion' === key) {
1557 var _ref, _payload$target;
1558 if ('number' === typeof payload.value) {
1559 payload.formatted = `${payload.value}%`;
1560 }
1561 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('targetPercent', 'Target: %s%%'), (_ref = (_payload$target = payload.target) !== null && _payload$target !== void 0 ? _payload$target : (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)().completionTarget) !== null && _ref !== void 0 ? _ref : 0);
1562 }
1563 (0,_kpi_js__WEBPACK_IMPORTED_MODULE_3__.renderKpi)(elCard, payload);
1564 if ('avg_completion' === key) {
1565 this.renderCompletionProgress(elCard, payload);
1566 }
1567 });
1568 }
1569 renderCompletionProgress(elCard, payload) {
1570 const elBar = elCard?.querySelector('.lp-kpi-progress__bar');
1571 if (!elBar) {
1572 return;
1573 }
1574 const value = Number(payload.value || 0);
1575 const target = Number(payload.target || (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)().completionTarget || 0);
1576 const width = target > 0 ? Math.min(100, value / target * 100) : 0;
1577 elBar.style.width = `${width}%`;
1578 }
1579 renderChart(chartData) {
1580 (0,_chart_js__WEBPACK_IMPORTED_MODULE_4__.renderLineChart)(LpStatsTabCourses.selectors.elChartCanvas, {
1581 labels: chartData.labels || [],
1582 datasets: [{
1583 label: chartData.line_label || (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('publishedCourses', 'Published courses'),
1584 data: chartData.data || [],
1585 yAxisID: 'y'
1586 }],
1587 xLabel: chartData.x_label || '',
1588 granularity: chartData.granularity || ''
1589 }, {
1590 yCurrency: false
1591 });
1592 }
1593 completionBadge(rate) {
1594 var _completionBadge$gree, _completionBadge$yell;
1595 if (null == rate) {
1596 return '';
1597 }
1598 const {
1599 completionBadge = {}
1600 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)();
1601 const green = (_completionBadge$gree = completionBadge.green) !== null && _completionBadge$gree !== void 0 ? _completionBadge$gree : 60;
1602 const yellow = (_completionBadge$yell = completionBadge.yellow) !== null && _completionBadge$yell !== void 0 ? _completionBadge$yell : 40;
1603 if (rate >= green) {
1604 return 'green';
1605 }
1606 return rate >= yellow ? 'yellow' : 'red';
1607 }
1608 performanceColumns() {
1609 return [{
1610 key: 'name',
1611 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
1612 }, {
1613 key: 'instructor',
1614 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructor', 'Instructor')
1615 }, {
1616 key: 'revenue_formatted',
1617 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
1618 csv: row => row.revenue
1619 }, {
1620 key: 'enrollments',
1621 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrollments', 'Enrollments')
1622 }, {
1623 key: 'completion_rate',
1624 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
1625 format: value => null == value ? '-' : `${value}%`,
1626 badge: row => this.completionBadge(row.completion_rate)
1627 }];
1628 }
1629 inventoryLabel(key) {
1630 const labels = {
1631 courses: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('courses', 'Courses'),
1632 lessons: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('lessons', 'Lessons'),
1633 quizzes: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('quizzes', 'Quizzes'),
1634 assignments: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('assignments', 'Assignments')
1635 };
1636 return labels[key] || String(key || '');
1637 }
1638 inventoryStatusLabel(key) {
1639 const labels = {
1640 publish: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('published', 'Published'),
1641 pending: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('pending', 'Pending'),
1642 future: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('future', 'Future'),
1643 draft: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('drafts', 'Drafts'),
1644 total: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('total', 'Total')
1645 };
1646 return labels[key] || String(key || '');
1647 }
1648 inventoryRows(inventory = {}) {
1649 return Object.entries(inventory).map(([type, counts]) => ({
1650 type,
1651 label: this.inventoryLabel(type),
1652 ...(counts || {})
1653 }));
1654 }
1655 inventoryColumns(rows = []) {
1656 const preferred = ['publish', 'pending', 'future', 'draft', 'total'];
1657 const statusKeys = preferred.filter(key => rows.some(row => Object.prototype.hasOwnProperty.call(row, key)));
1658 return [{
1659 key: 'label',
1660 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('content', 'Content')
1661 }, ...statusKeys.map(key => ({
1662 key,
1663 label: this.inventoryStatusLabel(key),
1664 csv: row => row[key]
1665 }))];
1666 }
1667 renderTables(dashboard) {
1668 const performanceRows = dashboard.performance || [];
1669 const performanceHandle = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabCourses.selectors.elTablePerformance), this.performanceColumns(), performanceRows, {
1670 emptyText: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('noCoursePerformance', 'No course performance data in this period.')
1671 });
1672 this.tables.performance = performanceHandle;
1673 this.decoratePerformanceRows(performanceRows);
1674 const inventoryRows = this.inventoryRows(dashboard.inventory || {});
1675 this.tables.inventory = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabCourses.selectors.elTableInventory), this.inventoryColumns(inventoryRows), inventoryRows);
1676 }
1677 decoratePerformanceRows(rows = []) {
1678 const tableRows = this.elContainer.querySelectorAll(`${LpStatsTabCourses.selectors.elTablePerformance} tbody tr`);
1679 rows.forEach((row, index) => {
1680 const tableRow = tableRows[index];
1681 if (tableRow && row.edit_link) {
1682 tableRow.classList.add('lp-stats-course-performance-row');
1683 tableRow.dataset.editLink = row.edit_link;
1684 }
1685 });
1686 }
1687 renderHealthChecks(healthChecks) {
1688 this.elContainer.querySelectorAll(LpStatsTabCourses.selectors.elHealthCheckCount).forEach(elCount => {
1689 var _healthChecks$check;
1690 const check = elCount.dataset.check;
1691 elCount.textContent = String((_healthChecks$check = healthChecks[check]) !== null && _healthChecks$check !== void 0 ? _healthChecks$check : 0);
1692 });
1693 }
1694 openCourseEdit(args) {
1695 const row = args.target.closest(LpStatsTabCourses.selectors.elPerformanceRow);
1696 if (!row || !this.elContainer.contains(row)) {
1697 return;
1698 }
1699 const editLink = row.dataset.editLink || '';
1700 const adminUrl = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)().adminUrl || '';
1701 if (editLink && adminUrl && editLink.startsWith(adminUrl)) {
1702 window.location.href = editLink;
1703 }
1704 }
1705 viewAllPerformance(args) {
1706 const btn = args.target.closest(LpStatsTabCourses.selectors.elBtnViewAllPerformance);
1707 if (!btn || !this.elContainer.contains(btn)) {
1708 return;
1709 }
1710 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
1711 report: 'course_performance',
1712 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('coursePerformance', 'Course performance'),
1713 tableId: 'course-performance'
1714 });
1715 }
1716 exportTables() {
1717 Object.entries(this.tables).forEach(([tableId, handle]) => {
1718 if (handle && handle.rows.length) {
1719 (0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.exportCsv)((0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.buildCsvFilename)('courses', tableId), handle.columns, handle.rows);
1720 }
1721 });
1722 }
1723 }
1724 const lpStatsTabCourses = new LpStatsTabCourses();
1725
1726 /***/ },
1727
1728 /***/ "./assets/src/js/admin/statistics/tab-instructors.js"
1729 /*!***********************************************************!*\
1730 !*** ./assets/src/js/admin/statistics/tab-instructors.js ***!
1731 \***********************************************************/
1732 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1733
1734 "use strict";
1735 __webpack_require__.r(__webpack_exports__);
1736 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1737 /* harmony export */ LpStatsTabInstructors: () => (/* binding */ LpStatsTabInstructors),
1738 /* harmony export */ lpStatsTabInstructors: () => (/* binding */ lpStatsTabInstructors)
1739 /* harmony export */ });
1740 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
1741 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
1742 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
1743 /* harmony import */ var _kpi_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./kpi.js */ "./assets/src/js/admin/statistics/kpi.js");
1744 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
1745 /* harmony import */ var _data_table_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./data-table.js */ "./assets/src/js/admin/statistics/data-table.js");
1746 /* harmony import */ var _report_modal_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
1747 /* harmony import */ var _csv_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./csv.js */ "./assets/src/js/admin/statistics/csv.js");
1748 /**
1749 * Instructors tab module.
1750 *
1751 * Fetches the `dashboard` payload and renders KPIs, the operations widget,
1752 * instructor performance + course watchlist tables, per-instructor report
1753 * popup, and CSV export.
1754 *
1755 * @since 4.4.2
1756 * @version 1.0.0
1757 */
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767 const sprintfLite = (template, value) => String(template).replace(/%[ds]/, String(value)).replace(/%%/g, '%');
1768 class LpStatsTabInstructors {
1769 static selectors = {
1770 elContainer: '.lp-stats-tab-instructors',
1771 elChartCanvas: '#instructor-chart-content',
1772 elTablePerformance: '.lp-stats-table-instructor-performance',
1773 elTableWatchlist: '.lp-stats-table-instructor-watchlist',
1774 elBtnViewAllInstructors: '.lp-stats-view-all-instructors',
1775 elPerformanceRow: '.lp-stats-instructor-performance-row',
1776 elOperationsRow: '.lp-stats-operations__row',
1777 elSkeleton: '.lp-skeleton-animation'
1778 };
1779 static kpiCards = {
1780 active_instructors: '.lp-kpi-active-instructors',
1781 instructor_revenue: '.lp-kpi-instructor-revenue',
1782 courses_managed: '.lp-kpi-courses-managed',
1783 students_reached: '.lp-kpi-students-reached',
1784 avg_completion: '.lp-kpi-avg-completion',
1785 needs_review: '.lp-kpi-needs-review'
1786 };
1787 constructor() {
1788 this.elContainer = null;
1789 this.isRequesting = false;
1790 this.pendingReload = false;
1791 this.tables = {};
1792 }
1793 init() {
1794 this.elContainer = document.querySelector(LpStatsTabInstructors.selectors.elContainer);
1795 if (!this.elContainer) {
1796 return;
1797 }
1798 this.events();
1799 this.loadData();
1800 }
1801 events() {
1802 if (LpStatsTabInstructors._loadedEvents) {
1803 return;
1804 }
1805 LpStatsTabInstructors._loadedEvents = this;
1806 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
1807 selector: LpStatsTabInstructors.selectors.elBtnViewAllInstructors,
1808 class: this,
1809 callBack: this.viewAllInstructors.name
1810 }, {
1811 selector: LpStatsTabInstructors.selectors.elPerformanceRow,
1812 class: this,
1813 callBack: this.openInstructorReport.name
1814 }]);
1815 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, () => this.loadData());
1816 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV, () => this.exportTables());
1817 }
1818 toggleSkeletons(show) {
1819 this.elContainer.querySelectorAll(LpStatsTabInstructors.selectors.elSkeleton).forEach(el => {
1820 el.style.display = show ? 'block' : 'none';
1821 });
1822 }
1823 loadData() {
1824 if (this.isRequesting) {
1825 this.pendingReload = true;
1826 return;
1827 }
1828 this.isRequesting = true;
1829 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('instructor-statistics', {}, {
1830 before: () => this.toggleSkeletons(true),
1831 success: response => this.render(response.data),
1832 error: err => {
1833 console.error('LP Statistics instructors:', err);
1834 this.render(null);
1835 },
1836 completed: () => {
1837 this.toggleSkeletons(false);
1838 this.isRequesting = false;
1839 if (this.pendingReload) {
1840 this.pendingReload = false;
1841 this.loadData();
1842 }
1843 }
1844 });
1845 }
1846 render(data) {
1847 if (!data?.dashboard) {
1848 console.error('LP Statistics instructors: dashboard payload missing.');
1849 data = {
1850 chart_data: {},
1851 dashboard: {}
1852 };
1853 }
1854 const dashboard = data.dashboard || {};
1855 this.renderKpis(dashboard.kpis || {});
1856 this.renderChart(data.chart_data || {});
1857 this.renderOperations(dashboard.operations || {});
1858 this.renderTables(dashboard);
1859 }
1860 renderKpis(kpis) {
1861 Object.entries(LpStatsTabInstructors.kpiCards).forEach(([key, selector]) => {
1862 const elCard = this.elContainer.querySelector(selector);
1863 const payload = {
1864 ...(kpis[key] || {})
1865 };
1866 if ('active_instructors' === key) {
1867 var _payload$total;
1868 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('ofTotalInstructors', '%d total'), (_payload$total = payload.total) !== null && _payload$total !== void 0 ? _payload$total : 0);
1869 }
1870 if ('instructor_revenue' === key && null != payload.contribution_pct) {
1871 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('ofNetSales', '%s%% of net sales'), payload.contribution_pct);
1872 }
1873 if ('avg_completion' === key && 'number' === typeof payload.value) {
1874 payload.formatted = `${payload.value}%`;
1875 }
1876 (0,_kpi_js__WEBPACK_IMPORTED_MODULE_3__.renderKpi)(elCard, payload);
1877 });
1878 }
1879 renderChart(chartData) {
1880 (0,_chart_js__WEBPACK_IMPORTED_MODULE_4__.renderLineChart)(LpStatsTabInstructors.selectors.elChartCanvas, {
1881 labels: chartData.labels || [],
1882 datasets: [{
1883 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
1884 data: chartData.revenue || [],
1885 yAxisID: 'y'
1886 }, {
1887 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrollments', 'Enrollments'),
1888 data: chartData.enrollments || [],
1889 yAxisID: 'y1'
1890 }],
1891 xLabel: chartData.x_label || '',
1892 granularity: chartData.granularity || ''
1893 });
1894 }
1895 renderOperations(operations) {
1896 this.elContainer.querySelectorAll(LpStatsTabInstructors.selectors.elOperationsRow).forEach(elRow => {
1897 const op = elRow.dataset.op;
1898 const elValue = elRow.querySelector('.lp-stats-operations__value');
1899 const elName = elRow.querySelector('.lp-stats-operations__name');
1900 const data = operations[op];
1901 if (elName) {
1902 elName.textContent = '';
1903 }
1904 if (null == data) {
1905 if (elValue) {
1906 elValue.textContent = '–';
1907 }
1908 return;
1909 }
1910
1911 // Scalar operations (counts) vs highlight objects ({ name, value }).
1912 if ('object' === typeof data) {
1913 if (elValue) {
1914 var _data$value_formatted, _data$value;
1915 elValue.textContent = (_data$value_formatted = data.value_formatted) !== null && _data$value_formatted !== void 0 ? _data$value_formatted : 'number' === typeof data.value && op === 'top_completion' ? `${data.value}%` : String((_data$value = data.value) !== null && _data$value !== void 0 ? _data$value : '');
1916 }
1917 if (elName) {
1918 elName.textContent = data.name || '';
1919 }
1920 } else if (elValue) {
1921 elValue.textContent = String(data);
1922 }
1923 });
1924 }
1925 completionBadge(rate) {
1926 var _completionBadge$gree, _completionBadge$yell;
1927 if (null == rate) {
1928 return '';
1929 }
1930 const {
1931 completionBadge = {}
1932 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)();
1933 const green = (_completionBadge$gree = completionBadge.green) !== null && _completionBadge$gree !== void 0 ? _completionBadge$gree : 60;
1934 const yellow = (_completionBadge$yell = completionBadge.yellow) !== null && _completionBadge$yell !== void 0 ? _completionBadge$yell : 40;
1935 if (rate >= green) {
1936 return 'green';
1937 }
1938 return rate >= yellow ? 'yellow' : 'red';
1939 }
1940 riskLabel(slug) {
1941 const labels = {
1942 high: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('riskHigh', 'High'),
1943 medium: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('riskMedium', 'Medium'),
1944 healthy: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('riskHealthy', 'Healthy')
1945 };
1946 return labels[slug] || String(slug || '');
1947 }
1948 actionLabel(slug) {
1949 const {
1950 watchlistActions = {}
1951 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)().i18n || {};
1952 return watchlistActions[slug] || String(slug || '');
1953 }
1954 performanceColumns() {
1955 return [{
1956 key: 'name',
1957 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructor', 'Instructor')
1958 }, {
1959 key: 'courses',
1960 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('courses', 'Courses')
1961 }, {
1962 key: 'students',
1963 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('students', 'Students')
1964 }, {
1965 key: 'revenue_formatted',
1966 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
1967 csv: row => row.revenue
1968 }, {
1969 key: 'avg_completion',
1970 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
1971 format: value => null == value ? '–' : `${value}%`,
1972 badge: row => this.completionBadge(row.avg_completion)
1973 }];
1974 }
1975 watchlistColumns() {
1976 return [{
1977 key: 'name',
1978 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
1979 }, {
1980 key: 'instructor',
1981 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructor', 'Instructor')
1982 }, {
1983 key: 'completion_rate',
1984 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
1985 format: value => null == value ? '–' : `${value}%`
1986 }, {
1987 key: 'risk',
1988 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('risk', 'Risk'),
1989 // Emoji lives in CSS pseudo-content on .lp-risk--{slug}; text stays clean.
1990 format: value => {
1991 const span = document.createElement('span');
1992 span.className = `lp-badge lp-risk lp-risk--${value}`;
1993 span.textContent = this.riskLabel(value);
1994 return span;
1995 },
1996 csv: row => this.riskLabel(row.risk)
1997 }, {
1998 key: 'action',
1999 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('actionRequired', 'Action required'),
2000 format: value => this.actionLabel(value),
2001 csv: row => this.actionLabel(row.action)
2002 }];
2003 }
2004 renderTables(dashboard) {
2005 const performanceRows = dashboard.performance || [];
2006 this.tables.performance = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabInstructors.selectors.elTablePerformance), this.performanceColumns(), performanceRows, {
2007 emptyText: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('noInstructorData', 'No instructor data in this period.')
2008 });
2009 this.decoratePerformanceRows(performanceRows);
2010 this.tables.watchlist = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabInstructors.selectors.elTableWatchlist), this.watchlistColumns(), dashboard.watchlist || []);
2011 }
2012 decoratePerformanceRows(rows = []) {
2013 const scopedInstructor = _state_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsState.get().instructor_id;
2014 const tableRows = this.elContainer.querySelectorAll(`${LpStatsTabInstructors.selectors.elTablePerformance} tbody tr`);
2015 rows.forEach((row, index) => {
2016 const tableRow = tableRows[index];
2017 if (!tableRow || !row.instructor_id) {
2018 return;
2019 }
2020 tableRow.classList.add('lp-stats-instructor-performance-row');
2021 tableRow.dataset.instructorId = String(row.instructor_id);
2022 tableRow.dataset.instructorName = row.name || '';
2023 if (scopedInstructor && scopedInstructor === row.instructor_id) {
2024 tableRow.classList.add('is-highlighted');
2025 }
2026 });
2027 }
2028 openInstructorReport(args) {
2029 const row = args.target.closest(LpStatsTabInstructors.selectors.elPerformanceRow);
2030 if (!row || !this.elContainer.contains(row)) {
2031 return;
2032 }
2033 const instructorId = parseInt(row.dataset.instructorId, 10) || 0;
2034 if (instructorId <= 0) {
2035 return;
2036 }
2037 const instructorName = row.dataset.instructorName || (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructorReport', 'Instructor report');
2038 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
2039 report: 'instructor_report',
2040 title: instructorName,
2041 tableId: `instructor-${instructorId}`,
2042 args: {
2043 instructor_id: instructorId
2044 }
2045 });
2046 }
2047 viewAllInstructors(args) {
2048 const btn = args.target.closest(LpStatsTabInstructors.selectors.elBtnViewAllInstructors);
2049 if (!btn || !this.elContainer.contains(btn)) {
2050 return;
2051 }
2052 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
2053 report: 'instructor_performance',
2054 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructorPerformance', 'Instructor performance'),
2055 tableId: 'instructor-performance'
2056 });
2057 }
2058 exportTables() {
2059 Object.entries(this.tables).forEach(([tableId, handle]) => {
2060 if (handle && handle.rows.length) {
2061 (0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.exportCsv)((0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.buildCsvFilename)('instructors', tableId), handle.columns, handle.rows);
2062 }
2063 });
2064 }
2065 }
2066 const lpStatsTabInstructors = new LpStatsTabInstructors();
2067
2068 /***/ },
2069
2070 /***/ "./assets/src/js/admin/statistics/tab-orders.js"
2071 /*!******************************************************!*\
2072 !*** ./assets/src/js/admin/statistics/tab-orders.js ***!
2073 \******************************************************/
2074 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2075
2076 "use strict";
2077 __webpack_require__.r(__webpack_exports__);
2078 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2079 /* harmony export */ LpStatsTabOrders: () => (/* binding */ LpStatsTabOrders),
2080 /* harmony export */ lpStatsTabOrders: () => (/* binding */ lpStatsTabOrders)
2081 /* harmony export */ });
2082 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
2083 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
2084 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
2085 /* harmony import */ var _kpi_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./kpi.js */ "./assets/src/js/admin/statistics/kpi.js");
2086 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
2087 /* harmony import */ var _data_table_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./data-table.js */ "./assets/src/js/admin/statistics/data-table.js");
2088 /* harmony import */ var _report_modal_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
2089 /* harmony import */ var _csv_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./csv.js */ "./assets/src/js/admin/statistics/csv.js");
2090 /**
2091 * Orders tab module.
2092 *
2093 * Fetches the `dashboard` payload and renders KPIs, completed-orders chart,
2094 * top sold courses, recent exceptions, popups and CSV export.
2095 *
2096 * @since 4.4.2
2097 * @version 1.0.0
2098 */
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108 const sprintfLite = (template, value) => String(template).replace(/%[ds]/, String(value)).replace(/%%/g, '%');
2109 class LpStatsTabOrders {
2110 static selectors = {
2111 elContainer: '.lp-stats-tab-orders',
2112 elChartCanvas: '#orders-chart-content',
2113 elTableTopSold: '.lp-stats-table-top-sold-courses',
2114 elTableExceptions: '.lp-stats-table-order-exceptions',
2115 elBtnViewAllTopSold: '.lp-stats-view-all-top-sold',
2116 elBtnViewAllExceptions: '.lp-stats-view-all-exceptions',
2117 elPaymentHealthRow: '.lp-stats-payment-health__row',
2118 elSkeleton: '.lp-skeleton-animation'
2119 };
2120 static kpiCards = {
2121 net_sales: '.lp-kpi-net-sales',
2122 completed_orders: '.lp-kpi-completed-orders',
2123 processing: '.lp-kpi-processing',
2124 pending: '.lp-kpi-pending',
2125 cancelled_failed: '.lp-kpi-cancelled-failed',
2126 paid_courses_sold: '.lp-kpi-paid-courses-sold'
2127 };
2128 static orderStatusAllowlist = ['completed', 'processing', 'pending', 'cancelled', 'failed'];
2129 constructor() {
2130 this.elContainer = null;
2131 this.isRequesting = false;
2132 this.pendingReload = false;
2133 this.tables = {};
2134 this.orderStatusFilter = '';
2135 }
2136 init() {
2137 this.elContainer = document.querySelector(LpStatsTabOrders.selectors.elContainer);
2138 if (!this.elContainer) {
2139 return;
2140 }
2141 this.orderStatusFilter = this.readOrderStatus();
2142 this.events();
2143 this.loadData();
2144 }
2145 events() {
2146 if (LpStatsTabOrders._loadedEvents) {
2147 return;
2148 }
2149 LpStatsTabOrders._loadedEvents = this;
2150 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
2151 selector: LpStatsTabOrders.selectors.elBtnViewAllTopSold,
2152 class: this,
2153 callBack: this.viewAllTopSold.name
2154 }, {
2155 selector: LpStatsTabOrders.selectors.elBtnViewAllExceptions,
2156 class: this,
2157 callBack: this.viewAllExceptions.name
2158 }]);
2159 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, () => this.loadData());
2160 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV, () => this.exportTables());
2161 }
2162 readOrderStatus() {
2163 const status = new URL(window.location.href).searchParams.get('order_status');
2164 return LpStatsTabOrders.orderStatusAllowlist.includes(status) ? status : '';
2165 }
2166 toggleSkeletons(show) {
2167 this.elContainer.querySelectorAll(LpStatsTabOrders.selectors.elSkeleton).forEach(el => {
2168 el.style.display = show ? 'block' : 'none';
2169 });
2170 }
2171 loadData() {
2172 if (this.isRequesting) {
2173 this.pendingReload = true;
2174 return;
2175 }
2176 this.isRequesting = true;
2177 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('order-statistics', {}, {
2178 before: () => this.toggleSkeletons(true),
2179 success: response => this.render(response.data),
2180 error: err => {
2181 console.error('LP Statistics orders:', err);
2182 this.render(null);
2183 },
2184 completed: () => {
2185 this.toggleSkeletons(false);
2186 this.isRequesting = false;
2187 if (this.pendingReload) {
2188 this.pendingReload = false;
2189 this.loadData();
2190 }
2191 }
2192 });
2193 }
2194 render(data) {
2195 if (!data?.dashboard) {
2196 console.error('LP Statistics orders: dashboard payload missing.');
2197 data = {
2198 chart_data: {},
2199 dashboard: {}
2200 };
2201 }
2202 const dashboard = data.dashboard || {};
2203 this.renderKpis(dashboard.kpis || {});
2204 this.renderChart(data.chart_data || {});
2205 this.renderPaymentHealth(dashboard.order_health || {});
2206 this.renderTables(dashboard);
2207 this.highlightStatus();
2208 }
2209 renderKpis(kpis) {
2210 Object.entries(LpStatsTabOrders.kpiCards).forEach(([key, selector]) => {
2211 const elCard = this.elContainer.querySelector(selector);
2212 const payload = {
2213 ...(kpis[key] || {})
2214 };
2215 if ('completed_orders' === key && payload.aov_formatted) {
2216 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('aov', 'Avg. order value: %s'), payload.aov_formatted);
2217 }
2218 if ('processing' === key) {
2219 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('needsFulfillmentReview', 'Needs fulfillment review');
2220 }
2221 if ('pending' === key) {
2222 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('awaitingPayment', 'Awaiting payment');
2223 }
2224 if ('cancelled_failed' === key && null != payload.rate_pct) {
2225 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('exceptionRate', '%s%% of all orders'), payload.rate_pct);
2226 }
2227 (0,_kpi_js__WEBPACK_IMPORTED_MODULE_3__.renderKpi)(elCard, payload);
2228 });
2229 }
2230 renderPaymentHealth(orderHealth) {
2231 this.elContainer.querySelectorAll(LpStatsTabOrders.selectors.elPaymentHealthRow).forEach(elRow => {
2232 const status = elRow.dataset.status;
2233 const elCount = elRow.querySelector('.lp-stats-payment-health__count');
2234 if (elCount) {
2235 var _orderHealth$status;
2236 elCount.textContent = String((_orderHealth$status = orderHealth[status]) !== null && _orderHealth$status !== void 0 ? _orderHealth$status : 0);
2237 }
2238 });
2239 }
2240 renderChart(chartData) {
2241 (0,_chart_js__WEBPACK_IMPORTED_MODULE_4__.renderLineChart)(LpStatsTabOrders.selectors.elChartCanvas, {
2242 labels: chartData.labels || [],
2243 datasets: [{
2244 label: chartData.line_label || (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('orders', 'Orders'),
2245 data: chartData.data || [],
2246 yAxisID: 'y'
2247 }],
2248 xLabel: chartData.x_label || '',
2249 granularity: chartData.granularity || ''
2250 }, {
2251 yCurrency: false
2252 });
2253 }
2254 statusLabel(slug) {
2255 const labels = {
2256 healthy: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('healthy', 'Healthy'),
2257 watch_completion: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('watchCompletion', 'Watch completion'),
2258 high_failed_quizzes: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('highFailedQuizzes', 'High failed quizzes')
2259 };
2260 return labels[slug] || String(slug || '');
2261 }
2262 statusBadge(slug) {
2263 if ('high_failed_quizzes' === slug) {
2264 return 'red';
2265 }
2266 if ('watch_completion' === slug) {
2267 return 'yellow';
2268 }
2269 return 'green';
2270 }
2271 severityLabel(severity) {
2272 const labels = {
2273 high: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('high', 'High'),
2274 medium: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('medium', 'Medium'),
2275 low: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('low', 'Low')
2276 };
2277 return labels[severity] || String(severity || '');
2278 }
2279 severityBadge(severity) {
2280 if ('high' === severity) {
2281 return 'red';
2282 }
2283 if ('medium' === severity) {
2284 return 'yellow';
2285 }
2286 return 'grey';
2287 }
2288 topSoldColumns() {
2289 return [{
2290 key: 'name',
2291 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
2292 }, {
2293 key: 'revenue_formatted',
2294 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
2295 csv: row => row.revenue
2296 }, {
2297 key: 'orders',
2298 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('orders', 'Orders')
2299 }, {
2300 key: 'aov_formatted',
2301 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('aovShort', 'AOV'),
2302 csv: row => row.aov
2303 }, {
2304 key: 'status_label',
2305 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('status', 'Status'),
2306 format: value => this.statusLabel(value),
2307 badge: row => this.statusBadge(row.status_label)
2308 }];
2309 }
2310 exceptionColumns() {
2311 return [{
2312 key: 'order_id',
2313 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('orderId', 'Order ID'),
2314 format: (value, row) => {
2315 if (!row.edit_link) {
2316 return value;
2317 }
2318 const link = document.createElement('a');
2319 link.href = row.edit_link;
2320 link.textContent = `#${value}`;
2321 return link;
2322 },
2323 csv: row => row.order_id
2324 }, {
2325 key: 'student',
2326 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('student', 'Student')
2327 }, {
2328 key: 'course',
2329 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
2330 }, {
2331 key: 'issue',
2332 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('issue', 'Issue')
2333 }, {
2334 key: 'date',
2335 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('date', 'Date')
2336 }, {
2337 key: 'severity',
2338 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('severity', 'Severity'),
2339 format: value => this.severityLabel(value),
2340 badge: row => this.severityBadge(row.severity)
2341 }];
2342 }
2343 filterExceptions(rows = []) {
2344 if (!['cancelled', 'failed'].includes(this.orderStatusFilter)) {
2345 return rows;
2346 }
2347 return rows.filter(row => row.status === this.orderStatusFilter);
2348 }
2349 renderTables(dashboard) {
2350 this.tables['top-sold-courses'] = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabOrders.selectors.elTableTopSold), this.topSoldColumns(), dashboard.top_sold_courses || []);
2351 const exceptionRows = this.filterExceptions(dashboard.exceptions || []);
2352 const exceptionHandle = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabOrders.selectors.elTableExceptions), this.exceptionColumns(), exceptionRows, {
2353 emptyText: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('noOrderExceptions', 'No failed or cancelled orders in this period.')
2354 });
2355 this.tables.exceptions = {
2356 ...exceptionHandle,
2357 rows: exceptionRows,
2358 allRows: dashboard.exceptions || []
2359 };
2360 }
2361 highlightStatus() {
2362 Object.values(LpStatsTabOrders.kpiCards).forEach(selector => {
2363 const elCard = this.elContainer.querySelector(selector);
2364 if (elCard) {
2365 elCard.classList.remove('is-highlighted');
2366 }
2367 });
2368 const statusMap = {
2369 completed: 'completed_orders',
2370 processing: 'processing',
2371 pending: 'pending',
2372 cancelled: 'cancelled_failed',
2373 failed: 'cancelled_failed'
2374 };
2375 const kpiKey = statusMap[this.orderStatusFilter];
2376 const selector = kpiKey ? LpStatsTabOrders.kpiCards[kpiKey] : '';
2377 const elCard = selector ? this.elContainer.querySelector(selector) : null;
2378 if (elCard) {
2379 elCard.classList.add('is-highlighted');
2380 }
2381 }
2382 viewAllTopSold(args) {
2383 const btn = args.target.closest(LpStatsTabOrders.selectors.elBtnViewAllTopSold);
2384 if (!btn || !this.elContainer.contains(btn)) {
2385 return;
2386 }
2387 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
2388 report: 'top_sold_courses',
2389 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('topSoldCourses', 'Top sold courses'),
2390 tableId: 'top-sold-courses'
2391 });
2392 }
2393 viewAllExceptions(args) {
2394 const btn = args.target.closest(LpStatsTabOrders.selectors.elBtnViewAllExceptions);
2395 if (!btn || !this.elContainer.contains(btn)) {
2396 return;
2397 }
2398
2399 // The cancelled/failed deep-link is pushed to the server so pagination
2400 // totals match the rows shown ( no more client-side filterExceptions ).
2401 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
2402 report: 'exceptions',
2403 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('orderExceptions', 'Recent order exceptions'),
2404 tableId: 'exceptions',
2405 orderStatus: ['cancelled', 'failed'].includes(this.orderStatusFilter) ? this.orderStatusFilter : ''
2406 });
2407 }
2408 exportTables() {
2409 Object.entries(this.tables).forEach(([tableId, handle]) => {
2410 if (handle && handle.rows.length) {
2411 (0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.exportCsv)((0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.buildCsvFilename)('orders', tableId), handle.columns, handle.rows);
2412 }
2413 });
2414 }
2415 }
2416 const lpStatsTabOrders = new LpStatsTabOrders();
2417
2418 /***/ },
2419
2420 /***/ "./assets/src/js/admin/statistics/tab-overview.js"
2421 /*!********************************************************!*\
2422 !*** ./assets/src/js/admin/statistics/tab-overview.js ***!
2423 \********************************************************/
2424 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2425
2426 "use strict";
2427 __webpack_require__.r(__webpack_exports__);
2428 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2429 /* harmony export */ LpStatsTabOverview: () => (/* binding */ LpStatsTabOverview),
2430 /* harmony export */ lpStatsTabOverview: () => (/* binding */ lpStatsTabOverview)
2431 /* harmony export */ });
2432 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
2433 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
2434 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
2435 /* harmony import */ var _kpi_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./kpi.js */ "./assets/src/js/admin/statistics/kpi.js");
2436 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
2437 /* harmony import */ var _data_table_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./data-table.js */ "./assets/src/js/admin/statistics/data-table.js");
2438 /* harmony import */ var _report_modal_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
2439 /* harmony import */ var _csv_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./csv.js */ "./assets/src/js/admin/statistics/csv.js");
2440 /**
2441 * Overview tab module — fetches the `dashboard` payload and renders
2442 * KPIs, dual-line chart, funnel, tables, order health and health checks.
2443 *
2444 * Listens to lp-stats:filter-changed; never mutates state itself.
2445 *
2446 * @since 4.4.2
2447 * @version 1.0.0
2448 */
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458 const sprintfLite = (template, value) => String(template).replace(/%[ds]/, String(value)).replace(/%%/g, '%');
2459 class LpStatsTabOverview {
2460 static selectors = {
2461 elContainer: '.lp-stats-tab-overview',
2462 elChartCanvas: '#net-sales-chart-content',
2463 elFunnelStep: '.lp-stats-funnel__step',
2464 elTableTopCourses: '.lp-stats-table-top-courses',
2465 elTableInstructors: '.lp-stats-table-instructors',
2466 elBtnViewAllCourses: '.lp-stats-view-all-courses',
2467 elOrderHealthBox: '.lp-stats-order-health .lp-stats-health-box',
2468 elHealthCheckCount: '.lp-stats-health-check__count',
2469 elSkeleton: '.lp-skeleton-animation'
2470 };
2471 static kpiCards = {
2472 net_sales: '.lp-kpi-net-sales',
2473 completed_orders: '.lp-kpi-completed-orders',
2474 enrollments: '.lp-kpi-enrollments',
2475 completion_rate: '.lp-kpi-completion-rate',
2476 active_learners: '.lp-kpi-active-learners',
2477 failed_orders: '.lp-kpi-failed-orders'
2478 };
2479 constructor() {
2480 this.elContainer = null;
2481 this.isRequesting = false;
2482 this.pendingReload = false;
2483 this.tables = {};
2484 }
2485 init() {
2486 this.elContainer = document.querySelector(LpStatsTabOverview.selectors.elContainer);
2487 if (!this.elContainer) {
2488 return;
2489 }
2490 this.events();
2491 this.loadData();
2492 }
2493 events() {
2494 if (LpStatsTabOverview._loadedEvents) {
2495 return;
2496 }
2497 LpStatsTabOverview._loadedEvents = this;
2498 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
2499 selector: LpStatsTabOverview.selectors.elBtnViewAllCourses,
2500 class: this,
2501 callBack: this.viewAllCourses.name
2502 }]);
2503 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, () => this.loadData());
2504 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV, () => this.exportTables());
2505 }
2506 toggleSkeletons(show) {
2507 this.elContainer.querySelectorAll(LpStatsTabOverview.selectors.elSkeleton).forEach(el => {
2508 el.style.display = show ? 'block' : 'none';
2509 });
2510 }
2511 loadData() {
2512 if (this.isRequesting) {
2513 // Latest filter wins: re-run once the in-flight request finishes.
2514 this.pendingReload = true;
2515 return;
2516 }
2517 this.isRequesting = true;
2518 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('overviews-statistics', {}, {
2519 before: () => this.toggleSkeletons(true),
2520 success: response => this.render(response.data?.dashboard),
2521 error: err => {
2522 console.error('LP Statistics overview:', err);
2523 this.render(null);
2524 },
2525 completed: () => {
2526 this.toggleSkeletons(false);
2527 this.isRequesting = false;
2528 if (this.pendingReload) {
2529 this.pendingReload = false;
2530 this.loadData();
2531 }
2532 }
2533 });
2534 }
2535
2536 /**
2537 * @param {Object|null} dashboard `dashboard` key of the response; null/missing
2538 * renders empty states, never throws.
2539 */
2540 render(dashboard) {
2541 if (!dashboard) {
2542 console.error('LP Statistics overview: dashboard payload missing.');
2543 dashboard = {};
2544 }
2545 this.renderKpis(dashboard.kpis || {});
2546 this.renderChart(dashboard.chart || {});
2547 this.renderFunnel(dashboard.funnel || {});
2548 this.renderTables(dashboard);
2549 this.renderOrderHealth(dashboard.order_health || {});
2550 this.renderHealthChecks(dashboard.health_checks || {});
2551 }
2552 renderKpis(kpis) {
2553 const i18n = (key, fallback) => (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)(key, fallback);
2554 Object.entries(LpStatsTabOverview.kpiCards).forEach(([key, selector]) => {
2555 const elCard = this.elContainer.querySelector(selector);
2556 const payload = {
2557 ...(kpis[key] || {})
2558 };
2559 if ('completed_orders' === key && payload.aov_formatted) {
2560 payload.subline = sprintfLite(i18n('aov', 'Avg. order value: %s'), payload.aov_formatted);
2561 }
2562 if ('completion_rate' === key) {
2563 var _payload$courses_belo;
2564 if ('number' === typeof payload.value) {
2565 payload.formatted = `${payload.value}%`;
2566 }
2567 payload.subline = sprintfLite(i18n('belowTarget', '%d below completion target'), (_payload$courses_belo = payload.courses_below_target) !== null && _payload$courses_belo !== void 0 ? _payload$courses_belo : 0);
2568 }
2569 if ('failed_orders' === key && null != payload.fail_rate_pct) {
2570 payload.subline = sprintfLite(i18n('failRate', '%s%% of all orders'), payload.fail_rate_pct);
2571 }
2572 (0,_kpi_js__WEBPACK_IMPORTED_MODULE_3__.renderKpi)(elCard, payload);
2573 });
2574 }
2575 renderChart(chart) {
2576 (0,_chart_js__WEBPACK_IMPORTED_MODULE_4__.renderLineChart)(LpStatsTabOverview.selectors.elChartCanvas, {
2577 labels: chart.labels || [],
2578 datasets: [{
2579 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
2580 data: chart.revenue || [],
2581 yAxisID: 'y'
2582 }, {
2583 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrollments', 'Enrollments'),
2584 data: chart.enrollments || [],
2585 yAxisID: 'y1'
2586 }],
2587 xLabel: chart.x_label || '',
2588 granularity: chart.granularity || ''
2589 });
2590 }
2591 renderFunnel(funnel) {
2592 const steps = ['registered', 'enrolled', 'started', 'completed'];
2593 let previous = null;
2594 steps.forEach(step => {
2595 var _funnel$step;
2596 const elStep = this.elContainer.querySelector(`${LpStatsTabOverview.selectors.elFunnelStep}[data-step="${step}"]`);
2597 if (!elStep) {
2598 return;
2599 }
2600 const count = Number((_funnel$step = funnel[step]) !== null && _funnel$step !== void 0 ? _funnel$step : 0);
2601 const base = null === previous ? count : previous;
2602 const width = base > 0 ? Math.min(100, count / base * 100) : 0;
2603 elStep.querySelector('.lp-stats-funnel__count').textContent = String(count);
2604 elStep.querySelector('.lp-stats-funnel__bar').style.width = `${width}%`;
2605 previous = count;
2606 });
2607 }
2608 completionBadge(rate) {
2609 var _completionBadge$gree, _completionBadge$yell;
2610 if (null == rate) {
2611 return '';
2612 }
2613 const {
2614 completionBadge = {}
2615 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)();
2616 const green = (_completionBadge$gree = completionBadge.green) !== null && _completionBadge$gree !== void 0 ? _completionBadge$gree : 60;
2617 const yellow = (_completionBadge$yell = completionBadge.yellow) !== null && _completionBadge$yell !== void 0 ? _completionBadge$yell : 40;
2618 if (rate >= green) {
2619 return 'green';
2620 }
2621 return rate >= yellow ? 'yellow' : 'red';
2622 }
2623 topCoursesColumns() {
2624 return [{
2625 key: 'course_name',
2626 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
2627 }, {
2628 key: 'revenue_formatted',
2629 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
2630 csv: row => row.revenue
2631 }, {
2632 key: 'order_count',
2633 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('orders', 'Orders')
2634 }, {
2635 key: 'enrolled',
2636 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrolled', 'Enrolled')
2637 }, {
2638 key: 'completion_rate',
2639 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
2640 format: value => null == value ? '–' : `${value}%`,
2641 badge: row => this.completionBadge(row.completion_rate)
2642 }];
2643 }
2644 instructorColumns() {
2645 return [{
2646 key: 'instructor_name',
2647 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('instructor', 'Instructor')
2648 }, {
2649 key: 'course_count',
2650 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('courses', 'Courses')
2651 }, {
2652 key: 'revenue_formatted',
2653 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('revenue', 'Revenue'),
2654 csv: row => row.revenue
2655 }, {
2656 key: 'enrolled',
2657 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrolled', 'Enrolled')
2658 }, {
2659 key: 'completion_rate',
2660 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
2661 format: value => null == value ? '–' : `${value}%`,
2662 badge: row => this.completionBadge(row.completion_rate)
2663 }];
2664 }
2665 renderTables(dashboard) {
2666 this.tables['top-courses'] = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabOverview.selectors.elTableTopCourses), this.topCoursesColumns(), dashboard.top_courses || []);
2667 this.tables.instructors = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabOverview.selectors.elTableInstructors), this.instructorColumns(), dashboard.instructor_summary || []);
2668 }
2669 renderOrderHealth(orderHealth) {
2670 this.elContainer.querySelectorAll(LpStatsTabOverview.selectors.elOrderHealthBox).forEach(elBox => {
2671 const status = elBox.dataset.status;
2672 const elCount = elBox.querySelector('.lp-stats-health-box__count');
2673 if (elCount) {
2674 var _orderHealth$status;
2675 elCount.textContent = String((_orderHealth$status = orderHealth[status]) !== null && _orderHealth$status !== void 0 ? _orderHealth$status : 0);
2676 }
2677 });
2678 }
2679 renderHealthChecks(healthChecks) {
2680 this.elContainer.querySelectorAll(LpStatsTabOverview.selectors.elHealthCheckCount).forEach(elCount => {
2681 var _healthChecks$check;
2682 const check = elCount.dataset.check;
2683 elCount.textContent = String((_healthChecks$check = healthChecks[check]) !== null && _healthChecks$check !== void 0 ? _healthChecks$check : 0);
2684 });
2685 }
2686 viewAllCourses(args) {
2687 const btn = args.target.closest(LpStatsTabOverview.selectors.elBtnViewAllCourses);
2688 if (!btn || !this.elContainer.contains(btn)) {
2689 return;
2690 }
2691 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
2692 report: 'top_courses',
2693 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('topCourses', 'Top courses'),
2694 tableId: 'top-courses'
2695 });
2696 }
2697 exportTables() {
2698 Object.entries(this.tables).forEach(([tableId, handle]) => {
2699 if (handle && handle.rows.length) {
2700 (0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.exportCsv)((0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.buildCsvFilename)('overview', tableId), handle.columns, handle.rows);
2701 }
2702 });
2703 }
2704 }
2705 const lpStatsTabOverview = new LpStatsTabOverview();
2706
2707 /***/ },
2708
2709 /***/ "./assets/src/js/admin/statistics/tab-users.js"
2710 /*!*****************************************************!*\
2711 !*** ./assets/src/js/admin/statistics/tab-users.js ***!
2712 \*****************************************************/
2713 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2714
2715 "use strict";
2716 __webpack_require__.r(__webpack_exports__);
2717 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2718 /* harmony export */ LpStatsTabUsers: () => (/* binding */ LpStatsTabUsers),
2719 /* harmony export */ lpStatsTabUsers: () => (/* binding */ lpStatsTabUsers)
2720 /* harmony export */ });
2721 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
2722 /* harmony import */ var _state_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./state.js */ "./assets/src/js/admin/statistics/state.js");
2723 /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./api.js */ "./assets/src/js/admin/statistics/api.js");
2724 /* harmony import */ var _kpi_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./kpi.js */ "./assets/src/js/admin/statistics/kpi.js");
2725 /* harmony import */ var _chart_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chart.js */ "./assets/src/js/admin/statistics/chart.js");
2726 /* harmony import */ var _data_table_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./data-table.js */ "./assets/src/js/admin/statistics/data-table.js");
2727 /* harmony import */ var _report_modal_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
2728 /* harmony import */ var _csv_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./csv.js */ "./assets/src/js/admin/statistics/csv.js");
2729 /**
2730 * Users tab module.
2731 *
2732 * Fetches the `dashboard` payload and renders KPIs, registered-users chart,
2733 * 5-step funnel (incl. failed), Top Students and Top Courses by Students
2734 * tables, popups and CSV export.
2735 *
2736 * @since 4.4.2
2737 * @version 1.0.0
2738 */
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748 const sprintfLite = (template, value) => String(template).replace(/%[ds]/, String(value)).replace(/%%/g, '%');
2749 class LpStatsTabUsers {
2750 static selectors = {
2751 elContainer: '.lp-stats-tab-users',
2752 elChartCanvas: '#user-chart-content',
2753 elFunnelStep: '.lp-stats-funnel__step',
2754 elTableTopStudents: '.lp-stats-table-top-students',
2755 elTableCoursesByStudents: '.lp-stats-table-courses-by-students',
2756 elBtnViewAllStudents: '.lp-stats-view-all-students',
2757 elBtnViewAllCourses: '.lp-stats-view-all-courses-by-students',
2758 elSkeleton: '.lp-skeleton-animation'
2759 };
2760 static kpiCards = {
2761 users_activated: '.lp-kpi-users-activated',
2762 students: '.lp-kpi-students',
2763 instructors: '.lp-kpi-instructors',
2764 not_started: '.lp-kpi-not-started',
2765 in_progress: '.lp-kpi-in-progress',
2766 finished: '.lp-kpi-finished'
2767 };
2768 constructor() {
2769 this.elContainer = null;
2770 this.isRequesting = false;
2771 this.pendingReload = false;
2772 this.tables = {};
2773 }
2774 init() {
2775 this.elContainer = document.querySelector(LpStatsTabUsers.selectors.elContainer);
2776 if (!this.elContainer) {
2777 return;
2778 }
2779 this.events();
2780 this.loadData();
2781 }
2782 events() {
2783 if (LpStatsTabUsers._loadedEvents) {
2784 return;
2785 }
2786 LpStatsTabUsers._loadedEvents = this;
2787 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{
2788 selector: LpStatsTabUsers.selectors.elBtnViewAllStudents,
2789 class: this,
2790 callBack: this.viewAllStudents.name
2791 }, {
2792 selector: LpStatsTabUsers.selectors.elBtnViewAllCourses,
2793 class: this,
2794 callBack: this.viewAllCoursesByStudents.name
2795 }]);
2796 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_FILTER_CHANGED, () => this.loadData());
2797 document.addEventListener(_state_js__WEBPACK_IMPORTED_MODULE_1__.LP_STATS_EXPORT_CSV, () => this.exportTables());
2798 }
2799 toggleSkeletons(show) {
2800 this.elContainer.querySelectorAll(LpStatsTabUsers.selectors.elSkeleton).forEach(el => {
2801 el.style.display = show ? 'block' : 'none';
2802 });
2803 }
2804 loadData() {
2805 if (this.isRequesting) {
2806 this.pendingReload = true;
2807 return;
2808 }
2809 this.isRequesting = true;
2810 (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsFetch)('user-statistics', {}, {
2811 before: () => this.toggleSkeletons(true),
2812 success: response => this.render(response.data),
2813 error: err => {
2814 console.error('LP Statistics users:', err);
2815 this.render(null);
2816 },
2817 completed: () => {
2818 this.toggleSkeletons(false);
2819 this.isRequesting = false;
2820 if (this.pendingReload) {
2821 this.pendingReload = false;
2822 this.loadData();
2823 }
2824 }
2825 });
2826 }
2827 render(data) {
2828 if (!data?.dashboard) {
2829 console.error('LP Statistics users: dashboard payload missing.');
2830 data = {
2831 chart_data: {},
2832 dashboard: {}
2833 };
2834 }
2835 const dashboard = data.dashboard || {};
2836 this.renderKpis(dashboard.kpis || {});
2837 this.renderChart(data.chart_data || {});
2838 this.renderFunnel(dashboard.funnel || {});
2839 this.renderTables(dashboard);
2840 }
2841 renderKpis(kpis) {
2842 Object.entries(LpStatsTabUsers.kpiCards).forEach(([key, selector]) => {
2843 const elCard = this.elContainer.querySelector(selector);
2844 const payload = {
2845 ...(kpis[key] || {})
2846 };
2847 if ('users_activated' === key) {
2848 var _payload$new_in_perio;
2849 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('newThisPeriod', '+%d this period'), (_payload$new_in_perio = payload.new_in_period) !== null && _payload$new_in_perio !== void 0 ? _payload$new_in_perio : 0);
2850 }
2851 if ('students' === key) {
2852 var _payload$active_in_pe;
2853 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('activeInPeriod', '%d active in this period'), (_payload$active_in_pe = payload.active_in_period) !== null && _payload$active_in_pe !== void 0 ? _payload$active_in_pe : 0);
2854 }
2855 if ('instructors' === key) {
2856 var _payload$active_in_pe2, _payload$value;
2857 payload.subline = `${(_payload$active_in_pe2 = payload.active_in_period) !== null && _payload$active_in_pe2 !== void 0 ? _payload$active_in_pe2 : 0}/${(_payload$value = payload.value) !== null && _payload$value !== void 0 ? _payload$value : 0} ${(0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('activeThisPeriod', 'active this period')}`;
2858 }
2859 if ('not_started' === key) {
2860 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('afterEnrollment', 'After enrollment');
2861 }
2862 if ('in_progress' === key) {
2863 payload.subline = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('currentLearners', 'Current learners');
2864 }
2865 if ('finished' === key && null != payload.completion_rate) {
2866 payload.subline = sprintfLite((0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completionRateSub', '%s%% completion rate'), payload.completion_rate);
2867 }
2868 (0,_kpi_js__WEBPACK_IMPORTED_MODULE_3__.renderKpi)(elCard, payload);
2869 });
2870 }
2871 renderChart(chartData) {
2872 (0,_chart_js__WEBPACK_IMPORTED_MODULE_4__.renderLineChart)(LpStatsTabUsers.selectors.elChartCanvas, {
2873 labels: chartData.labels || [],
2874 datasets: [{
2875 label: chartData.line_label || (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('registeredUsers', 'Registered users'),
2876 data: chartData.data || [],
2877 yAxisID: 'y'
2878 }],
2879 xLabel: chartData.x_label || '',
2880 granularity: chartData.granularity || ''
2881 }, {
2882 yCurrency: false
2883 });
2884 }
2885 renderFunnel(funnel) {
2886 const steps = ['registered', 'enrolled', 'started', 'completed', 'failed'];
2887 let previous = null;
2888 steps.forEach(step => {
2889 var _funnel$step;
2890 const elStep = this.elContainer.querySelector(`${LpStatsTabUsers.selectors.elFunnelStep}[data-step="${step}"]`);
2891 if (!elStep) {
2892 return;
2893 }
2894 const count = Number((_funnel$step = funnel[step]) !== null && _funnel$step !== void 0 ? _funnel$step : 0);
2895 // 'failed' is an annotation on 'started', not the next narrowing step.
2896 let base = previous;
2897 if ('failed' === step) {
2898 var _funnel$started;
2899 base = Number((_funnel$started = funnel.started) !== null && _funnel$started !== void 0 ? _funnel$started : 0);
2900 } else if (null === previous) {
2901 base = count;
2902 }
2903 const width = base > 0 ? Math.min(100, count / base * 100) : 0;
2904 elStep.querySelector('.lp-stats-funnel__count').textContent = String(count);
2905 elStep.querySelector('.lp-stats-funnel__bar').style.width = `${width}%`;
2906 if ('failed' !== step) {
2907 previous = count;
2908 }
2909 });
2910 }
2911 completionBadge(rate) {
2912 var _completionBadge$gree, _completionBadge$yell;
2913 if (null == rate) {
2914 return '';
2915 }
2916 const {
2917 completionBadge = {}
2918 } = (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsConfig)();
2919 const green = (_completionBadge$gree = completionBadge.green) !== null && _completionBadge$gree !== void 0 ? _completionBadge$gree : 60;
2920 const yellow = (_completionBadge$yell = completionBadge.yellow) !== null && _completionBadge$yell !== void 0 ? _completionBadge$yell : 40;
2921 if (rate >= green) {
2922 return 'green';
2923 }
2924 return rate >= yellow ? 'yellow' : 'red';
2925 }
2926 studentStatusLabel(slug) {
2927 const labels = {
2928 active: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('statusActive', 'Active'),
2929 at_risk: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('statusAtRisk', 'At risk'),
2930 idle: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('statusIdle', 'Idle')
2931 };
2932 return labels[slug] || String(slug || '');
2933 }
2934 studentStatusBadge(slug) {
2935 const badges = {
2936 active: 'green',
2937 at_risk: 'yellow',
2938 idle: 'grey'
2939 };
2940 return badges[slug] || '';
2941 }
2942 formatLastActive(value) {
2943 if (!value) {
2944 return '—';
2945 }
2946 const date = new Date(String(value).replace(' ', 'T'));
2947 if (isNaN(date.getTime())) {
2948 return '—';
2949 }
2950 try {
2951 const days = Math.round((date.getTime() - Date.now()) / 86400000);
2952 return new Intl.RelativeTimeFormat(undefined, {
2953 numeric: 'auto'
2954 }).format(days, 'day');
2955 } catch {
2956 return date.toLocaleDateString();
2957 }
2958 }
2959
2960 /**
2961 * @param {boolean} withScore avg_score column only when the payload carries scores.
2962 */
2963 topStudentsColumns(withScore = true) {
2964 const columns = [{
2965 key: 'name',
2966 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('student', 'Student')
2967 }, {
2968 key: 'enrolled',
2969 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrolled', 'Enrolled')
2970 }, {
2971 key: 'completed',
2972 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completedLabel', 'Completed')
2973 }];
2974 if (withScore) {
2975 columns.push({
2976 key: 'avg_score',
2977 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('avgScore', 'Quiz pass rate'),
2978 format: value => null == value ? '—' : `${value}%`
2979 });
2980 }
2981 columns.push({
2982 key: 'last_active',
2983 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('lastActive', 'Last active'),
2984 format: value => this.formatLastActive(value),
2985 csv: row => row.last_active || ''
2986 }, {
2987 key: 'status',
2988 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('status', 'Status'),
2989 format: value => this.studentStatusLabel(value),
2990 badge: row => this.studentStatusBadge(row.status),
2991 csv: row => row.status
2992 });
2993 return columns;
2994 }
2995 coursesByStudentsColumns() {
2996 return [{
2997 key: 'name',
2998 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('course', 'Course')
2999 }, {
3000 key: 'enrolled',
3001 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('enrolled', 'Enrolled')
3002 }, {
3003 key: 'started',
3004 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('startedLabel', 'Started')
3005 }, {
3006 key: 'completed',
3007 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completedLabel', 'Completed')
3008 }, {
3009 key: 'completion_rate',
3010 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('completion', 'Completion'),
3011 format: value => null == value ? '—' : `${value}%`,
3012 badge: row => this.completionBadge(row.completion_rate)
3013 }, {
3014 key: 'active_7d',
3015 label: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('activeLast7dShort', 'Active 7d')
3016 }];
3017 }
3018
3019 /**
3020 * avg_score is null when quiz data is unavailable — hide the whole column.
3021 *
3022 * @param {Array} rows
3023 */
3024 hasScores(rows = []) {
3025 return rows.some(row => null != row.avg_score);
3026 }
3027 renderTables(dashboard) {
3028 const students = dashboard.top_students || [];
3029 this.tables['top-students'] = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabUsers.selectors.elTableTopStudents), this.topStudentsColumns(this.hasScores(students)), students);
3030 this.tables['courses-by-students'] = (0,_data_table_js__WEBPACK_IMPORTED_MODULE_5__.renderDataTable)(this.elContainer.querySelector(LpStatsTabUsers.selectors.elTableCoursesByStudents), this.coursesByStudentsColumns(), dashboard.top_courses_by_students || []);
3031 }
3032 viewAllStudents(args) {
3033 const btn = args.target.closest(LpStatsTabUsers.selectors.elBtnViewAllStudents);
3034 if (!btn || !this.elContainer.contains(btn)) {
3035 return;
3036 }
3037 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
3038 report: 'top_students',
3039 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('topStudents', 'Top students'),
3040 tableId: 'top-students'
3041 });
3042 }
3043 viewAllCoursesByStudents(args) {
3044 const btn = args.target.closest(LpStatsTabUsers.selectors.elBtnViewAllCourses);
3045 if (!btn || !this.elContainer.contains(btn)) {
3046 return;
3047 }
3048 _report_modal_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsReportModal.open({
3049 report: 'courses_by_students',
3050 title: (0,_api_js__WEBPACK_IMPORTED_MODULE_2__.getStatsI18n)('topCoursesByStudents', 'Top courses by students'),
3051 tableId: 'courses-by-students'
3052 });
3053 }
3054 exportTables() {
3055 Object.entries(this.tables).forEach(([tableId, handle]) => {
3056 if (handle && handle.rows.length) {
3057 (0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.exportCsv)((0,_csv_js__WEBPACK_IMPORTED_MODULE_7__.buildCsvFilename)('users', tableId), handle.columns, handle.rows);
3058 }
3059 });
3060 }
3061 }
3062 const lpStatsTabUsers = new LpStatsTabUsers();
3063
3064 /***/ },
3065
3066 /***/ "./assets/src/js/utils.js"
3067 /*!********************************!*\
3068 !*** ./assets/src/js/utils.js ***!
3069 \********************************/
3070 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3071
3072 "use strict";
3073 __webpack_require__.r(__webpack_exports__);
3074 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
3075 /* harmony export */ debounce: () => (/* binding */ debounce),
3076 /* harmony export */ eventHandlers: () => (/* binding */ eventHandlers),
3077 /* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm),
3078 /* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm),
3079 /* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated),
3080 /* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed),
3081 /* harmony export */ lpAddQueryArgs: () => (/* binding */ lpAddQueryArgs),
3082 /* harmony export */ lpAjaxParseJsonOld: () => (/* binding */ lpAjaxParseJsonOld),
3083 /* harmony export */ lpClassName: () => (/* binding */ lpClassName),
3084 /* harmony export */ lpFetchAPI: () => (/* binding */ lpFetchAPI),
3085 /* harmony export */ lpGetCurrentURLNoParam: () => (/* binding */ lpGetCurrentURLNoParam),
3086 /* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady),
3087 /* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl),
3088 /* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl),
3089 /* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm),
3090 /* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse)
3091 /* harmony export */ });
3092 /**
3093 * Utils functions
3094 *
3095 * @param url
3096 * @param data
3097 * @param functions
3098 * @since 4.2.5.1
3099 * @version 1.0.6
3100 */
3101 const lpClassName = {
3102 hidden: 'lp-hidden',
3103 loading: 'loading',
3104 elCollapse: 'lp-collapse',
3105 elSectionToggle: '.lp-section-toggle',
3106 elTriggerToggle: '.lp-trigger-toggle'
3107 };
3108 const lpFetchAPI = (url, data = {}, functions = {}) => {
3109 if ('function' === typeof functions.before) {
3110 functions.before();
3111 }
3112 fetch(url, {
3113 method: 'GET',
3114 ...data
3115 }).then(response => response.json()).then(response => {
3116 if ('function' === typeof functions.success) {
3117 functions.success(response);
3118 }
3119 }).catch(err => {
3120 if ('function' === typeof functions.error) {
3121 functions.error(err);
3122 }
3123 }).finally(() => {
3124 if ('function' === typeof functions.completed) {
3125 functions.completed();
3126 }
3127 });
3128 };
3129
3130 /**
3131 * Get current URL without params.
3132 *
3133 * @since 4.2.5.1
3134 */
3135 const lpGetCurrentURLNoParam = () => {
3136 let currentUrl = window.location.href;
3137 const hasParams = currentUrl.includes('?');
3138 if (hasParams) {
3139 currentUrl = currentUrl.split('?')[0];
3140 }
3141 return currentUrl;
3142 };
3143 const lpAddQueryArgs = (endpoint, args) => {
3144 const url = new URL(endpoint);
3145 Object.keys(args).forEach(arg => {
3146 url.searchParams.set(arg, args[arg]);
3147 });
3148 return url;
3149 };
3150
3151 /**
3152 * Listen element viewed.
3153 *
3154 * @param el
3155 * @param callback
3156 * @since 4.2.5.8
3157 */
3158 const listenElementViewed = (el, callback) => {
3159 const observerSeeItem = new IntersectionObserver(function (entries) {
3160 for (const entry of entries) {
3161 if (entry.isIntersecting) {
3162 callback(entry);
3163 }
3164 }
3165 });
3166 observerSeeItem.observe(el);
3167 };
3168
3169 /**
3170 * Listen element created.
3171 *
3172 * @param callback
3173 * @since 4.2.5.8
3174 */
3175 const listenElementCreated = callback => {
3176 const observerCreateItem = new MutationObserver(function (mutations) {
3177 mutations.forEach(function (mutation) {
3178 if (mutation.addedNodes) {
3179 mutation.addedNodes.forEach(function (node) {
3180 if (node.nodeType === 1) {
3181 callback(node);
3182 }
3183 });
3184 }
3185 });
3186 });
3187 observerCreateItem.observe(document, {
3188 childList: true,
3189 subtree: true
3190 });
3191 // End.
3192 };
3193
3194 /**
3195 * Listen element created.
3196 *
3197 * @param selector
3198 * @param callback
3199 * @since 4.2.7.1
3200 */
3201 const lpOnElementReady = (selector, callback) => {
3202 const element = document.querySelector(selector);
3203 if (element) {
3204 callback(element);
3205 return;
3206 }
3207 const observer = new MutationObserver((mutations, obs) => {
3208 const element = document.querySelector(selector);
3209 if (element) {
3210 obs.disconnect();
3211 callback(element);
3212 }
3213 });
3214 observer.observe(document.documentElement, {
3215 childList: true,
3216 subtree: true
3217 });
3218 };
3219
3220 // Parse JSON from string with content include LP_AJAX_START.
3221 const lpAjaxParseJsonOld = data => {
3222 if (typeof data !== 'string') {
3223 return data;
3224 }
3225 const m = String.raw({
3226 raw: data
3227 }).match(/<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s);
3228 try {
3229 if (m) {
3230 data = JSON.parse(m[1].replace(/(?:\r\n|\r|\n)/g, ''));
3231 } else {
3232 data = JSON.parse(data);
3233 }
3234 } catch (e) {
3235 data = {};
3236 }
3237 return data;
3238 };
3239
3240 // status 0: hide, 1: show
3241 const lpShowHideEl = (el, status = 0) => {
3242 if (!el) {
3243 return;
3244 }
3245 if (!status) {
3246 el.classList.add(lpClassName.hidden);
3247 } else {
3248 el.classList.remove(lpClassName.hidden);
3249 }
3250 };
3251
3252 // status 0: hide, 1: show
3253 const lpSetLoadingEl = (el, status) => {
3254 if (!el) {
3255 return;
3256 }
3257 if (!status) {
3258 el.classList.remove(lpClassName.loading);
3259 } else {
3260 el.classList.add(lpClassName.loading);
3261 }
3262 };
3263
3264 // Toggle collapse section
3265 const toggleCollapse = (e, target, elTriggerClassName = '', elsExclude = [], callback) => {
3266 if (!elTriggerClassName) {
3267 elTriggerClassName = lpClassName.elTriggerToggle;
3268 }
3269
3270 // Exclude elements, which should not trigger the collapse toggle
3271 if (elsExclude && elsExclude.length > 0) {
3272 for (const elExclude of elsExclude) {
3273 if (target.closest(elExclude)) {
3274 return;
3275 }
3276 }
3277 }
3278 const elTrigger = target.closest(elTriggerClassName);
3279 if (!elTrigger) {
3280 return;
3281 }
3282
3283 //console.log( 'elTrigger', elTrigger );
3284
3285 const elSectionToggle = elTrigger.closest(`${lpClassName.elSectionToggle}`);
3286 if (!elSectionToggle) {
3287 return;
3288 }
3289 elSectionToggle.classList.toggle(`${lpClassName.elCollapse}`);
3290 if ('function' === typeof callback) {
3291 callback(elSectionToggle);
3292 }
3293 };
3294
3295 // Get data of form
3296 const getDataOfForm = form => {
3297 const dataSend = {};
3298 const formData = new FormData(form);
3299 for (const pair of formData.entries()) {
3300 const key = pair[0];
3301 const value = formData.getAll(key);
3302 if (!dataSend.hasOwnProperty(key)) {
3303 // Convert value array to string.
3304 dataSend[key] = value.join(',');
3305 }
3306 }
3307 return dataSend;
3308 };
3309
3310 // Get field keys of form
3311 const getFieldKeysOfForm = form => {
3312 const keys = [];
3313 const elements = form.elements;
3314 for (let i = 0; i < elements.length; i++) {
3315 const name = elements[i].name;
3316 if (name && !keys.includes(name)) {
3317 keys.push(name);
3318 }
3319 }
3320 return keys;
3321 };
3322
3323 // Merge data handle with data form.
3324 const mergeDataWithDatForm = (elForm, dataHandle) => {
3325 const dataForm = getDataOfForm(elForm);
3326 const keys = getFieldKeysOfForm(elForm);
3327 keys.forEach(key => {
3328 if (!dataForm.hasOwnProperty(key)) {
3329 delete dataHandle[key];
3330 } else if (dataForm[key][0] === '') {
3331 delete dataForm[key];
3332 delete dataHandle[key];
3333 }
3334 });
3335 dataHandle = {
3336 ...dataHandle,
3337 ...dataForm
3338 };
3339 return dataHandle;
3340 };
3341
3342 /**
3343 * Event trigger
3344 * For each list of event handlers, listen event on document.
3345 *
3346 * eventName: 'click', 'change', ...
3347 * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
3348 *
3349 * @param eventName
3350 * @param eventHandlers
3351 */
3352 const eventHandlers = (eventName, eventHandlers) => {
3353 document.addEventListener(eventName, e => {
3354 const target = e.target;
3355 let args = {
3356 e,
3357 target
3358 };
3359 eventHandlers.forEach(eventHandler => {
3360 args = {
3361 ...args,
3362 ...eventHandler
3363 };
3364
3365 //console.log( args );
3366
3367 // Check condition before call back
3368 if (eventHandler.conditionBeforeCallBack) {
3369 if (eventHandler.conditionBeforeCallBack(args) !== true) {
3370 return;
3371 }
3372 }
3373
3374 // Special check for keydown event with checkIsEventEnter = true
3375 if (eventName === 'keydown' && eventHandler.checkIsEventEnter) {
3376 if (e.key !== 'Enter') {
3377 return;
3378 }
3379 }
3380 if (target.closest(eventHandler.selector)) {
3381 if (eventHandler.class) {
3382 // Call method of class, function callBack will understand exactly {this} is class object.
3383 eventHandler.class[eventHandler.callBack](args);
3384 } else {
3385 // For send args is objected, {this} is eventHandler object, not class object.
3386 eventHandler.callBack(args);
3387 }
3388 }
3389 });
3390 });
3391 };
3392
3393 /**
3394 * Debounce - delays function execution until after `wait` ms of inactivity.
3395 *
3396 * Each call resets the timer. Only the last call in a burst executes.
3397 *
3398 * USE CASES:
3399 * - Search inputs, form validation, window resize
3400 * - Multiple elements need independent timers
3401 * - When you need to call with different arguments
3402 *
3403 * EXAMPLES:
3404 * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
3405 * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
3406 *
3407 * const debouncedResize = debounce( recalculateLayout, 250 );
3408 * window.addEventListener('resize', debouncedResize);
3409 *
3410 * ⚠️ Create ONCE outside event handlers, not inside.
3411 *
3412 * @param {Function} func - Function to debounce (can be anonymous)
3413 * @param {number} wait - Milliseconds to wait (default: 500)
3414 * @return {Function} Debounced wrapper function
3415 * @since 4.3.7
3416 * @version 1.0.0
3417 */
3418 const debounce = (func, wait = 500) => {
3419 let timer;
3420 return args => {
3421 clearTimeout(timer);
3422 timer = setTimeout(() => func(args), wait);
3423 };
3424 };
3425
3426 /***/ },
3427
3428 /***/ "./node_modules/sweetalert2/dist/sweetalert2.all.js"
3429 /*!**********************************************************!*\
3430 !*** ./node_modules/sweetalert2/dist/sweetalert2.all.js ***!
3431 \**********************************************************/
3432 (module) {
3433
3434 /*!
3435 * sweetalert2 v11.26.17
3436 * Released under the MIT License.
3437 */
3438 (function (global, factory) {
3439 true ? module.exports = factory() :
3440 0;
3441 })(this, (function () { 'use strict';
3442
3443 function _assertClassBrand(e, t, n) {
3444 if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
3445 throw new TypeError("Private element is not present on this object");
3446 }
3447 function _checkPrivateRedeclaration(e, t) {
3448 if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
3449 }
3450 function _classPrivateFieldGet2(s, a) {
3451 return s.get(_assertClassBrand(s, a));
3452 }
3453 function _classPrivateFieldInitSpec(e, t, a) {
3454 _checkPrivateRedeclaration(e, t), t.set(e, a);
3455 }
3456 function _classPrivateFieldSet2(s, a, r) {
3457 return s.set(_assertClassBrand(s, a), r), r;
3458 }
3459
3460 const RESTORE_FOCUS_TIMEOUT = 100;
3461
3462 /** @type {GlobalState} */
3463 const globalState = {};
3464 const focusPreviousActiveElement = () => {
3465 if (globalState.previousActiveElement instanceof HTMLElement) {
3466 globalState.previousActiveElement.focus();
3467 globalState.previousActiveElement = null;
3468 } else if (document.body) {
3469 document.body.focus();
3470 }
3471 };
3472
3473 /**
3474 * Restore previous active (focused) element
3475 *
3476 * @param {boolean} returnFocus
3477 * @returns {Promise<void>}
3478 */
3479 const restoreActiveElement = returnFocus => {
3480 return new Promise(resolve => {
3481 if (!returnFocus) {
3482 return resolve();
3483 }
3484 const x = window.scrollX;
3485 const y = window.scrollY;
3486 globalState.restoreFocusTimeout = setTimeout(() => {
3487 focusPreviousActiveElement();
3488 resolve();
3489 }, RESTORE_FOCUS_TIMEOUT); // issues/900
3490
3491 window.scrollTo(x, y);
3492 });
3493 };
3494
3495 const swalPrefix = 'swal2-';
3496
3497 /**
3498 * @typedef {Record<SwalClass, string>} SwalClasses
3499 */
3500
3501 /**
3502 * @typedef {'success' | 'warning' | 'info' | 'question' | 'error'} SwalIcon
3503 * @typedef {Record<SwalIcon, string>} SwalIcons
3504 */
3505
3506 /** @type {SwalClass[]} */
3507 const classNames = ['container', 'shown', 'height-auto', 'iosfix', 'popup', 'modal', 'no-backdrop', 'no-transition', 'toast', 'toast-shown', 'show', 'hide', 'close', 'title', 'html-container', 'actions', 'confirm', 'deny', 'cancel', 'footer', 'icon', 'icon-content', 'image', 'input', 'file', 'range', 'select', 'radio', 'checkbox', 'label', 'textarea', 'inputerror', 'input-label', 'validation-message', 'progress-steps', 'active-progress-step', 'progress-step', 'progress-step-line', 'loader', 'loading', 'styled', 'top', 'top-start', 'top-end', 'top-left', 'top-right', 'center', 'center-start', 'center-end', 'center-left', 'center-right', 'bottom', 'bottom-start', 'bottom-end', 'bottom-left', 'bottom-right', 'grow-row', 'grow-column', 'grow-fullscreen', 'rtl', 'timer-progress-bar', 'timer-progress-bar-container', 'scrollbar-measure', 'icon-success', 'icon-warning', 'icon-info', 'icon-question', 'icon-error', 'draggable', 'dragging'];
3508 const swalClasses = classNames.reduce((acc, className) => {
3509 acc[className] = swalPrefix + className;
3510 return acc;
3511 }, /** @type {SwalClasses} */{});
3512
3513 /** @type {SwalIcon[]} */
3514 const icons = ['success', 'warning', 'info', 'question', 'error'];
3515 const iconTypes = icons.reduce((acc, icon) => {
3516 acc[icon] = swalPrefix + icon;
3517 return acc;
3518 }, /** @type {SwalIcons} */{});
3519
3520 const consolePrefix = 'SweetAlert2:';
3521
3522 /**
3523 * Capitalize the first letter of a string
3524 *
3525 * @param {string} str
3526 * @returns {string}
3527 */
3528 const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);
3529
3530 /**
3531 * Standardize console warnings
3532 *
3533 * @param {string | string[]} message
3534 */
3535 const warn = message => {
3536 console.warn(`${consolePrefix} ${typeof message === 'object' ? message.join(' ') : message}`);
3537 };
3538
3539 /**
3540 * Standardize console errors
3541 *
3542 * @param {string} message
3543 */
3544 const error = message => {
3545 console.error(`${consolePrefix} ${message}`);
3546 };
3547
3548 /**
3549 * Private global state for `warnOnce`
3550 *
3551 * @type {string[]}
3552 * @private
3553 */
3554 const previousWarnOnceMessages = [];
3555
3556 /**
3557 * Show a console warning, but only if it hasn't already been shown
3558 *
3559 * @param {string} message
3560 */
3561 const warnOnce = message => {
3562 if (!previousWarnOnceMessages.includes(message)) {
3563 previousWarnOnceMessages.push(message);
3564 warn(message);
3565 }
3566 };
3567
3568 /**
3569 * Show a one-time console warning about deprecated params/methods
3570 *
3571 * @param {string} deprecatedParam
3572 * @param {string?} useInstead
3573 */
3574 const warnAboutDeprecation = (deprecatedParam, useInstead = null) => {
3575 warnOnce(`"${deprecatedParam}" is deprecated and will be removed in the next major release.${useInstead ? ` Use "${useInstead}" instead.` : ''}`);
3576 };
3577
3578 /**
3579 * If `arg` is a function, call it (with no arguments or context) and return the result.
3580 * Otherwise, just pass the value through
3581 *
3582 * @param {(() => *) | *} arg
3583 * @returns {*}
3584 */
3585 const callIfFunction = arg => typeof arg === 'function' ? arg() : arg;
3586
3587 /**
3588 * @param {*} arg
3589 * @returns {boolean}
3590 */
3591 const hasToPromiseFn = arg => arg && typeof arg.toPromise === 'function';
3592
3593 /**
3594 * @param {*} arg
3595 * @returns {Promise<*>}
3596 */
3597 const asPromise = arg => hasToPromiseFn(arg) ? arg.toPromise() : Promise.resolve(arg);
3598
3599 /**
3600 * @param {*} arg
3601 * @returns {boolean}
3602 */
3603 const isPromise = arg => arg && Promise.resolve(arg) === arg;
3604
3605 /**
3606 * Gets the popup container which contains the backdrop and the popup itself.
3607 *
3608 * @returns {HTMLElement | null}
3609 */
3610 const getContainer = () => document.body.querySelector(`.${swalClasses.container}`);
3611
3612 /**
3613 * @param {string} selectorString
3614 * @returns {HTMLElement | null}
3615 */
3616 const elementBySelector = selectorString => {
3617 const container = getContainer();
3618 return container ? container.querySelector(selectorString) : null;
3619 };
3620
3621 /**
3622 * @param {string} className
3623 * @returns {HTMLElement | null}
3624 */
3625 const elementByClass = className => {
3626 return elementBySelector(`.${className}`);
3627 };
3628
3629 /**
3630 * @returns {HTMLElement | null}
3631 */
3632 const getPopup = () => elementByClass(swalClasses.popup);
3633
3634 /**
3635 * @returns {HTMLElement | null}
3636 */
3637 const getIcon = () => elementByClass(swalClasses.icon);
3638
3639 /**
3640 * @returns {HTMLElement | null}
3641 */
3642 const getIconContent = () => elementByClass(swalClasses['icon-content']);
3643
3644 /**
3645 * @returns {HTMLElement | null}
3646 */
3647 const getTitle = () => elementByClass(swalClasses.title);
3648
3649 /**
3650 * @returns {HTMLElement | null}
3651 */
3652 const getHtmlContainer = () => elementByClass(swalClasses['html-container']);
3653
3654 /**
3655 * @returns {HTMLElement | null}
3656 */
3657 const getImage = () => elementByClass(swalClasses.image);
3658
3659 /**
3660 * @returns {HTMLElement | null}
3661 */
3662 const getProgressSteps = () => elementByClass(swalClasses['progress-steps']);
3663
3664 /**
3665 * @returns {HTMLElement | null}
3666 */
3667 const getValidationMessage = () => elementByClass(swalClasses['validation-message']);
3668
3669 /**
3670 * @returns {HTMLButtonElement | null}
3671 */
3672 const getConfirmButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.confirm}`));
3673
3674 /**
3675 * @returns {HTMLButtonElement | null}
3676 */
3677 const getCancelButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.cancel}`));
3678
3679 /**
3680 * @returns {HTMLButtonElement | null}
3681 */
3682 const getDenyButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.deny}`));
3683
3684 /**
3685 * @returns {HTMLElement | null}
3686 */
3687 const getInputLabel = () => elementByClass(swalClasses['input-label']);
3688
3689 /**
3690 * @returns {HTMLElement | null}
3691 */
3692 const getLoader = () => elementBySelector(`.${swalClasses.loader}`);
3693
3694 /**
3695 * @returns {HTMLElement | null}
3696 */
3697 const getActions = () => elementByClass(swalClasses.actions);
3698
3699 /**
3700 * @returns {HTMLElement | null}
3701 */
3702 const getFooter = () => elementByClass(swalClasses.footer);
3703
3704 /**
3705 * @returns {HTMLElement | null}
3706 */
3707 const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']);
3708
3709 /**
3710 * @returns {HTMLElement | null}
3711 */
3712 const getCloseButton = () => elementByClass(swalClasses.close);
3713
3714 // https://github.com/jkup/focusable/blob/master/index.js
3715 const focusable = `
3716 a[href],
3717 area[href],
3718 input:not([disabled]),
3719 select:not([disabled]),
3720 textarea:not([disabled]),
3721 button:not([disabled]),
3722 iframe,
3723 object,
3724 embed,
3725 [tabindex="0"],
3726 [contenteditable],
3727 audio[controls],
3728 video[controls],
3729 summary
3730 `;
3731 /**
3732 * @returns {HTMLElement[]}
3733 */
3734 const getFocusableElements = () => {
3735 const popup = getPopup();
3736 if (!popup) {
3737 return [];
3738 }
3739 /** @type {NodeListOf<HTMLElement>} */
3740 const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])');
3741 const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex)
3742 // sort according to tabindex
3743 .sort((a, b) => {
3744 const tabindexA = parseInt(a.getAttribute('tabindex') || '0');
3745 const tabindexB = parseInt(b.getAttribute('tabindex') || '0');
3746 if (tabindexA > tabindexB) {
3747 return 1;
3748 } else if (tabindexA < tabindexB) {
3749 return -1;
3750 }
3751 return 0;
3752 });
3753
3754 /** @type {NodeListOf<HTMLElement>} */
3755 const otherFocusableElements = popup.querySelectorAll(focusable);
3756 const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1');
3757 return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el));
3758 };
3759
3760 /**
3761 * @returns {boolean}
3762 */
3763 const isModal = () => {
3764 return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']);
3765 };
3766
3767 /**
3768 * @returns {boolean}
3769 */
3770 const isToast = () => {
3771 const popup = getPopup();
3772 if (!popup) {
3773 return false;
3774 }
3775 return hasClass(popup, swalClasses.toast);
3776 };
3777
3778 /**
3779 * @returns {boolean}
3780 */
3781 const isLoading = () => {
3782 const popup = getPopup();
3783 if (!popup) {
3784 return false;
3785 }
3786 return popup.hasAttribute('data-loading');
3787 };
3788
3789 /**
3790 * Securely set innerHTML of an element
3791 * https://github.com/sweetalert2/sweetalert2/issues/1926
3792 *
3793 * @param {HTMLElement} elem
3794 * @param {string} html
3795 */
3796 const setInnerHtml = (elem, html) => {
3797 elem.textContent = '';
3798 if (html) {
3799 const parser = new DOMParser();
3800 const parsed = parser.parseFromString(html, `text/html`);
3801 const head = parsed.querySelector('head');
3802 if (head) {
3803 Array.from(head.childNodes).forEach(child => {
3804 elem.appendChild(child);
3805 });
3806 }
3807 const body = parsed.querySelector('body');
3808 if (body) {
3809 Array.from(body.childNodes).forEach(child => {
3810 if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) {
3811 elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507
3812 } else {
3813 elem.appendChild(child);
3814 }
3815 });
3816 }
3817 }
3818 };
3819
3820 /**
3821 * @param {HTMLElement} elem
3822 * @param {string} className
3823 * @returns {boolean}
3824 */
3825 const hasClass = (elem, className) => {
3826 if (!className) {
3827 return false;
3828 }
3829 const classList = className.split(/\s+/);
3830 for (let i = 0; i < classList.length; i++) {
3831 if (!elem.classList.contains(classList[i])) {
3832 return false;
3833 }
3834 }
3835 return true;
3836 };
3837
3838 /**
3839 * @param {HTMLElement} elem
3840 * @param {SweetAlertOptions} params
3841 */
3842 const removeCustomClasses = (elem, params) => {
3843 Array.from(elem.classList).forEach(className => {
3844 if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) {
3845 elem.classList.remove(className);
3846 }
3847 });
3848 };
3849
3850 /**
3851 * @param {HTMLElement} elem
3852 * @param {SweetAlertOptions} params
3853 * @param {string} className
3854 */
3855 const applyCustomClass = (elem, params, className) => {
3856 removeCustomClasses(elem, params);
3857 if (!params.customClass) {
3858 return;
3859 }
3860 const customClass = params.customClass[(/** @type {keyof SweetAlertCustomClass} */className)];
3861 if (!customClass) {
3862 return;
3863 }
3864 if (typeof customClass !== 'string' && !customClass.forEach) {
3865 warn(`Invalid type of customClass.${className}! Expected string or iterable object, got "${typeof customClass}"`);
3866 return;
3867 }
3868 addClass(elem, customClass);
3869 };
3870
3871 /**
3872 * @param {HTMLElement} popup
3873 * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass
3874 * @returns {HTMLInputElement | null}
3875 */
3876 const getInput$1 = (popup, inputClass) => {
3877 if (!inputClass) {
3878 return null;
3879 }
3880 switch (inputClass) {
3881 case 'select':
3882 case 'textarea':
3883 case 'file':
3884 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses[inputClass]}`);
3885 case 'checkbox':
3886 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.checkbox} input`);
3887 case 'radio':
3888 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:checked`) || popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:first-child`);
3889 case 'range':
3890 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.range} input`);
3891 default:
3892 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.input}`);
3893 }
3894 };
3895
3896 /**
3897 * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input
3898 */
3899 const focusInput = input => {
3900 input.focus();
3901
3902 // place cursor at end of text in text input
3903 if (input.type !== 'file') {
3904 // http://stackoverflow.com/a/2345915
3905 const val = input.value;
3906 input.value = '';
3907 input.value = val;
3908 }
3909 };
3910
3911 /**
3912 * @param {HTMLElement | HTMLElement[] | null} target
3913 * @param {string | string[] | readonly string[] | undefined} classList
3914 * @param {boolean} condition
3915 */
3916 const toggleClass = (target, classList, condition) => {
3917 if (!target || !classList) {
3918 return;
3919 }
3920 if (typeof classList === 'string') {
3921 classList = classList.split(/\s+/).filter(Boolean);
3922 }
3923 classList.forEach(className => {
3924 if (Array.isArray(target)) {
3925 target.forEach(elem => {
3926 if (condition) {
3927 elem.classList.add(className);
3928 } else {
3929 elem.classList.remove(className);
3930 }
3931 });
3932 } else {
3933 if (condition) {
3934 target.classList.add(className);
3935 } else {
3936 target.classList.remove(className);
3937 }
3938 }
3939 });
3940 };
3941
3942 /**
3943 * @param {HTMLElement | HTMLElement[] | null} target
3944 * @param {string | string[] | readonly string[] | undefined} classList
3945 */
3946 const addClass = (target, classList) => {
3947 toggleClass(target, classList, true);
3948 };
3949
3950 /**
3951 * @param {HTMLElement | HTMLElement[] | null} target
3952 * @param {string | string[] | readonly string[] | undefined} classList
3953 */
3954 const removeClass = (target, classList) => {
3955 toggleClass(target, classList, false);
3956 };
3957
3958 /**
3959 * Get direct child of an element by class name
3960 *
3961 * @param {HTMLElement} elem
3962 * @param {string} className
3963 * @returns {HTMLElement | undefined}
3964 */
3965 const getDirectChildByClass = (elem, className) => {
3966 const children = Array.from(elem.children);
3967 for (let i = 0; i < children.length; i++) {
3968 const child = children[i];
3969 if (child instanceof HTMLElement && hasClass(child, className)) {
3970 return child;
3971 }
3972 }
3973 };
3974
3975 /**
3976 * @param {HTMLElement} elem
3977 * @param {string} property
3978 * @param {string | number | null | undefined} value
3979 */
3980 const applyNumericalStyle = (elem, property, value) => {
3981 if (value === `${parseInt(`${value}`)}`) {
3982 value = parseInt(value);
3983 }
3984 if (value || parseInt(`${value}`) === 0) {
3985 elem.style.setProperty(property, typeof value === 'number' ? `${value}px` : (/** @type {string} */value));
3986 } else {
3987 elem.style.removeProperty(property);
3988 }
3989 };
3990
3991 /**
3992 * @param {HTMLElement | null} elem
3993 * @param {string} display
3994 */
3995 const show = (elem, display = 'flex') => {
3996 if (!elem) {
3997 return;
3998 }
3999 elem.style.display = display;
4000 };
4001
4002 /**
4003 * @param {HTMLElement | null} elem
4004 */
4005 const hide = elem => {
4006 if (!elem) {
4007 return;
4008 }
4009 elem.style.display = 'none';
4010 };
4011
4012 /**
4013 * @param {HTMLElement | null} elem
4014 * @param {string} display
4015 */
4016 const showWhenInnerHtmlPresent = (elem, display = 'block') => {
4017 if (!elem) {
4018 return;
4019 }
4020 new MutationObserver(() => {
4021 toggle(elem, elem.innerHTML, display);
4022 }).observe(elem, {
4023 childList: true,
4024 subtree: true
4025 });
4026 };
4027
4028 /**
4029 * @param {HTMLElement} parent
4030 * @param {string} selector
4031 * @param {string} property
4032 * @param {string} value
4033 */
4034 const setStyle = (parent, selector, property, value) => {
4035 /** @type {HTMLElement | null} */
4036 const el = parent.querySelector(selector);
4037 if (el) {
4038 el.style.setProperty(property, value);
4039 }
4040 };
4041
4042 /**
4043 * @param {HTMLElement} elem
4044 * @param {boolean | string | null | undefined} condition
4045 * @param {string} display
4046 */
4047 const toggle = (elem, condition, display = 'flex') => {
4048 if (condition) {
4049 show(elem, display);
4050 } else {
4051 hide(elem);
4052 }
4053 };
4054
4055 /**
4056 * borrowed from jquery $(elem).is(':visible') implementation
4057 *
4058 * @param {HTMLElement | null} elem
4059 * @returns {boolean}
4060 */
4061 const isVisible$1 = elem => Boolean(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length));
4062
4063 /**
4064 * @returns {boolean}
4065 */
4066 const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton());
4067
4068 /**
4069 * @param {HTMLElement} elem
4070 * @returns {boolean}
4071 */
4072 const isScrollable = elem => Boolean(elem.scrollHeight > elem.clientHeight);
4073
4074 /**
4075 * @param {HTMLElement} element
4076 * @param {HTMLElement} stopElement
4077 * @returns {boolean}
4078 */
4079 const selfOrParentIsScrollable = (element, stopElement) => {
4080 let parent = /** @type {HTMLElement | null} */element;
4081 while (parent && parent !== stopElement) {
4082 if (isScrollable(parent)) {
4083 return true;
4084 }
4085 parent = parent.parentElement;
4086 }
4087 return false;
4088 };
4089
4090 /**
4091 * borrowed from https://stackoverflow.com/a/46352119
4092 *
4093 * @param {HTMLElement} elem
4094 * @returns {boolean}
4095 */
4096 const hasCssAnimation = elem => {
4097 const style = window.getComputedStyle(elem);
4098 const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0');
4099 const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0');
4100 return animDuration > 0 || transDuration > 0;
4101 };
4102
4103 /**
4104 * @param {number} timer
4105 * @param {boolean} reset
4106 */
4107 const animateTimerProgressBar = (timer, reset = false) => {
4108 const timerProgressBar = getTimerProgressBar();
4109 if (!timerProgressBar) {
4110 return;
4111 }
4112 if (isVisible$1(timerProgressBar)) {
4113 if (reset) {
4114 timerProgressBar.style.transition = 'none';
4115 timerProgressBar.style.width = '100%';
4116 }
4117 setTimeout(() => {
4118 timerProgressBar.style.transition = `width ${timer / 1000}s linear`;
4119 timerProgressBar.style.width = '0%';
4120 }, 10);
4121 }
4122 };
4123 const stopTimerProgressBar = () => {
4124 const timerProgressBar = getTimerProgressBar();
4125 if (!timerProgressBar) {
4126 return;
4127 }
4128 const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4129 timerProgressBar.style.removeProperty('transition');
4130 timerProgressBar.style.width = '100%';
4131 const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4132 const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100;
4133 timerProgressBar.style.width = `${timerProgressBarPercent}%`;
4134 };
4135
4136 /**
4137 * Detect Node env
4138 *
4139 * @returns {boolean}
4140 */
4141 const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
4142
4143 const sweetHTML = `
4144 <div aria-labelledby="${swalClasses.title}" aria-describedby="${swalClasses['html-container']}" class="${swalClasses.popup}" tabindex="-1">
4145 <button type="button" class="${swalClasses.close}"></button>
4146 <ul class="${swalClasses['progress-steps']}"></ul>
4147 <div class="${swalClasses.icon}"></div>
4148 <img class="${swalClasses.image}" />
4149 <h2 class="${swalClasses.title}" id="${swalClasses.title}"></h2>
4150 <div class="${swalClasses['html-container']}" id="${swalClasses['html-container']}"></div>
4151 <input class="${swalClasses.input}" id="${swalClasses.input}" />
4152 <input type="file" class="${swalClasses.file}" />
4153 <div class="${swalClasses.range}">
4154 <input type="range" />
4155 <output></output>
4156 </div>
4157 <select class="${swalClasses.select}" id="${swalClasses.select}"></select>
4158 <div class="${swalClasses.radio}"></div>
4159 <label class="${swalClasses.checkbox}">
4160 <input type="checkbox" id="${swalClasses.checkbox}" />
4161 <span class="${swalClasses.label}"></span>
4162 </label>
4163 <textarea class="${swalClasses.textarea}" id="${swalClasses.textarea}"></textarea>
4164 <div class="${swalClasses['validation-message']}" id="${swalClasses['validation-message']}"></div>
4165 <div class="${swalClasses.actions}">
4166 <div class="${swalClasses.loader}"></div>
4167 <button type="button" class="${swalClasses.confirm}"></button>
4168 <button type="button" class="${swalClasses.deny}"></button>
4169 <button type="button" class="${swalClasses.cancel}"></button>
4170 </div>
4171 <div class="${swalClasses.footer}"></div>
4172 <div class="${swalClasses['timer-progress-bar-container']}">
4173 <div class="${swalClasses['timer-progress-bar']}"></div>
4174 </div>
4175 </div>
4176 `.replace(/(^|\n)\s*/g, '');
4177
4178 /**
4179 * @returns {boolean}
4180 */
4181 const resetOldContainer = () => {
4182 const oldContainer = getContainer();
4183 if (!oldContainer) {
4184 return false;
4185 }
4186 oldContainer.remove();
4187 removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'],
4188 // @ts-ignore: 'has-column' is not defined in swalClasses but may be set dynamically
4189 swalClasses['has-column']]);
4190 return true;
4191 };
4192 const resetValidationMessage$1 = () => {
4193 if (globalState.currentInstance) {
4194 globalState.currentInstance.resetValidationMessage();
4195 }
4196 };
4197 const addInputChangeListeners = () => {
4198 const popup = getPopup();
4199 if (!popup) {
4200 return;
4201 }
4202 const input = getDirectChildByClass(popup, swalClasses.input);
4203 const file = getDirectChildByClass(popup, swalClasses.file);
4204 /** @type {HTMLInputElement | null} */
4205 const range = popup.querySelector(`.${swalClasses.range} input`);
4206 /** @type {HTMLOutputElement | null} */
4207 const rangeOutput = popup.querySelector(`.${swalClasses.range} output`);
4208 const select = getDirectChildByClass(popup, swalClasses.select);
4209 /** @type {HTMLInputElement | null} */
4210 const checkbox = popup.querySelector(`.${swalClasses.checkbox} input`);
4211 const textarea = getDirectChildByClass(popup, swalClasses.textarea);
4212 if (input) {
4213 input.oninput = resetValidationMessage$1;
4214 }
4215 if (file) {
4216 file.onchange = resetValidationMessage$1;
4217 }
4218 if (select) {
4219 select.onchange = resetValidationMessage$1;
4220 }
4221 if (checkbox) {
4222 checkbox.onchange = resetValidationMessage$1;
4223 }
4224 if (textarea) {
4225 textarea.oninput = resetValidationMessage$1;
4226 }
4227 if (range && rangeOutput) {
4228 range.oninput = () => {
4229 resetValidationMessage$1();
4230 rangeOutput.value = range.value;
4231 };
4232 range.onchange = () => {
4233 resetValidationMessage$1();
4234 rangeOutput.value = range.value;
4235 };
4236 }
4237 };
4238
4239 /**
4240 * @param {string | HTMLElement} target
4241 * @returns {HTMLElement}
4242 */
4243 const getTarget = target => {
4244 if (typeof target === 'string') {
4245 const element = document.querySelector(target);
4246 if (!element) {
4247 throw new Error(`Target element "${target}" not found`);
4248 }
4249 return /** @type {HTMLElement} */element;
4250 }
4251 return target;
4252 };
4253
4254 /**
4255 * @param {SweetAlertOptions} params
4256 */
4257 const setupAccessibility = params => {
4258 const popup = getPopup();
4259 if (!popup) {
4260 return;
4261 }
4262 popup.setAttribute('role', params.toast ? 'alert' : 'dialog');
4263 popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive');
4264 if (!params.toast) {
4265 popup.setAttribute('aria-modal', 'true');
4266 }
4267 };
4268
4269 /**
4270 * @param {HTMLElement} targetElement
4271 */
4272 const setupRTL = targetElement => {
4273 if (window.getComputedStyle(targetElement).direction === 'rtl') {
4274 addClass(getContainer(), swalClasses.rtl);
4275 globalState.isRTL = true;
4276 }
4277 };
4278
4279 /**
4280 * Add modal + backdrop to DOM
4281 *
4282 * @param {SweetAlertOptions} params
4283 */
4284 const init = params => {
4285 // Clean up the old popup container if it exists
4286 const oldContainerExisted = resetOldContainer();
4287 if (isNodeEnv()) {
4288 error('SweetAlert2 requires document to initialize');
4289 return;
4290 }
4291 const container = document.createElement('div');
4292 container.className = swalClasses.container;
4293 if (oldContainerExisted) {
4294 addClass(container, swalClasses['no-transition']);
4295 }
4296 setInnerHtml(container, sweetHTML);
4297 container.dataset['swal2Theme'] = params.theme;
4298 const targetElement = getTarget(params.target || 'body');
4299 targetElement.appendChild(container);
4300 if (params.topLayer) {
4301 container.setAttribute('popover', '');
4302 container.showPopover();
4303 }
4304 setupAccessibility(params);
4305 setupRTL(targetElement);
4306 addInputChangeListeners();
4307 };
4308
4309 /**
4310 * @param {HTMLElement | object | string} param
4311 * @param {HTMLElement} target
4312 */
4313 const parseHtmlToContainer = (param, target) => {
4314 // DOM element
4315 if (param instanceof HTMLElement) {
4316 target.appendChild(param);
4317 }
4318
4319 // Object
4320 else if (typeof param === 'object') {
4321 handleObject(param, target);
4322 }
4323
4324 // Plain string
4325 else if (param) {
4326 setInnerHtml(target, param);
4327 }
4328 };
4329
4330 /**
4331 * @param {object} param
4332 * @param {HTMLElement} target
4333 */
4334 const handleObject = (param, target) => {
4335 // JQuery element(s)
4336 if ('jquery' in param) {
4337 handleJqueryElem(target, param);
4338 }
4339
4340 // For other objects use their string representation
4341 else {
4342 setInnerHtml(target, param.toString());
4343 }
4344 };
4345
4346 /**
4347 * @param {HTMLElement} target
4348 * @param {any} elem
4349 */
4350 const handleJqueryElem = (target, elem) => {
4351 target.textContent = '';
4352 if (0 in elem) {
4353 for (let i = 0; i in elem; i++) {
4354 target.appendChild(elem[i].cloneNode(true));
4355 }
4356 } else {
4357 target.appendChild(elem.cloneNode(true));
4358 }
4359 };
4360
4361 /**
4362 * @param {SweetAlert} instance
4363 * @param {SweetAlertOptions} params
4364 */
4365 const renderActions = (instance, params) => {
4366 const actions = getActions();
4367 const loader = getLoader();
4368 if (!actions || !loader) {
4369 return;
4370 }
4371
4372 // Actions (buttons) wrapper
4373 if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) {
4374 hide(actions);
4375 } else {
4376 show(actions);
4377 }
4378
4379 // Custom class
4380 applyCustomClass(actions, params, 'actions');
4381
4382 // Render all the buttons
4383 renderButtons(actions, loader, params);
4384
4385 // Loader
4386 setInnerHtml(loader, params.loaderHtml || '');
4387 applyCustomClass(loader, params, 'loader');
4388 };
4389
4390 /**
4391 * @param {HTMLElement} actions
4392 * @param {HTMLElement} loader
4393 * @param {SweetAlertOptions} params
4394 */
4395 function renderButtons(actions, loader, params) {
4396 const confirmButton = getConfirmButton();
4397 const denyButton = getDenyButton();
4398 const cancelButton = getCancelButton();
4399 if (!confirmButton || !denyButton || !cancelButton) {
4400 return;
4401 }
4402
4403 // Render buttons
4404 renderButton(confirmButton, 'confirm', params);
4405 renderButton(denyButton, 'deny', params);
4406 renderButton(cancelButton, 'cancel', params);
4407 handleButtonsStyling(confirmButton, denyButton, cancelButton, params);
4408 if (params.reverseButtons) {
4409 if (params.toast) {
4410 actions.insertBefore(cancelButton, confirmButton);
4411 actions.insertBefore(denyButton, confirmButton);
4412 } else {
4413 actions.insertBefore(cancelButton, loader);
4414 actions.insertBefore(denyButton, loader);
4415 actions.insertBefore(confirmButton, loader);
4416 }
4417 }
4418 }
4419
4420 /**
4421 * @param {HTMLElement} confirmButton
4422 * @param {HTMLElement} denyButton
4423 * @param {HTMLElement} cancelButton
4424 * @param {SweetAlertOptions} params
4425 */
4426 function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) {
4427 if (!params.buttonsStyling) {
4428 removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4429 return;
4430 }
4431 addClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4432
4433 // Apply custom background colors to action buttons
4434 if (params.confirmButtonColor) {
4435 confirmButton.style.setProperty('--swal2-confirm-button-background-color', params.confirmButtonColor);
4436 }
4437 if (params.denyButtonColor) {
4438 denyButton.style.setProperty('--swal2-deny-button-background-color', params.denyButtonColor);
4439 }
4440 if (params.cancelButtonColor) {
4441 cancelButton.style.setProperty('--swal2-cancel-button-background-color', params.cancelButtonColor);
4442 }
4443
4444 // Apply the outline color to action buttons
4445 applyOutlineColor(confirmButton);
4446 applyOutlineColor(denyButton);
4447 applyOutlineColor(cancelButton);
4448 }
4449
4450 /**
4451 * @param {HTMLElement} button
4452 */
4453 function applyOutlineColor(button) {
4454 const buttonStyle = window.getComputedStyle(button);
4455 if (buttonStyle.getPropertyValue('--swal2-action-button-focus-box-shadow')) {
4456 // If the button already has a custom outline color, no need to change it
4457 return;
4458 }
4459 const outlineColor = buttonStyle.backgroundColor.replace(/rgba?\((\d+), (\d+), (\d+).*/, 'rgba($1, $2, $3, 0.5)');
4460 button.style.setProperty('--swal2-action-button-focus-box-shadow', buttonStyle.getPropertyValue('--swal2-outline').replace(/ rgba\(.*/, ` ${outlineColor}`));
4461 }
4462
4463 /**
4464 * @param {HTMLElement} button
4465 * @param {'confirm' | 'deny' | 'cancel'} buttonType
4466 * @param {SweetAlertOptions} params
4467 */
4468 function renderButton(button, buttonType, params) {
4469 const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType);
4470 toggle(button, params[`show${buttonName}Button`], 'inline-block');
4471 setInnerHtml(button, params[`${buttonType}ButtonText`] || ''); // Set caption text
4472 button.setAttribute('aria-label', params[`${buttonType}ButtonAriaLabel`] || ''); // ARIA label
4473
4474 // Add buttons custom classes
4475 button.className = swalClasses[buttonType];
4476 applyCustomClass(button, params, `${buttonType}Button`);
4477 }
4478
4479 /**
4480 * @param {SweetAlert} instance
4481 * @param {SweetAlertOptions} params
4482 */
4483 const renderCloseButton = (instance, params) => {
4484 const closeButton = getCloseButton();
4485 if (!closeButton) {
4486 return;
4487 }
4488 setInnerHtml(closeButton, params.closeButtonHtml || '');
4489
4490 // Custom class
4491 applyCustomClass(closeButton, params, 'closeButton');
4492 toggle(closeButton, params.showCloseButton);
4493 closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || '');
4494 };
4495
4496 /**
4497 * @param {SweetAlert} instance
4498 * @param {SweetAlertOptions} params
4499 */
4500 const renderContainer = (instance, params) => {
4501 const container = getContainer();
4502 if (!container) {
4503 return;
4504 }
4505 handleBackdropParam(container, params.backdrop);
4506 handlePositionParam(container, params.position);
4507 handleGrowParam(container, params.grow);
4508
4509 // Custom class
4510 applyCustomClass(container, params, 'container');
4511 };
4512
4513 /**
4514 * @param {HTMLElement} container
4515 * @param {SweetAlertOptions['backdrop']} backdrop
4516 */
4517 function handleBackdropParam(container, backdrop) {
4518 if (typeof backdrop === 'string') {
4519 container.style.background = backdrop;
4520 } else if (!backdrop) {
4521 addClass([document.documentElement, document.body], swalClasses['no-backdrop']);
4522 }
4523 }
4524
4525 /**
4526 * @param {HTMLElement} container
4527 * @param {SweetAlertOptions['position']} position
4528 */
4529 function handlePositionParam(container, position) {
4530 if (!position) {
4531 return;
4532 }
4533 if (position in swalClasses) {
4534 addClass(container, swalClasses[position]);
4535 } else {
4536 warn('The "position" parameter is not valid, defaulting to "center"');
4537 addClass(container, swalClasses.center);
4538 }
4539 }
4540
4541 /**
4542 * @param {HTMLElement} container
4543 * @param {SweetAlertOptions['grow']} grow
4544 */
4545 function handleGrowParam(container, grow) {
4546 if (!grow) {
4547 return;
4548 }
4549 addClass(container, swalClasses[`grow-${grow}`]);
4550 }
4551
4552 /**
4553 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
4554 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
4555 * This is the approach that Babel will probably take to implement private methods/fields
4556 * https://github.com/tc39/proposal-private-methods
4557 * https://github.com/babel/babel/pull/7555
4558 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
4559 * then we can use that language feature.
4560 */
4561
4562 var privateProps = {
4563 innerParams: new WeakMap(),
4564 domCache: new WeakMap()
4565 };
4566
4567 /// <reference path="../../../../sweetalert2.d.ts"/>
4568
4569
4570 /** @type {InputClass[]} */
4571 const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
4572
4573 /**
4574 * @param {SweetAlert} instance
4575 * @param {SweetAlertOptions} params
4576 */
4577 const renderInput = (instance, params) => {
4578 const popup = getPopup();
4579 if (!popup) {
4580 return;
4581 }
4582 const innerParams = privateProps.innerParams.get(instance);
4583 const rerender = !innerParams || params.input !== innerParams.input;
4584 inputClasses.forEach(inputClass => {
4585 const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]);
4586 if (!inputContainer) {
4587 return;
4588 }
4589
4590 // set attributes
4591 setAttributes(inputClass, params.inputAttributes);
4592
4593 // set class
4594 inputContainer.className = swalClasses[inputClass];
4595 if (rerender) {
4596 hide(inputContainer);
4597 }
4598 });
4599 if (params.input) {
4600 if (rerender) {
4601 showInput(params);
4602 }
4603 // set custom class
4604 setCustomClass(params);
4605 }
4606 };
4607
4608 /**
4609 * @param {SweetAlertOptions} params
4610 */
4611 const showInput = params => {
4612 if (!params.input) {
4613 return;
4614 }
4615 if (!renderInputType[params.input]) {
4616 error(`Unexpected type of input! Expected ${Object.keys(renderInputType).join(' | ')}, got "${params.input}"`);
4617 return;
4618 }
4619 const inputContainer = getInputContainer(params.input);
4620 if (!inputContainer) {
4621 return;
4622 }
4623 const input = renderInputType[params.input](inputContainer, params);
4624 show(inputContainer);
4625
4626 // input autofocus
4627 if (params.inputAutoFocus) {
4628 setTimeout(() => {
4629 focusInput(input);
4630 });
4631 }
4632 };
4633
4634 /**
4635 * @param {HTMLInputElement} input
4636 */
4637 const removeAttributes = input => {
4638 for (let i = 0; i < input.attributes.length; i++) {
4639 const attrName = input.attributes[i].name;
4640 if (!['id', 'type', 'value', 'style'].includes(attrName)) {
4641 input.removeAttribute(attrName);
4642 }
4643 }
4644 };
4645
4646 /**
4647 * @param {InputClass} inputClass
4648 * @param {SweetAlertOptions['inputAttributes']} inputAttributes
4649 */
4650 const setAttributes = (inputClass, inputAttributes) => {
4651 const popup = getPopup();
4652 if (!popup) {
4653 return;
4654 }
4655 const input = getInput$1(popup, inputClass);
4656 if (!input) {
4657 return;
4658 }
4659 removeAttributes(input);
4660 for (const attr in inputAttributes) {
4661 input.setAttribute(attr, inputAttributes[attr]);
4662 }
4663 };
4664
4665 /**
4666 * @param {SweetAlertOptions} params
4667 */
4668 const setCustomClass = params => {
4669 if (!params.input) {
4670 return;
4671 }
4672 const inputContainer = getInputContainer(params.input);
4673 if (inputContainer) {
4674 applyCustomClass(inputContainer, params, 'input');
4675 }
4676 };
4677
4678 /**
4679 * @param {HTMLInputElement | HTMLTextAreaElement} input
4680 * @param {SweetAlertOptions} params
4681 */
4682 const setInputPlaceholder = (input, params) => {
4683 if (!input.placeholder && params.inputPlaceholder) {
4684 input.placeholder = params.inputPlaceholder;
4685 }
4686 };
4687
4688 /**
4689 * @param {Input} input
4690 * @param {Input} prependTo
4691 * @param {SweetAlertOptions} params
4692 */
4693 const setInputLabel = (input, prependTo, params) => {
4694 if (params.inputLabel) {
4695 const label = document.createElement('label');
4696 const labelClass = swalClasses['input-label'];
4697 label.setAttribute('for', input.id);
4698 label.className = labelClass;
4699 if (typeof params.customClass === 'object') {
4700 addClass(label, params.customClass.inputLabel);
4701 }
4702 label.innerText = params.inputLabel;
4703 prependTo.insertAdjacentElement('beforebegin', label);
4704 }
4705 };
4706
4707 /**
4708 * @param {SweetAlertInput} inputType
4709 * @returns {HTMLElement | undefined}
4710 */
4711 const getInputContainer = inputType => {
4712 const popup = getPopup();
4713 if (!popup) {
4714 return;
4715 }
4716 return getDirectChildByClass(popup, swalClasses[(/** @type {SwalClass} */inputType)] || swalClasses.input);
4717 };
4718
4719 /**
4720 * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input
4721 * @param {SweetAlertOptions['inputValue']} inputValue
4722 */
4723 const checkAndSetInputValue = (input, inputValue) => {
4724 if (['string', 'number'].includes(typeof inputValue)) {
4725 input.value = `${inputValue}`;
4726 } else if (!isPromise(inputValue)) {
4727 warn(`Unexpected type of inputValue! Expected "string", "number" or "Promise", got "${typeof inputValue}"`);
4728 }
4729 };
4730
4731 /** @type {Record<SweetAlertInput, (input: Input | HTMLElement, params: SweetAlertOptions) => Input>} */
4732 const renderInputType = {};
4733
4734 /**
4735 * @param {Input | HTMLElement} input
4736 * @param {SweetAlertOptions} params
4737 * @returns {Input}
4738 */
4739 renderInputType.text = renderInputType.email = renderInputType.password = renderInputType.number = renderInputType.tel = renderInputType.url = renderInputType.search = renderInputType.date = renderInputType['datetime-local'] = renderInputType.time = renderInputType.week = renderInputType.month = /** @type {(input: Input | HTMLElement, params: SweetAlertOptions) => Input} */
4740 (input, params) => {
4741 const inputElement = /** @type {HTMLInputElement} */input;
4742 checkAndSetInputValue(inputElement, params.inputValue);
4743 setInputLabel(inputElement, inputElement, params);
4744 setInputPlaceholder(inputElement, params);
4745 inputElement.type = /** @type {string} */params.input;
4746 return inputElement;
4747 };
4748
4749 /**
4750 * @param {Input | HTMLElement} input
4751 * @param {SweetAlertOptions} params
4752 * @returns {Input}
4753 */
4754 renderInputType.file = (input, params) => {
4755 const inputElement = /** @type {HTMLInputElement} */input;
4756 setInputLabel(inputElement, inputElement, params);
4757 setInputPlaceholder(inputElement, params);
4758 return inputElement;
4759 };
4760
4761 /**
4762 * @param {Input | HTMLElement} range
4763 * @param {SweetAlertOptions} params
4764 * @returns {Input}
4765 */
4766 renderInputType.range = (range, params) => {
4767 const rangeContainer = /** @type {HTMLElement} */range;
4768 const rangeInput = rangeContainer.querySelector('input');
4769 const rangeOutput = rangeContainer.querySelector('output');
4770 if (rangeInput) {
4771 checkAndSetInputValue(rangeInput, params.inputValue);
4772 rangeInput.type = /** @type {string} */params.input;
4773 setInputLabel(rangeInput, /** @type {Input} */range, params);
4774 }
4775 if (rangeOutput) {
4776 checkAndSetInputValue(rangeOutput, params.inputValue);
4777 }
4778 return /** @type {Input} */range;
4779 };
4780
4781 /**
4782 * @param {Input | HTMLElement} select
4783 * @param {SweetAlertOptions} params
4784 * @returns {Input}
4785 */
4786 renderInputType.select = (select, params) => {
4787 const selectElement = /** @type {HTMLSelectElement} */select;
4788 selectElement.textContent = '';
4789 if (params.inputPlaceholder) {
4790 const placeholder = document.createElement('option');
4791 setInnerHtml(placeholder, params.inputPlaceholder);
4792 placeholder.value = '';
4793 placeholder.disabled = true;
4794 placeholder.selected = true;
4795 selectElement.appendChild(placeholder);
4796 }
4797 setInputLabel(selectElement, selectElement, params);
4798 return selectElement;
4799 };
4800
4801 /**
4802 * @param {Input | HTMLElement} radio
4803 * @returns {Input}
4804 */
4805 renderInputType.radio = radio => {
4806 const radioElement = /** @type {HTMLElement} */radio;
4807 radioElement.textContent = '';
4808 return /** @type {Input} */radio;
4809 };
4810
4811 /**
4812 * @param {Input | HTMLElement} checkboxContainer
4813 * @param {SweetAlertOptions} params
4814 * @returns {Input}
4815 */
4816 renderInputType.checkbox = (checkboxContainer, params) => {
4817 const popup = getPopup();
4818 if (!popup) {
4819 throw new Error('Popup not found');
4820 }
4821 const checkbox = getInput$1(popup, 'checkbox');
4822 if (!checkbox) {
4823 throw new Error('Checkbox input not found');
4824 }
4825 checkbox.value = '1';
4826 checkbox.checked = Boolean(params.inputValue);
4827 const containerElement = /** @type {HTMLElement} */checkboxContainer;
4828 const label = containerElement.querySelector('span');
4829 if (label) {
4830 const placeholderOrLabel = params.inputPlaceholder || params.inputLabel;
4831 if (placeholderOrLabel) {
4832 setInnerHtml(label, placeholderOrLabel);
4833 }
4834 }
4835 return checkbox;
4836 };
4837
4838 /**
4839 * @param {Input | HTMLElement} textarea
4840 * @param {SweetAlertOptions} params
4841 * @returns {Input}
4842 */
4843 renderInputType.textarea = (textarea, params) => {
4844 const textareaElement = /** @type {HTMLTextAreaElement} */textarea;
4845 checkAndSetInputValue(textareaElement, params.inputValue);
4846 setInputPlaceholder(textareaElement, params);
4847 setInputLabel(textareaElement, textareaElement, params);
4848
4849 /**
4850 * @param {HTMLElement} el
4851 * @returns {number}
4852 */
4853 const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight);
4854
4855 // https://github.com/sweetalert2/sweetalert2/issues/2291
4856 setTimeout(() => {
4857 // https://github.com/sweetalert2/sweetalert2/issues/1699
4858 if ('MutationObserver' in window) {
4859 const popup = getPopup();
4860 if (!popup) {
4861 return;
4862 }
4863 const initialPopupWidth = parseInt(window.getComputedStyle(popup).width);
4864 const textareaResizeHandler = () => {
4865 // check if texarea is still in document (i.e. popup wasn't closed in the meantime)
4866 if (!document.body.contains(textareaElement)) {
4867 return;
4868 }
4869 const textareaWidth = textareaElement.offsetWidth + getMargin(textareaElement);
4870 const popupElement = getPopup();
4871 if (popupElement) {
4872 if (textareaWidth > initialPopupWidth) {
4873 popupElement.style.width = `${textareaWidth}px`;
4874 } else {
4875 applyNumericalStyle(popupElement, 'width', params.width);
4876 }
4877 }
4878 };
4879 new MutationObserver(textareaResizeHandler).observe(textareaElement, {
4880 attributes: true,
4881 attributeFilter: ['style']
4882 });
4883 }
4884 });
4885 return textareaElement;
4886 };
4887
4888 /**
4889 * @param {SweetAlert} instance
4890 * @param {SweetAlertOptions} params
4891 */
4892 const renderContent = (instance, params) => {
4893 const htmlContainer = getHtmlContainer();
4894 if (!htmlContainer) {
4895 return;
4896 }
4897 showWhenInnerHtmlPresent(htmlContainer);
4898 applyCustomClass(htmlContainer, params, 'htmlContainer');
4899
4900 // Content as HTML
4901 if (params.html) {
4902 parseHtmlToContainer(params.html, htmlContainer);
4903 show(htmlContainer, 'block');
4904 }
4905
4906 // Content as plain text
4907 else if (params.text) {
4908 htmlContainer.textContent = params.text;
4909 show(htmlContainer, 'block');
4910 }
4911
4912 // No content
4913 else {
4914 hide(htmlContainer);
4915 }
4916 renderInput(instance, params);
4917 };
4918
4919 /**
4920 * @param {SweetAlert} instance
4921 * @param {SweetAlertOptions} params
4922 */
4923 const renderFooter = (instance, params) => {
4924 const footer = getFooter();
4925 if (!footer) {
4926 return;
4927 }
4928 showWhenInnerHtmlPresent(footer);
4929 toggle(footer, Boolean(params.footer), 'block');
4930 if (params.footer) {
4931 parseHtmlToContainer(params.footer, footer);
4932 }
4933
4934 // Custom class
4935 applyCustomClass(footer, params, 'footer');
4936 };
4937
4938 /**
4939 * @param {SweetAlert} instance
4940 * @param {SweetAlertOptions} params
4941 */
4942 const renderIcon = (instance, params) => {
4943 const innerParams = privateProps.innerParams.get(instance);
4944 const icon = getIcon();
4945 if (!icon) {
4946 return;
4947 }
4948
4949 // if the given icon already rendered, apply the styling without re-rendering the icon
4950 if (innerParams && params.icon === innerParams.icon) {
4951 // Custom or default content
4952 setContent(icon, params);
4953 applyStyles(icon, params);
4954 return;
4955 }
4956 if (!params.icon && !params.iconHtml) {
4957 hide(icon);
4958 return;
4959 }
4960 if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) {
4961 error(`Unknown icon! Expected "success", "error", "warning", "info" or "question", got "${params.icon}"`);
4962 hide(icon);
4963 return;
4964 }
4965 show(icon);
4966
4967 // Custom or default content
4968 setContent(icon, params);
4969 applyStyles(icon, params);
4970
4971 // Animate icon
4972 addClass(icon, params.showClass && params.showClass.icon);
4973
4974 // Re-adjust the success icon on system theme change
4975 const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
4976 colorSchemeQueryList.addEventListener('change', adjustSuccessIconBackgroundColor);
4977 };
4978
4979 /**
4980 * @param {HTMLElement} icon
4981 * @param {SweetAlertOptions} params
4982 */
4983 const applyStyles = (icon, params) => {
4984 for (const [iconType, iconClassName] of Object.entries(iconTypes)) {
4985 if (params.icon !== iconType) {
4986 removeClass(icon, iconClassName);
4987 }
4988 }
4989 addClass(icon, params.icon && iconTypes[params.icon]);
4990
4991 // Icon color
4992 setColor(icon, params);
4993
4994 // Success icon background color
4995 adjustSuccessIconBackgroundColor();
4996
4997 // Custom class
4998 applyCustomClass(icon, params, 'icon');
4999 };
5000
5001 // Adjust success icon background color to match the popup background color
5002 const adjustSuccessIconBackgroundColor = () => {
5003 const popup = getPopup();
5004 if (!popup) {
5005 return;
5006 }
5007 const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color');
5008 /** @type {NodeListOf<HTMLElement>} */
5009 const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix');
5010 for (let i = 0; i < successIconParts.length; i++) {
5011 successIconParts[i].style.backgroundColor = popupBackgroundColor;
5012 }
5013 };
5014
5015 /**
5016 *
5017 * @param {SweetAlertOptions} params
5018 * @returns {string}
5019 */
5020 const successIconHtml = params => `
5021 ${params.animation ? '<div class="swal2-success-circular-line-left"></div>' : ''}
5022 <span class="swal2-success-line-tip"></span> <span class="swal2-success-line-long"></span>
5023 <div class="swal2-success-ring"></div>
5024 ${params.animation ? '<div class="swal2-success-fix"></div>' : ''}
5025 ${params.animation ? '<div class="swal2-success-circular-line-right"></div>' : ''}
5026 `;
5027 const errorIconHtml = `
5028 <span class="swal2-x-mark">
5029 <span class="swal2-x-mark-line-left"></span>
5030 <span class="swal2-x-mark-line-right"></span>
5031 </span>
5032 `;
5033
5034 /**
5035 * @param {HTMLElement} icon
5036 * @param {SweetAlertOptions} params
5037 */
5038 const setContent = (icon, params) => {
5039 if (!params.icon && !params.iconHtml) {
5040 return;
5041 }
5042 let oldContent = icon.innerHTML;
5043 let newContent = '';
5044 if (params.iconHtml) {
5045 newContent = iconContent(params.iconHtml);
5046 } else if (params.icon === 'success') {
5047 newContent = successIconHtml(params);
5048 oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor()
5049 } else if (params.icon === 'error') {
5050 newContent = errorIconHtml;
5051 } else if (params.icon) {
5052 const defaultIconHtml = {
5053 question: '?',
5054 warning: '!',
5055 info: 'i'
5056 };
5057 newContent = iconContent(defaultIconHtml[params.icon]);
5058 }
5059 if (oldContent.trim() !== newContent.trim()) {
5060 setInnerHtml(icon, newContent);
5061 }
5062 };
5063
5064 /**
5065 * @param {HTMLElement} icon
5066 * @param {SweetAlertOptions} params
5067 */
5068 const setColor = (icon, params) => {
5069 if (!params.iconColor) {
5070 return;
5071 }
5072 icon.style.color = params.iconColor;
5073 icon.style.borderColor = params.iconColor;
5074 for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) {
5075 setStyle(icon, sel, 'background-color', params.iconColor);
5076 }
5077 setStyle(icon, '.swal2-success-ring', 'border-color', params.iconColor);
5078 };
5079
5080 /**
5081 * @param {string} content
5082 * @returns {string}
5083 */
5084 const iconContent = content => `<div class="${swalClasses['icon-content']}">${content}</div>`;
5085
5086 /**
5087 * @param {SweetAlert} instance
5088 * @param {SweetAlertOptions} params
5089 */
5090 const renderImage = (instance, params) => {
5091 const image = getImage();
5092 if (!image) {
5093 return;
5094 }
5095 if (!params.imageUrl) {
5096 hide(image);
5097 return;
5098 }
5099 show(image, '');
5100
5101 // Src, alt
5102 image.setAttribute('src', params.imageUrl);
5103 image.setAttribute('alt', params.imageAlt || '');
5104
5105 // Width, height
5106 applyNumericalStyle(image, 'width', params.imageWidth);
5107 applyNumericalStyle(image, 'height', params.imageHeight);
5108
5109 // Class
5110 image.className = swalClasses.image;
5111 applyCustomClass(image, params, 'image');
5112 };
5113
5114 let dragging = false;
5115 let mousedownX = 0;
5116 let mousedownY = 0;
5117 let initialX = 0;
5118 let initialY = 0;
5119
5120 /**
5121 * @param {HTMLElement} popup
5122 */
5123 const addDraggableListeners = popup => {
5124 popup.addEventListener('mousedown', down);
5125 document.body.addEventListener('mousemove', move);
5126 popup.addEventListener('mouseup', up);
5127 popup.addEventListener('touchstart', down);
5128 document.body.addEventListener('touchmove', move);
5129 popup.addEventListener('touchend', up);
5130 };
5131
5132 /**
5133 * @param {HTMLElement} popup
5134 */
5135 const removeDraggableListeners = popup => {
5136 popup.removeEventListener('mousedown', down);
5137 document.body.removeEventListener('mousemove', move);
5138 popup.removeEventListener('mouseup', up);
5139 popup.removeEventListener('touchstart', down);
5140 document.body.removeEventListener('touchmove', move);
5141 popup.removeEventListener('touchend', up);
5142 };
5143
5144 /**
5145 * @param {MouseEvent | TouchEvent} event
5146 */
5147 const down = event => {
5148 const popup = getPopup();
5149 if (!popup) {
5150 return;
5151 }
5152 const icon = getIcon();
5153 if (event.target === popup || icon && icon.contains(/** @type {HTMLElement} */event.target)) {
5154 dragging = true;
5155 const clientXY = getClientXY(event);
5156 mousedownX = clientXY.clientX;
5157 mousedownY = clientXY.clientY;
5158 initialX = parseInt(popup.style.insetInlineStart) || 0;
5159 initialY = parseInt(popup.style.insetBlockStart) || 0;
5160 addClass(popup, 'swal2-dragging');
5161 }
5162 };
5163
5164 /**
5165 * @param {MouseEvent | TouchEvent} event
5166 */
5167 const move = event => {
5168 const popup = getPopup();
5169 if (!popup) {
5170 return;
5171 }
5172 if (dragging) {
5173 let {
5174 clientX,
5175 clientY
5176 } = getClientXY(event);
5177 const deltaX = clientX - mousedownX;
5178 // In RTL mode, negate the horizontal delta since insetInlineStart refers to the right edge
5179 popup.style.insetInlineStart = `${initialX + (globalState.isRTL ? -deltaX : deltaX)}px`;
5180 popup.style.insetBlockStart = `${initialY + (clientY - mousedownY)}px`;
5181 }
5182 };
5183 const up = () => {
5184 const popup = getPopup();
5185 dragging = false;
5186 removeClass(popup, 'swal2-dragging');
5187 };
5188
5189 /**
5190 * @param {MouseEvent | TouchEvent} event
5191 * @returns {{ clientX: number, clientY: number }}
5192 */
5193 const getClientXY = event => {
5194 let clientX = 0,
5195 clientY = 0;
5196 if (event.type.startsWith('mouse')) {
5197 clientX = /** @type {MouseEvent} */event.clientX;
5198 clientY = /** @type {MouseEvent} */event.clientY;
5199 } else if (event.type.startsWith('touch')) {
5200 clientX = /** @type {TouchEvent} */event.touches[0].clientX;
5201 clientY = /** @type {TouchEvent} */event.touches[0].clientY;
5202 }
5203 return {
5204 clientX,
5205 clientY
5206 };
5207 };
5208
5209 /**
5210 * @param {SweetAlert} instance
5211 * @param {SweetAlertOptions} params
5212 */
5213 const renderPopup = (instance, params) => {
5214 const container = getContainer();
5215 const popup = getPopup();
5216 if (!container || !popup) {
5217 return;
5218 }
5219
5220 // Width
5221 // https://github.com/sweetalert2/sweetalert2/issues/2170
5222 if (params.toast) {
5223 applyNumericalStyle(container, 'width', params.width);
5224 popup.style.width = '100%';
5225 const loader = getLoader();
5226 if (loader) {
5227 popup.insertBefore(loader, getIcon());
5228 }
5229 } else {
5230 applyNumericalStyle(popup, 'width', params.width);
5231 }
5232
5233 // Padding
5234 applyNumericalStyle(popup, 'padding', params.padding);
5235
5236 // Color
5237 if (params.color) {
5238 popup.style.color = params.color;
5239 }
5240
5241 // Background
5242 if (params.background) {
5243 popup.style.background = params.background;
5244 }
5245 hide(getValidationMessage());
5246
5247 // Classes
5248 addClasses$1(popup, params);
5249 if (params.draggable && !params.toast) {
5250 addClass(popup, swalClasses.draggable);
5251 addDraggableListeners(popup);
5252 } else {
5253 removeClass(popup, swalClasses.draggable);
5254 removeDraggableListeners(popup);
5255 }
5256 };
5257
5258 /**
5259 * @param {HTMLElement} popup
5260 * @param {SweetAlertOptions} params
5261 */
5262 const addClasses$1 = (popup, params) => {
5263 const showClass = params.showClass || {};
5264 // Default Class + showClass when updating Swal.update({})
5265 popup.className = `${swalClasses.popup} ${isVisible$1(popup) ? showClass.popup : ''}`;
5266 if (params.toast) {
5267 addClass([document.documentElement, document.body], swalClasses['toast-shown']);
5268 addClass(popup, swalClasses.toast);
5269 } else {
5270 addClass(popup, swalClasses.modal);
5271 }
5272
5273 // Custom class
5274 applyCustomClass(popup, params, 'popup');
5275 // TODO: remove in the next major
5276 if (typeof params.customClass === 'string') {
5277 addClass(popup, params.customClass);
5278 }
5279
5280 // Icon class (#1842)
5281 if (params.icon) {
5282 addClass(popup, swalClasses[`icon-${params.icon}`]);
5283 }
5284 };
5285
5286 /**
5287 * @param {SweetAlert} instance
5288 * @param {SweetAlertOptions} params
5289 */
5290 const renderProgressSteps = (instance, params) => {
5291 const progressStepsContainer = getProgressSteps();
5292 if (!progressStepsContainer) {
5293 return;
5294 }
5295 const {
5296 progressSteps,
5297 currentProgressStep
5298 } = params;
5299 if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) {
5300 hide(progressStepsContainer);
5301 return;
5302 }
5303 show(progressStepsContainer);
5304 progressStepsContainer.textContent = '';
5305 if (currentProgressStep >= progressSteps.length) {
5306 warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)');
5307 }
5308 progressSteps.forEach((step, index) => {
5309 const stepEl = createStepElement(step);
5310 progressStepsContainer.appendChild(stepEl);
5311 if (index === currentProgressStep) {
5312 addClass(stepEl, swalClasses['active-progress-step']);
5313 }
5314 if (index !== progressSteps.length - 1) {
5315 const lineEl = createLineElement(params);
5316 progressStepsContainer.appendChild(lineEl);
5317 }
5318 });
5319 };
5320
5321 /**
5322 * @param {string} step
5323 * @returns {HTMLLIElement}
5324 */
5325 const createStepElement = step => {
5326 const stepEl = document.createElement('li');
5327 addClass(stepEl, swalClasses['progress-step']);
5328 setInnerHtml(stepEl, step);
5329 return stepEl;
5330 };
5331
5332 /**
5333 * @param {SweetAlertOptions} params
5334 * @returns {HTMLLIElement}
5335 */
5336 const createLineElement = params => {
5337 const lineEl = document.createElement('li');
5338 addClass(lineEl, swalClasses['progress-step-line']);
5339 if (params.progressStepsDistance) {
5340 applyNumericalStyle(lineEl, 'width', params.progressStepsDistance);
5341 }
5342 return lineEl;
5343 };
5344
5345 /**
5346 * @param {SweetAlert} instance
5347 * @param {SweetAlertOptions} params
5348 */
5349 const renderTitle = (instance, params) => {
5350 const title = getTitle();
5351 if (!title) {
5352 return;
5353 }
5354 showWhenInnerHtmlPresent(title);
5355 toggle(title, Boolean(params.title || params.titleText), 'block');
5356 if (params.title) {
5357 parseHtmlToContainer(params.title, title);
5358 }
5359 if (params.titleText) {
5360 title.innerText = params.titleText;
5361 }
5362
5363 // Custom class
5364 applyCustomClass(title, params, 'title');
5365 };
5366
5367 /**
5368 * @param {SweetAlert} instance
5369 * @param {SweetAlertOptions} params
5370 */
5371 const render = (instance, params) => {
5372 var _globalState$eventEmi;
5373 renderPopup(instance, params);
5374 renderContainer(instance, params);
5375 renderProgressSteps(instance, params);
5376 renderIcon(instance, params);
5377 renderImage(instance, params);
5378 renderTitle(instance, params);
5379 renderCloseButton(instance, params);
5380 renderContent(instance, params);
5381 renderActions(instance, params);
5382 renderFooter(instance, params);
5383 const popup = getPopup();
5384 if (typeof params.didRender === 'function' && popup) {
5385 params.didRender(popup);
5386 }
5387 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didRender', popup);
5388 };
5389
5390 /*
5391 * Global function to determine if SweetAlert2 popup is shown
5392 */
5393 const isVisible = () => {
5394 return isVisible$1(getPopup());
5395 };
5396
5397 /*
5398 * Global function to click 'Confirm' button
5399 */
5400 const clickConfirm = () => {
5401 var _dom$getConfirmButton;
5402 return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click();
5403 };
5404
5405 /*
5406 * Global function to click 'Deny' button
5407 */
5408 const clickDeny = () => {
5409 var _dom$getDenyButton;
5410 return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click();
5411 };
5412
5413 /*
5414 * Global function to click 'Cancel' button
5415 */
5416 const clickCancel = () => {
5417 var _dom$getCancelButton;
5418 return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click();
5419 };
5420
5421 /** @type {Record<DismissReason, DismissReason>} */
5422 const DismissReason = Object.freeze({
5423 cancel: 'cancel',
5424 backdrop: 'backdrop',
5425 close: 'close',
5426 esc: 'esc',
5427 timer: 'timer'
5428 });
5429
5430 /**
5431 * @param {GlobalState} globalState
5432 */
5433 const removeKeydownHandler = globalState => {
5434 if (globalState.keydownTarget && globalState.keydownHandlerAdded && globalState.keydownHandler) {
5435 const handler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */globalState.keydownHandler;
5436 globalState.keydownTarget.removeEventListener('keydown', handler, {
5437 capture: globalState.keydownListenerCapture
5438 });
5439 globalState.keydownHandlerAdded = false;
5440 }
5441 };
5442
5443 /**
5444 * @param {GlobalState} globalState
5445 * @param {SweetAlertOptions} innerParams
5446 * @param {(dismiss: DismissReason) => void} dismissWith
5447 */
5448 const addKeydownHandler = (globalState, innerParams, dismissWith) => {
5449 removeKeydownHandler(globalState);
5450 if (!innerParams.toast) {
5451 /** @type {(this: HTMLElement, event: KeyboardEvent) => void} */
5452 const handler = e => keydownHandler(innerParams, e, dismissWith);
5453 globalState.keydownHandler = handler;
5454 const target = innerParams.keydownListenerCapture ? window : getPopup();
5455 if (target) {
5456 globalState.keydownTarget = target;
5457 globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
5458 const eventHandler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */handler;
5459 globalState.keydownTarget.addEventListener('keydown', eventHandler, {
5460 capture: globalState.keydownListenerCapture
5461 });
5462 globalState.keydownHandlerAdded = true;
5463 }
5464 }
5465 };
5466
5467 /**
5468 * @param {number} index
5469 * @param {number} increment
5470 */
5471 const setFocus = (index, increment) => {
5472 var _dom$getPopup;
5473 const focusableElements = getFocusableElements();
5474 // search for visible elements and select the next possible match
5475 if (focusableElements.length) {
5476 index = index + increment;
5477
5478 // shift + tab when .swal2-popup is focused
5479 if (index === -2) {
5480 index = focusableElements.length - 1;
5481 }
5482
5483 // rollover to first item
5484 if (index === focusableElements.length) {
5485 index = 0;
5486
5487 // go to last item
5488 } else if (index === -1) {
5489 index = focusableElements.length - 1;
5490 }
5491 focusableElements[index].focus();
5492 return;
5493 }
5494 // no visible focusable elements, focus the popup
5495 (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus();
5496 };
5497 const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
5498 const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
5499
5500 /**
5501 * @param {SweetAlertOptions} innerParams
5502 * @param {KeyboardEvent} event
5503 * @param {(dismiss: DismissReason) => void} dismissWith
5504 */
5505 const keydownHandler = (innerParams, event, dismissWith) => {
5506 if (!innerParams) {
5507 return; // This instance has already been destroyed
5508 }
5509
5510 // Ignore keydown during IME composition
5511 // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
5512 // https://github.com/sweetalert2/sweetalert2/issues/720
5513 // https://github.com/sweetalert2/sweetalert2/issues/2406
5514 if (event.isComposing || event.keyCode === 229) {
5515 return;
5516 }
5517 if (innerParams.stopKeydownPropagation) {
5518 event.stopPropagation();
5519 }
5520
5521 // ENTER
5522 if (event.key === 'Enter') {
5523 handleEnter(event, innerParams);
5524 }
5525
5526 // TAB
5527 else if (event.key === 'Tab') {
5528 handleTab(event);
5529 }
5530
5531 // ARROWS - switch focus between buttons
5532 else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) {
5533 handleArrows(event.key);
5534 }
5535
5536 // ESC
5537 else if (event.key === 'Escape') {
5538 handleEsc(event, innerParams, dismissWith);
5539 }
5540 };
5541
5542 /**
5543 * @param {KeyboardEvent} event
5544 * @param {SweetAlertOptions} innerParams
5545 */
5546 const handleEnter = (event, innerParams) => {
5547 // https://github.com/sweetalert2/sweetalert2/issues/2386
5548 if (!callIfFunction(innerParams.allowEnterKey)) {
5549 return;
5550 }
5551 const popup = getPopup();
5552 if (!popup || !innerParams.input) {
5553 return;
5554 }
5555 const input = getInput$1(popup, innerParams.input);
5556 if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) {
5557 if (['textarea', 'file'].includes(innerParams.input)) {
5558 return; // do not submit
5559 }
5560 clickConfirm();
5561 event.preventDefault();
5562 }
5563 };
5564
5565 /**
5566 * @param {KeyboardEvent} event
5567 */
5568 const handleTab = event => {
5569 const targetElement = event.target;
5570 const focusableElements = getFocusableElements();
5571 let btnIndex = -1;
5572 for (let i = 0; i < focusableElements.length; i++) {
5573 if (targetElement === focusableElements[i]) {
5574 btnIndex = i;
5575 break;
5576 }
5577 }
5578
5579 // Cycle to the next button
5580 if (!event.shiftKey) {
5581 setFocus(btnIndex, 1);
5582 }
5583
5584 // Cycle to the prev button
5585 else {
5586 setFocus(btnIndex, -1);
5587 }
5588 event.stopPropagation();
5589 event.preventDefault();
5590 };
5591
5592 /**
5593 * @param {string} key
5594 */
5595 const handleArrows = key => {
5596 const actions = getActions();
5597 const confirmButton = getConfirmButton();
5598 const denyButton = getDenyButton();
5599 const cancelButton = getCancelButton();
5600 if (!actions || !confirmButton || !denyButton || !cancelButton) {
5601 return;
5602 }
5603 /** @type HTMLElement[] */
5604 const buttons = [confirmButton, denyButton, cancelButton];
5605 if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) {
5606 return;
5607 }
5608 const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
5609 let buttonToFocus = document.activeElement;
5610 if (!buttonToFocus) {
5611 return;
5612 }
5613 for (let i = 0; i < actions.children.length; i++) {
5614 buttonToFocus = buttonToFocus[sibling];
5615 if (!buttonToFocus) {
5616 return;
5617 }
5618 if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) {
5619 break;
5620 }
5621 }
5622 if (buttonToFocus instanceof HTMLButtonElement) {
5623 buttonToFocus.focus();
5624 }
5625 };
5626
5627 /**
5628 * @param {KeyboardEvent} event
5629 * @param {SweetAlertOptions} innerParams
5630 * @param {(dismiss: DismissReason) => void} dismissWith
5631 */
5632 const handleEsc = (event, innerParams, dismissWith) => {
5633 event.preventDefault();
5634 if (callIfFunction(innerParams.allowEscapeKey)) {
5635 dismissWith(DismissReason.esc);
5636 }
5637 };
5638
5639 /**
5640 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
5641 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
5642 * This is the approach that Babel will probably take to implement private methods/fields
5643 * https://github.com/tc39/proposal-private-methods
5644 * https://github.com/babel/babel/pull/7555
5645 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
5646 * then we can use that language feature.
5647 */
5648
5649 var privateMethods = {
5650 swalPromiseResolve: new WeakMap(),
5651 swalPromiseReject: new WeakMap()
5652 };
5653
5654 // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/
5655 // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
5656 // elements not within the active modal dialog will not be surfaced if a user opens a screen
5657 // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
5658
5659 const setAriaHidden = () => {
5660 const container = getContainer();
5661 const bodyChildren = Array.from(document.body.children);
5662 bodyChildren.forEach(el => {
5663 if (el.contains(container)) {
5664 return;
5665 }
5666 if (el.hasAttribute('aria-hidden')) {
5667 el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || '');
5668 }
5669 el.setAttribute('aria-hidden', 'true');
5670 });
5671 };
5672 const unsetAriaHidden = () => {
5673 const bodyChildren = Array.from(document.body.children);
5674 bodyChildren.forEach(el => {
5675 if (el.hasAttribute('data-previous-aria-hidden')) {
5676 el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || '');
5677 el.removeAttribute('data-previous-aria-hidden');
5678 } else {
5679 el.removeAttribute('aria-hidden');
5680 }
5681 });
5682 };
5683
5684 // @ts-ignore
5685 const isSafariOrIOS = typeof window !== 'undefined' && Boolean(window.GestureEvent); // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394
5686
5687 /**
5688 * Fix iOS scrolling
5689 * http://stackoverflow.com/q/39626302
5690 */
5691 const iOSfix = () => {
5692 if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) {
5693 const offset = document.body.scrollTop;
5694 document.body.style.top = `${offset * -1}px`;
5695 addClass(document.body, swalClasses.iosfix);
5696 lockBodyScroll();
5697 }
5698 };
5699
5700 /**
5701 * https://github.com/sweetalert2/sweetalert2/issues/1246
5702 */
5703 const lockBodyScroll = () => {
5704 const container = getContainer();
5705 if (!container) {
5706 return;
5707 }
5708 /** @type {boolean} */
5709 let preventTouchMove;
5710 /**
5711 * @param {TouchEvent} event
5712 */
5713 container.ontouchstart = event => {
5714 preventTouchMove = shouldPreventTouchMove(event);
5715 };
5716 /**
5717 * @param {TouchEvent} event
5718 */
5719 container.ontouchmove = event => {
5720 if (preventTouchMove) {
5721 event.preventDefault();
5722 event.stopPropagation();
5723 }
5724 };
5725 };
5726
5727 /**
5728 * @param {TouchEvent} event
5729 * @returns {boolean}
5730 */
5731 const shouldPreventTouchMove = event => {
5732 const target = event.target;
5733 const container = getContainer();
5734 const htmlContainer = getHtmlContainer();
5735 if (!container || !htmlContainer) {
5736 return false;
5737 }
5738 if (isStylus(event) || isZoom(event)) {
5739 return false;
5740 }
5741 if (target === container) {
5742 return true;
5743 }
5744 if (!isScrollable(container) && target instanceof HTMLElement && !selfOrParentIsScrollable(target, htmlContainer) &&
5745 // #2823
5746 target.tagName !== 'INPUT' &&
5747 // #1603
5748 target.tagName !== 'TEXTAREA' &&
5749 // #2266
5750 !(isScrollable(htmlContainer) &&
5751 // #1944
5752 htmlContainer.contains(target))) {
5753 return true;
5754 }
5755 return false;
5756 };
5757
5758 /**
5759 * https://github.com/sweetalert2/sweetalert2/issues/1786
5760 *
5761 * @param {TouchEvent} event
5762 * @returns {boolean}
5763 */
5764 const isStylus = event => {
5765 return Boolean(event.touches && event.touches.length &&
5766 // @ts-ignore - touchType is not a standard property
5767 event.touches[0].touchType === 'stylus');
5768 };
5769
5770 /**
5771 * https://github.com/sweetalert2/sweetalert2/issues/1891
5772 *
5773 * @param {TouchEvent} event
5774 * @returns {boolean}
5775 */
5776 const isZoom = event => {
5777 return event.touches && event.touches.length > 1;
5778 };
5779 const undoIOSfix = () => {
5780 if (hasClass(document.body, swalClasses.iosfix)) {
5781 const offset = parseInt(document.body.style.top, 10);
5782 removeClass(document.body, swalClasses.iosfix);
5783 document.body.style.top = '';
5784 document.body.scrollTop = offset * -1;
5785 }
5786 };
5787
5788 /**
5789 * Measure scrollbar width for padding body during modal show/hide
5790 * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js
5791 *
5792 * @returns {number}
5793 */
5794 const measureScrollbar = () => {
5795 const scrollDiv = document.createElement('div');
5796 scrollDiv.className = swalClasses['scrollbar-measure'];
5797 document.body.appendChild(scrollDiv);
5798 const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
5799 document.body.removeChild(scrollDiv);
5800 return scrollbarWidth;
5801 };
5802
5803 /**
5804 * Remember state in cases where opening and handling a modal will fiddle with it.
5805 * @type {number | null}
5806 */
5807 let previousBodyPadding = null;
5808
5809 /**
5810 * @param {string} initialBodyOverflow
5811 */
5812 const replaceScrollbarWithPadding = initialBodyOverflow => {
5813 // for queues, do not do this more than once
5814 if (previousBodyPadding !== null) {
5815 return;
5816 }
5817 // if the body has overflow
5818 if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663
5819 ) {
5820 // add padding so the content doesn't shift after removal of scrollbar
5821 previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
5822 document.body.style.paddingRight = `${previousBodyPadding + measureScrollbar()}px`;
5823 }
5824 };
5825 const undoReplaceScrollbarWithPadding = () => {
5826 if (previousBodyPadding !== null) {
5827 document.body.style.paddingRight = `${previousBodyPadding}px`;
5828 previousBodyPadding = null;
5829 }
5830 };
5831
5832 /**
5833 * @param {SweetAlert} instance
5834 * @param {HTMLElement} container
5835 * @param {boolean} returnFocus
5836 * @param {(() => void) | undefined} didClose
5837 */
5838 function removePopupAndResetState(instance, container, returnFocus, didClose) {
5839 if (isToast()) {
5840 triggerDidCloseAndDispose(instance, didClose);
5841 } else {
5842 restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
5843 removeKeydownHandler(globalState);
5844 }
5845
5846 // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088
5847 // for some reason removing the container in Safari will scroll the document to bottom
5848 if (isSafariOrIOS) {
5849 container.setAttribute('style', 'display:none !important');
5850 container.removeAttribute('class');
5851 container.innerHTML = '';
5852 } else {
5853 container.remove();
5854 }
5855 if (isModal()) {
5856 undoReplaceScrollbarWithPadding();
5857 undoIOSfix();
5858 unsetAriaHidden();
5859 }
5860 removeBodyClasses();
5861 }
5862
5863 /**
5864 * Remove SweetAlert2 classes from body
5865 */
5866 function removeBodyClasses() {
5867 removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
5868 }
5869
5870 /**
5871 * Instance method to close sweetAlert
5872 *
5873 * @param {SweetAlertResult | undefined} resolveValue
5874 * @this {SweetAlert}
5875 */
5876 function close(resolveValue) {
5877 resolveValue = prepareResolveValue(resolveValue);
5878 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
5879 const didClose = triggerClosePopup(this);
5880 if (this.isAwaitingPromise) {
5881 // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
5882 if (!resolveValue.isDismissed) {
5883 handleAwaitingPromise(this);
5884 swalPromiseResolve(resolveValue);
5885 }
5886 } else if (didClose) {
5887 // Resolve Swal promise
5888 swalPromiseResolve(resolveValue);
5889 }
5890 }
5891
5892 /**
5893 * @param {SweetAlert} instance
5894 * @returns {boolean}
5895 */
5896 const triggerClosePopup = instance => {
5897 const popup = getPopup();
5898 if (!popup) {
5899 return false;
5900 }
5901 const innerParams = privateProps.innerParams.get(instance);
5902 if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
5903 return false;
5904 }
5905 removeClass(popup, innerParams.showClass.popup);
5906 addClass(popup, innerParams.hideClass.popup);
5907 const backdrop = getContainer();
5908 removeClass(backdrop, innerParams.showClass.backdrop);
5909 addClass(backdrop, innerParams.hideClass.backdrop);
5910 handlePopupAnimation(instance, popup, innerParams);
5911 return true;
5912 };
5913
5914 /**
5915 * @param {Error | string} error
5916 * @this {SweetAlert}
5917 */
5918 function rejectPromise(error) {
5919 const rejectPromise = privateMethods.swalPromiseReject.get(this);
5920 handleAwaitingPromise(this);
5921 if (rejectPromise) {
5922 // Reject Swal promise
5923 rejectPromise(error);
5924 }
5925 }
5926
5927 /**
5928 * @param {SweetAlert} instance
5929 */
5930 const handleAwaitingPromise = instance => {
5931 if (instance.isAwaitingPromise) {
5932 // @ts-ignore
5933 delete instance.isAwaitingPromise;
5934 // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
5935 if (!privateProps.innerParams.get(instance)) {
5936 instance._destroy();
5937 }
5938 }
5939 };
5940
5941 /**
5942 * @param {SweetAlertResult | undefined} resolveValue
5943 * @returns {SweetAlertResult}
5944 */
5945 const prepareResolveValue = resolveValue => {
5946 // When user calls Swal.close()
5947 if (typeof resolveValue === 'undefined') {
5948 return {
5949 isConfirmed: false,
5950 isDenied: false,
5951 isDismissed: true
5952 };
5953 }
5954 return Object.assign({
5955 isConfirmed: false,
5956 isDenied: false,
5957 isDismissed: false
5958 }, resolveValue);
5959 };
5960
5961 /**
5962 * @param {SweetAlert} instance
5963 * @param {HTMLElement} popup
5964 * @param {SweetAlertOptions} innerParams
5965 */
5966 const handlePopupAnimation = (instance, popup, innerParams) => {
5967 var _globalState$eventEmi;
5968 const container = getContainer();
5969 // If animation is supported, animate
5970 const animationIsSupported = hasCssAnimation(popup);
5971 if (typeof innerParams.willClose === 'function') {
5972 innerParams.willClose(popup);
5973 }
5974 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willClose', popup);
5975 if (animationIsSupported && container) {
5976 animatePopup(instance, popup, container, Boolean(innerParams.returnFocus), innerParams.didClose);
5977 } else if (container) {
5978 // Otherwise, remove immediately
5979 removePopupAndResetState(instance, container, Boolean(innerParams.returnFocus), innerParams.didClose);
5980 }
5981 };
5982
5983 /**
5984 * @param {SweetAlert} instance
5985 * @param {HTMLElement} popup
5986 * @param {HTMLElement} container
5987 * @param {boolean} returnFocus
5988 * @param {(() => void) | undefined} didClose
5989 */
5990 const animatePopup = (instance, popup, container, returnFocus, didClose) => {
5991 globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
5992 /**
5993 * @param {AnimationEvent | TransitionEvent} e
5994 */
5995 const swalCloseAnimationFinished = function (e) {
5996 if (e.target === popup) {
5997 var _globalState$swalClos;
5998 (_globalState$swalClos = globalState.swalCloseEventFinishedCallback) === null || _globalState$swalClos === void 0 || _globalState$swalClos.call(globalState);
5999 delete globalState.swalCloseEventFinishedCallback;
6000 popup.removeEventListener('animationend', swalCloseAnimationFinished);
6001 popup.removeEventListener('transitionend', swalCloseAnimationFinished);
6002 }
6003 };
6004 popup.addEventListener('animationend', swalCloseAnimationFinished);
6005 popup.addEventListener('transitionend', swalCloseAnimationFinished);
6006 };
6007
6008 /**
6009 * @param {SweetAlert} instance
6010 * @param {(() => void) | undefined} didClose
6011 */
6012 const triggerDidCloseAndDispose = (instance, didClose) => {
6013 setTimeout(() => {
6014 var _globalState$eventEmi2;
6015 if (typeof didClose === 'function') {
6016 didClose.bind(instance.params)();
6017 }
6018 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didClose');
6019 // instance might have been destroyed already
6020 if (instance._destroy) {
6021 instance._destroy();
6022 }
6023 });
6024 };
6025
6026 /**
6027 * Shows loader (spinner), this is useful with AJAX requests.
6028 * By default the loader be shown instead of the "Confirm" button.
6029 *
6030 * @param {HTMLButtonElement | null} [buttonToReplace]
6031 */
6032 const showLoading = buttonToReplace => {
6033 let popup = getPopup();
6034 if (!popup) {
6035 new Swal();
6036 }
6037 popup = getPopup();
6038 if (!popup) {
6039 return;
6040 }
6041 const loader = getLoader();
6042 if (isToast()) {
6043 hide(getIcon());
6044 } else {
6045 replaceButton(popup, buttonToReplace);
6046 }
6047 show(loader);
6048 popup.setAttribute('data-loading', 'true');
6049 popup.setAttribute('aria-busy', 'true');
6050 popup.focus();
6051 };
6052
6053 /**
6054 * @param {HTMLElement} popup
6055 * @param {HTMLButtonElement | null} [buttonToReplace]
6056 */
6057 const replaceButton = (popup, buttonToReplace) => {
6058 const actions = getActions();
6059 const loader = getLoader();
6060 if (!actions || !loader) {
6061 return;
6062 }
6063 if (!buttonToReplace && isVisible$1(getConfirmButton())) {
6064 buttonToReplace = getConfirmButton();
6065 }
6066 show(actions);
6067 if (buttonToReplace) {
6068 hide(buttonToReplace);
6069 loader.setAttribute('data-button-to-replace', buttonToReplace.className);
6070 actions.insertBefore(loader, buttonToReplace);
6071 }
6072 addClass([popup, actions], swalClasses.loading);
6073 };
6074
6075 /**
6076 * @param {SweetAlert} instance
6077 * @param {SweetAlertOptions} params
6078 */
6079 const handleInputOptionsAndValue = (instance, params) => {
6080 if (params.input === 'select' || params.input === 'radio') {
6081 handleInputOptions(instance, params);
6082 } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
6083 showLoading(getConfirmButton());
6084 handleInputValue(instance, params);
6085 }
6086 };
6087
6088 /**
6089 * @param {SweetAlert} instance
6090 * @param {SweetAlertOptions} innerParams
6091 * @returns {SweetAlertInputValue}
6092 */
6093 const getInputValue = (instance, innerParams) => {
6094 const input = instance.getInput();
6095 if (!input) {
6096 return null;
6097 }
6098 switch (innerParams.input) {
6099 case 'checkbox':
6100 return getCheckboxValue(input);
6101 case 'radio':
6102 return getRadioValue(input);
6103 case 'file':
6104 return getFileValue(input);
6105 default:
6106 return innerParams.inputAutoTrim ? input.value.trim() : input.value;
6107 }
6108 };
6109
6110 /**
6111 * @param {HTMLInputElement} input
6112 * @returns {number}
6113 */
6114 const getCheckboxValue = input => input.checked ? 1 : 0;
6115
6116 /**
6117 * @param {HTMLInputElement} input
6118 * @returns {string | null}
6119 */
6120 const getRadioValue = input => input.checked ? input.value : null;
6121
6122 /**
6123 * @param {HTMLInputElement} input
6124 * @returns {FileList | File | null}
6125 */
6126 const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null;
6127
6128 /**
6129 * @param {SweetAlert} instance
6130 * @param {SweetAlertOptions} params
6131 */
6132 const handleInputOptions = (instance, params) => {
6133 const popup = getPopup();
6134 if (!popup) {
6135 return;
6136 }
6137 /**
6138 * @param {*} inputOptions
6139 */
6140 const processInputOptions = inputOptions => {
6141 if (params.input === 'select') {
6142 populateSelectOptions(popup, formatInputOptions(inputOptions), params);
6143 } else if (params.input === 'radio') {
6144 populateRadioOptions(popup, formatInputOptions(inputOptions), params);
6145 }
6146 };
6147 if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) {
6148 showLoading(getConfirmButton());
6149 asPromise(params.inputOptions).then(inputOptions => {
6150 instance.hideLoading();
6151 processInputOptions(inputOptions);
6152 });
6153 } else if (typeof params.inputOptions === 'object') {
6154 processInputOptions(params.inputOptions);
6155 } else {
6156 error(`Unexpected type of inputOptions! Expected object, Map or Promise, got ${typeof params.inputOptions}`);
6157 }
6158 };
6159
6160 /**
6161 * @param {SweetAlert} instance
6162 * @param {SweetAlertOptions} params
6163 */
6164 const handleInputValue = (instance, params) => {
6165 const input = instance.getInput();
6166 if (!input) {
6167 return;
6168 }
6169 hide(input);
6170 asPromise(params.inputValue).then(inputValue => {
6171 input.value = params.input === 'number' ? `${parseFloat(inputValue) || 0}` : `${inputValue}`;
6172 show(input);
6173 input.focus();
6174 instance.hideLoading();
6175 }).catch(err => {
6176 error(`Error in inputValue promise: ${err}`);
6177 input.value = '';
6178 show(input);
6179 input.focus();
6180 instance.hideLoading();
6181 });
6182 };
6183
6184 /**
6185 * @param {HTMLElement} popup
6186 * @param {InputOptionFlattened[]} inputOptions
6187 * @param {SweetAlertOptions} params
6188 */
6189 function populateSelectOptions(popup, inputOptions, params) {
6190 const select = getDirectChildByClass(popup, swalClasses.select);
6191 if (!select) {
6192 return;
6193 }
6194 /**
6195 * @param {HTMLElement} parent
6196 * @param {string} optionLabel
6197 * @param {string} optionValue
6198 */
6199 const renderOption = (parent, optionLabel, optionValue) => {
6200 const option = document.createElement('option');
6201 option.value = optionValue;
6202 setInnerHtml(option, optionLabel);
6203 option.selected = isSelected(optionValue, params.inputValue);
6204 parent.appendChild(option);
6205 };
6206 inputOptions.forEach(inputOption => {
6207 const optionValue = inputOption[0];
6208 const optionLabel = inputOption[1];
6209 // <optgroup> spec:
6210 // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
6211 // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
6212 // check whether this is a <optgroup>
6213 if (Array.isArray(optionLabel)) {
6214 // if it is an array, then it is an <optgroup>
6215 const optgroup = document.createElement('optgroup');
6216 optgroup.label = optionValue;
6217 optgroup.disabled = false; // not configurable for now
6218 select.appendChild(optgroup);
6219 optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
6220 } else {
6221 // case of <option>
6222 renderOption(select, optionLabel, optionValue);
6223 }
6224 });
6225 select.focus();
6226 }
6227
6228 /**
6229 * @param {HTMLElement} popup
6230 * @param {InputOptionFlattened[]} inputOptions
6231 * @param {SweetAlertOptions} params
6232 */
6233 function populateRadioOptions(popup, inputOptions, params) {
6234 const radio = getDirectChildByClass(popup, swalClasses.radio);
6235 if (!radio) {
6236 return;
6237 }
6238 inputOptions.forEach(inputOption => {
6239 const radioValue = inputOption[0];
6240 const radioLabel = inputOption[1];
6241 const radioInput = document.createElement('input');
6242 const radioLabelElement = document.createElement('label');
6243 radioInput.type = 'radio';
6244 radioInput.name = swalClasses.radio;
6245 radioInput.value = radioValue;
6246 if (isSelected(radioValue, params.inputValue)) {
6247 radioInput.checked = true;
6248 }
6249 const label = document.createElement('span');
6250 setInnerHtml(label, radioLabel);
6251 label.className = swalClasses.label;
6252 radioLabelElement.appendChild(radioInput);
6253 radioLabelElement.appendChild(label);
6254 radio.appendChild(radioLabelElement);
6255 });
6256 const radios = radio.querySelectorAll('input');
6257 if (radios.length) {
6258 radios[0].focus();
6259 }
6260 }
6261
6262 /**
6263 * Converts `inputOptions` into an array of `[value, label]`s
6264 *
6265 * @param {*} inputOptions
6266 * @typedef {string[]} InputOptionFlattened
6267 * @returns {InputOptionFlattened[]}
6268 */
6269 const formatInputOptions = inputOptions => {
6270 /** @type {InputOptionFlattened[]} */
6271 const result = [];
6272 if (inputOptions instanceof Map) {
6273 inputOptions.forEach((value, key) => {
6274 let valueFormatted = value;
6275 if (typeof valueFormatted === 'object') {
6276 // case of <optgroup>
6277 valueFormatted = formatInputOptions(valueFormatted);
6278 }
6279 result.push([key, valueFormatted]);
6280 });
6281 } else {
6282 Object.keys(inputOptions).forEach(key => {
6283 let valueFormatted = inputOptions[key];
6284 if (typeof valueFormatted === 'object') {
6285 // case of <optgroup>
6286 valueFormatted = formatInputOptions(valueFormatted);
6287 }
6288 result.push([key, valueFormatted]);
6289 });
6290 }
6291 return result;
6292 };
6293
6294 /**
6295 * @param {string} optionValue
6296 * @param {SweetAlertInputValue} inputValue
6297 * @returns {boolean}
6298 */
6299 const isSelected = (optionValue, inputValue) => {
6300 return Boolean(inputValue) && inputValue !== null && inputValue !== undefined && inputValue.toString() === optionValue.toString();
6301 };
6302
6303 /**
6304 * @param {SweetAlert} instance
6305 */
6306 const handleConfirmButtonClick = instance => {
6307 const innerParams = privateProps.innerParams.get(instance);
6308 instance.disableButtons();
6309 if (innerParams.input) {
6310 handleConfirmOrDenyWithInput(instance, 'confirm');
6311 } else {
6312 confirm(instance, true);
6313 }
6314 };
6315
6316 /**
6317 * @param {SweetAlert} instance
6318 */
6319 const handleDenyButtonClick = instance => {
6320 const innerParams = privateProps.innerParams.get(instance);
6321 instance.disableButtons();
6322 if (innerParams.returnInputValueOnDeny) {
6323 handleConfirmOrDenyWithInput(instance, 'deny');
6324 } else {
6325 deny(instance, false);
6326 }
6327 };
6328
6329 /**
6330 * @param {SweetAlert} instance
6331 * @param {(dismiss: DismissReason) => void} dismissWith
6332 */
6333 const handleCancelButtonClick = (instance, dismissWith) => {
6334 instance.disableButtons();
6335 dismissWith(DismissReason.cancel);
6336 };
6337
6338 /**
6339 * @param {SweetAlert} instance
6340 * @param {'confirm' | 'deny'} type
6341 */
6342 const handleConfirmOrDenyWithInput = (instance, type) => {
6343 const innerParams = privateProps.innerParams.get(instance);
6344 if (!innerParams.input) {
6345 error(`The "input" parameter is needed to be set when using returnInputValueOn${capitalizeFirstLetter(type)}`);
6346 return;
6347 }
6348 const input = instance.getInput();
6349 const inputValue = getInputValue(instance, innerParams);
6350 if (innerParams.inputValidator) {
6351 handleInputValidator(instance, inputValue, type);
6352 } else if (input && !input.checkValidity()) {
6353 instance.enableButtons();
6354 instance.showValidationMessage(innerParams.validationMessage || input.validationMessage);
6355 } else if (type === 'deny') {
6356 deny(instance, inputValue);
6357 } else {
6358 confirm(instance, inputValue);
6359 }
6360 };
6361
6362 /**
6363 * @param {SweetAlert} instance
6364 * @param {SweetAlertInputValue} inputValue
6365 * @param {'confirm' | 'deny'} type
6366 */
6367 const handleInputValidator = (instance, inputValue, type) => {
6368 const innerParams = privateProps.innerParams.get(instance);
6369 instance.disableInput();
6370 const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
6371 validationPromise.then(validationMessage => {
6372 instance.enableButtons();
6373 instance.enableInput();
6374 if (validationMessage) {
6375 instance.showValidationMessage(validationMessage);
6376 } else if (type === 'deny') {
6377 deny(instance, inputValue);
6378 } else {
6379 confirm(instance, inputValue);
6380 }
6381 });
6382 };
6383
6384 /**
6385 * @param {SweetAlert} instance
6386 * @param {*} value
6387 */
6388 const deny = (instance, value) => {
6389 const innerParams = privateProps.innerParams.get(instance);
6390 if (innerParams.showLoaderOnDeny) {
6391 showLoading(getDenyButton());
6392 }
6393 if (innerParams.preDeny) {
6394 instance.isAwaitingPromise = true; // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preDeny's promise is received
6395 const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
6396 preDenyPromise.then(preDenyValue => {
6397 if (preDenyValue === false) {
6398 instance.hideLoading();
6399 handleAwaitingPromise(instance);
6400 } else {
6401 instance.close(/** @type SweetAlertResult */{
6402 isDenied: true,
6403 value: typeof preDenyValue === 'undefined' ? value : preDenyValue
6404 });
6405 }
6406 }).catch(error => rejectWith(instance, error));
6407 } else {
6408 instance.close(/** @type SweetAlertResult */{
6409 isDenied: true,
6410 value
6411 });
6412 }
6413 };
6414
6415 /**
6416 * @param {SweetAlert} instance
6417 * @param {*} value
6418 */
6419 const succeedWith = (instance, value) => {
6420 instance.close(/** @type SweetAlertResult */{
6421 isConfirmed: true,
6422 value
6423 });
6424 };
6425
6426 /**
6427 *
6428 * @param {SweetAlert} instance
6429 * @param {string} error
6430 */
6431 const rejectWith = (instance, error) => {
6432 instance.rejectPromise(error);
6433 };
6434
6435 /**
6436 *
6437 * @param {SweetAlert} instance
6438 * @param {*} value
6439 */
6440 const confirm = (instance, value) => {
6441 const innerParams = privateProps.innerParams.get(instance);
6442 if (innerParams.showLoaderOnConfirm) {
6443 showLoading();
6444 }
6445 if (innerParams.preConfirm) {
6446 instance.resetValidationMessage();
6447 instance.isAwaitingPromise = true; // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preConfirm's promise is received
6448 const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
6449 preConfirmPromise.then(preConfirmValue => {
6450 if (isVisible$1(getValidationMessage()) || preConfirmValue === false) {
6451 instance.hideLoading();
6452 handleAwaitingPromise(instance);
6453 } else {
6454 succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
6455 }
6456 }).catch(error => rejectWith(instance, error));
6457 } else {
6458 succeedWith(instance, value);
6459 }
6460 };
6461
6462 /**
6463 * Hides loader and shows back the button which was hidden by .showLoading()
6464 * @this {SweetAlert}
6465 */
6466 function hideLoading() {
6467 // do nothing if popup is closed
6468 const innerParams = privateProps.innerParams.get(this);
6469 if (!innerParams) {
6470 return;
6471 }
6472 const domCache = privateProps.domCache.get(this);
6473 hide(domCache.loader);
6474 if (isToast()) {
6475 if (innerParams.icon) {
6476 show(getIcon());
6477 }
6478 } else {
6479 showRelatedButton(domCache);
6480 }
6481 removeClass([domCache.popup, domCache.actions], swalClasses.loading);
6482 domCache.popup.removeAttribute('aria-busy');
6483 domCache.popup.removeAttribute('data-loading');
6484 domCache.confirmButton.disabled = false;
6485 domCache.denyButton.disabled = false;
6486 domCache.cancelButton.disabled = false;
6487 }
6488
6489 /**
6490 * @param {DomCache} domCache
6491 */
6492 const showRelatedButton = domCache => {
6493 const dataButtonToReplace = domCache.loader.getAttribute('data-button-to-replace');
6494 const buttonToReplace = dataButtonToReplace ? domCache.popup.getElementsByClassName(dataButtonToReplace) : [];
6495 if (buttonToReplace.length) {
6496 show(/** @type {HTMLElement} */buttonToReplace[0], 'inline-block');
6497 } else if (allButtonsAreHidden()) {
6498 hide(domCache.actions);
6499 }
6500 };
6501
6502 /**
6503 * Gets the input DOM node, this method works with input parameter.
6504 *
6505 * @returns {HTMLInputElement | null}
6506 * @this {SweetAlert}
6507 */
6508 function getInput() {
6509 const innerParams = privateProps.innerParams.get(this);
6510 const domCache = privateProps.domCache.get(this);
6511 if (!domCache) {
6512 return null;
6513 }
6514 return getInput$1(domCache.popup, innerParams.input);
6515 }
6516
6517 /**
6518 * @param {SweetAlert} instance
6519 * @param {string[]} buttons
6520 * @param {boolean} disabled
6521 */
6522 function setButtonsDisabled(instance, buttons, disabled) {
6523 const domCache = privateProps.domCache.get(instance);
6524 buttons.forEach(button => {
6525 domCache[button].disabled = disabled;
6526 });
6527 }
6528
6529 /**
6530 * @param {HTMLInputElement | null} input
6531 * @param {boolean} disabled
6532 */
6533 function setInputDisabled(input, disabled) {
6534 const popup = getPopup();
6535 if (!popup || !input) {
6536 return;
6537 }
6538 if (input.type === 'radio') {
6539 /** @type {NodeListOf<HTMLInputElement>} */
6540 const radios = popup.querySelectorAll(`[name="${swalClasses.radio}"]`);
6541 for (let i = 0; i < radios.length; i++) {
6542 radios[i].disabled = disabled;
6543 }
6544 } else {
6545 input.disabled = disabled;
6546 }
6547 }
6548
6549 /**
6550 * Enable all the buttons
6551 * @this {SweetAlert}
6552 */
6553 function enableButtons() {
6554 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
6555 }
6556
6557 /**
6558 * Disable all the buttons
6559 * @this {SweetAlert}
6560 */
6561 function disableButtons() {
6562 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
6563 }
6564
6565 /**
6566 * Enable the input field
6567 * @this {SweetAlert}
6568 */
6569 function enableInput() {
6570 setInputDisabled(this.getInput(), false);
6571 }
6572
6573 /**
6574 * Disable the input field
6575 * @this {SweetAlert}
6576 */
6577 function disableInput() {
6578 setInputDisabled(this.getInput(), true);
6579 }
6580
6581 /**
6582 * Show block with validation message
6583 *
6584 * @param {string} error
6585 * @this {SweetAlert}
6586 */
6587 function showValidationMessage(error) {
6588 const domCache = privateProps.domCache.get(this);
6589 const params = privateProps.innerParams.get(this);
6590 setInnerHtml(domCache.validationMessage, error);
6591 domCache.validationMessage.className = swalClasses['validation-message'];
6592 if (params.customClass && params.customClass.validationMessage) {
6593 addClass(domCache.validationMessage, params.customClass.validationMessage);
6594 }
6595 show(domCache.validationMessage);
6596 const input = this.getInput();
6597 if (input) {
6598 input.setAttribute('aria-invalid', 'true');
6599 input.setAttribute('aria-describedby', swalClasses['validation-message']);
6600 focusInput(input);
6601 addClass(input, swalClasses.inputerror);
6602 }
6603 }
6604
6605 /**
6606 * Hide block with validation message
6607 *
6608 * @this {SweetAlert}
6609 */
6610 function resetValidationMessage() {
6611 const domCache = privateProps.domCache.get(this);
6612 if (domCache.validationMessage) {
6613 hide(domCache.validationMessage);
6614 }
6615 const input = this.getInput();
6616 if (input) {
6617 input.removeAttribute('aria-invalid');
6618 input.removeAttribute('aria-describedby');
6619 removeClass(input, swalClasses.inputerror);
6620 }
6621 }
6622
6623 const defaultParams = {
6624 title: '',
6625 titleText: '',
6626 text: '',
6627 html: '',
6628 footer: '',
6629 icon: undefined,
6630 iconColor: undefined,
6631 iconHtml: undefined,
6632 template: undefined,
6633 toast: false,
6634 draggable: false,
6635 animation: true,
6636 theme: 'light',
6637 showClass: {
6638 popup: 'swal2-show',
6639 backdrop: 'swal2-backdrop-show',
6640 icon: 'swal2-icon-show'
6641 },
6642 hideClass: {
6643 popup: 'swal2-hide',
6644 backdrop: 'swal2-backdrop-hide',
6645 icon: 'swal2-icon-hide'
6646 },
6647 customClass: {},
6648 target: 'body',
6649 color: undefined,
6650 backdrop: true,
6651 heightAuto: true,
6652 allowOutsideClick: true,
6653 allowEscapeKey: true,
6654 allowEnterKey: true,
6655 stopKeydownPropagation: true,
6656 keydownListenerCapture: false,
6657 showConfirmButton: true,
6658 showDenyButton: false,
6659 showCancelButton: false,
6660 preConfirm: undefined,
6661 preDeny: undefined,
6662 confirmButtonText: 'OK',
6663 confirmButtonAriaLabel: '',
6664 confirmButtonColor: undefined,
6665 denyButtonText: 'No',
6666 denyButtonAriaLabel: '',
6667 denyButtonColor: undefined,
6668 cancelButtonText: 'Cancel',
6669 cancelButtonAriaLabel: '',
6670 cancelButtonColor: undefined,
6671 buttonsStyling: true,
6672 reverseButtons: false,
6673 focusConfirm: true,
6674 focusDeny: false,
6675 focusCancel: false,
6676 returnFocus: true,
6677 showCloseButton: false,
6678 closeButtonHtml: '&times;',
6679 closeButtonAriaLabel: 'Close this dialog',
6680 loaderHtml: '',
6681 showLoaderOnConfirm: false,
6682 showLoaderOnDeny: false,
6683 imageUrl: undefined,
6684 imageWidth: undefined,
6685 imageHeight: undefined,
6686 imageAlt: '',
6687 timer: undefined,
6688 timerProgressBar: false,
6689 width: undefined,
6690 padding: undefined,
6691 background: undefined,
6692 input: undefined,
6693 inputPlaceholder: '',
6694 inputLabel: '',
6695 inputValue: '',
6696 inputOptions: {},
6697 inputAutoFocus: true,
6698 inputAutoTrim: true,
6699 inputAttributes: {},
6700 inputValidator: undefined,
6701 returnInputValueOnDeny: false,
6702 validationMessage: undefined,
6703 grow: false,
6704 position: 'center',
6705 progressSteps: [],
6706 currentProgressStep: undefined,
6707 progressStepsDistance: undefined,
6708 willOpen: undefined,
6709 didOpen: undefined,
6710 didRender: undefined,
6711 willClose: undefined,
6712 didClose: undefined,
6713 didDestroy: undefined,
6714 scrollbarPadding: true,
6715 topLayer: false
6716 };
6717 const updatableParams = ['allowEscapeKey', 'allowOutsideClick', 'background', 'buttonsStyling', 'cancelButtonAriaLabel', 'cancelButtonColor', 'cancelButtonText', 'closeButtonAriaLabel', 'closeButtonHtml', 'color', 'confirmButtonAriaLabel', 'confirmButtonColor', 'confirmButtonText', 'currentProgressStep', 'customClass', 'denyButtonAriaLabel', 'denyButtonColor', 'denyButtonText', 'didClose', 'didDestroy', 'draggable', 'footer', 'hideClass', 'html', 'icon', 'iconColor', 'iconHtml', 'imageAlt', 'imageHeight', 'imageUrl', 'imageWidth', 'preConfirm', 'preDeny', 'progressSteps', 'returnFocus', 'reverseButtons', 'showCancelButton', 'showCloseButton', 'showConfirmButton', 'showDenyButton', 'text', 'title', 'titleText', 'theme', 'willClose'];
6718
6719 /** @type {Record<string, string | undefined>} */
6720 const deprecatedParams = {
6721 allowEnterKey: undefined
6722 };
6723 const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'draggable', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
6724
6725 /**
6726 * Is valid parameter
6727 *
6728 * @param {string} paramName
6729 * @returns {boolean}
6730 */
6731 const isValidParameter = paramName => {
6732 return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
6733 };
6734
6735 /**
6736 * Is valid parameter for Swal.update() method
6737 *
6738 * @param {string} paramName
6739 * @returns {boolean}
6740 */
6741 const isUpdatableParameter = paramName => {
6742 return updatableParams.indexOf(paramName) !== -1;
6743 };
6744
6745 /**
6746 * Is deprecated parameter
6747 *
6748 * @param {string} paramName
6749 * @returns {string | undefined}
6750 */
6751 const isDeprecatedParameter = paramName => {
6752 return deprecatedParams[paramName];
6753 };
6754
6755 /**
6756 * @param {string} param
6757 */
6758 const checkIfParamIsValid = param => {
6759 if (!isValidParameter(param)) {
6760 warn(`Unknown parameter "${param}"`);
6761 }
6762 };
6763
6764 /**
6765 * @param {string} param
6766 */
6767 const checkIfToastParamIsValid = param => {
6768 if (toastIncompatibleParams.includes(param)) {
6769 warn(`The parameter "${param}" is incompatible with toasts`);
6770 }
6771 };
6772
6773 /**
6774 * @param {string} param
6775 */
6776 const checkIfParamIsDeprecated = param => {
6777 const isDeprecated = isDeprecatedParameter(param);
6778 if (isDeprecated) {
6779 warnAboutDeprecation(param, isDeprecated);
6780 }
6781 };
6782
6783 /**
6784 * Show relevant warnings for given params
6785 *
6786 * @param {SweetAlertOptions} params
6787 */
6788 const showWarningsForParams = params => {
6789 if (params.backdrop === false && params.allowOutsideClick) {
6790 warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
6791 }
6792 if (params.theme && !['light', 'dark', 'auto', 'minimal', 'borderless', 'bootstrap-4', 'bootstrap-4-light', 'bootstrap-4-dark', 'bootstrap-5', 'bootstrap-5-light', 'bootstrap-5-dark', 'material-ui', 'material-ui-light', 'material-ui-dark', 'embed-iframe', 'bulma', 'bulma-light', 'bulma-dark'].includes(params.theme)) {
6793 warn(`Invalid theme "${params.theme}"`);
6794 }
6795 for (const param in params) {
6796 checkIfParamIsValid(param);
6797 if (params.toast) {
6798 checkIfToastParamIsValid(param);
6799 }
6800 checkIfParamIsDeprecated(param);
6801 }
6802 };
6803
6804 /**
6805 * Updates popup parameters.
6806 *
6807 * @this {any}
6808 * @param {SweetAlertOptions} params
6809 */
6810 function update(params) {
6811 const container = getContainer();
6812 const popup = getPopup();
6813 const innerParams = privateProps.innerParams.get(this);
6814 if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
6815 warn(`You're trying to update the closed or closing popup, that won't work. Use the update() method in preConfirm parameter or show a new popup.`);
6816 return;
6817 }
6818 const validUpdatableParams = filterValidParams(params);
6819 const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
6820 showWarningsForParams(updatedParams);
6821 if (container) {
6822 container.dataset['swal2Theme'] = updatedParams.theme;
6823 }
6824 render(this, updatedParams);
6825 privateProps.innerParams.set(this, updatedParams);
6826 Object.defineProperties(this, {
6827 params: {
6828 value: Object.assign({}, this.params, params),
6829 writable: false,
6830 enumerable: true
6831 }
6832 });
6833 }
6834
6835 /**
6836 * @param {SweetAlertOptions} params
6837 * @returns {SweetAlertOptions}
6838 */
6839 const filterValidParams = params => {
6840 /** @type {Record<string, any>} */
6841 const validUpdatableParams = {};
6842 Object.keys(params).forEach(param => {
6843 if (isUpdatableParameter(param)) {
6844 const typedParams = /** @type {Record<string, any>} */params;
6845 validUpdatableParams[param] = typedParams[param];
6846 } else {
6847 warn(`Invalid parameter to update: ${param}`);
6848 }
6849 });
6850 return validUpdatableParams;
6851 };
6852
6853 /**
6854 * Dispose the current SweetAlert2 instance
6855 * @this {SweetAlert}
6856 */
6857 function _destroy() {
6858 var _globalState$eventEmi;
6859 const domCache = privateProps.domCache.get(this);
6860 const innerParams = privateProps.innerParams.get(this);
6861 if (!innerParams) {
6862 disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
6863 return; // This instance has already been destroyed
6864 }
6865
6866 // Check if there is another Swal closing
6867 if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
6868 globalState.swalCloseEventFinishedCallback();
6869 delete globalState.swalCloseEventFinishedCallback;
6870 }
6871 if (typeof innerParams.didDestroy === 'function') {
6872 innerParams.didDestroy();
6873 }
6874 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didDestroy');
6875 disposeSwal(this);
6876 }
6877
6878 /**
6879 * @param {SweetAlert} instance
6880 */
6881 const disposeSwal = instance => {
6882 disposeWeakMaps(instance);
6883 // Unset this.params so GC will dispose it (#1569)
6884 // @ts-ignore
6885 delete instance.params;
6886 // Unset globalState props so GC will dispose globalState (#1569)
6887 delete globalState.keydownHandler;
6888 delete globalState.keydownTarget;
6889 // Unset currentInstance
6890 delete globalState.currentInstance;
6891 };
6892
6893 /**
6894 * @param {SweetAlert} instance
6895 */
6896 const disposeWeakMaps = instance => {
6897 // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
6898 if (instance.isAwaitingPromise) {
6899 unsetWeakMaps(privateProps, instance);
6900 instance.isAwaitingPromise = true;
6901 } else {
6902 unsetWeakMaps(privateMethods, instance);
6903 unsetWeakMaps(privateProps, instance);
6904
6905 // @ts-ignore
6906 delete instance.isAwaitingPromise;
6907 // Unset instance methods
6908 // @ts-ignore
6909 delete instance.disableButtons;
6910 // @ts-ignore
6911 delete instance.enableButtons;
6912 // @ts-ignore
6913 delete instance.getInput;
6914 // @ts-ignore
6915 delete instance.disableInput;
6916 // @ts-ignore
6917 delete instance.enableInput;
6918 // @ts-ignore
6919 delete instance.hideLoading;
6920 // @ts-ignore
6921 delete instance.disableLoading;
6922 // @ts-ignore
6923 delete instance.showValidationMessage;
6924 // @ts-ignore
6925 delete instance.resetValidationMessage;
6926 // @ts-ignore
6927 delete instance.close;
6928 // @ts-ignore
6929 delete instance.closePopup;
6930 // @ts-ignore
6931 delete instance.closeModal;
6932 // @ts-ignore
6933 delete instance.closeToast;
6934 // @ts-ignore
6935 delete instance.rejectPromise;
6936 // @ts-ignore
6937 delete instance.update;
6938 // @ts-ignore
6939 delete instance._destroy;
6940 }
6941 };
6942
6943 /**
6944 * @param {Record<string, WeakMap<any, any>>} obj
6945 * @param {SweetAlert} instance
6946 */
6947 const unsetWeakMaps = (obj, instance) => {
6948 for (const i in obj) {
6949 obj[i].delete(instance);
6950 }
6951 };
6952
6953 var instanceMethods = /*#__PURE__*/Object.freeze({
6954 __proto__: null,
6955 _destroy: _destroy,
6956 close: close,
6957 closeModal: close,
6958 closePopup: close,
6959 closeToast: close,
6960 disableButtons: disableButtons,
6961 disableInput: disableInput,
6962 disableLoading: hideLoading,
6963 enableButtons: enableButtons,
6964 enableInput: enableInput,
6965 getInput: getInput,
6966 handleAwaitingPromise: handleAwaitingPromise,
6967 hideLoading: hideLoading,
6968 rejectPromise: rejectPromise,
6969 resetValidationMessage: resetValidationMessage,
6970 showValidationMessage: showValidationMessage,
6971 update: update
6972 });
6973
6974 /**
6975 * @param {SweetAlertOptions} innerParams
6976 * @param {DomCache} domCache
6977 * @param {(dismiss: DismissReason) => void} dismissWith
6978 */
6979 const handlePopupClick = (innerParams, domCache, dismissWith) => {
6980 if (innerParams.toast) {
6981 handleToastClick(innerParams, domCache, dismissWith);
6982 } else {
6983 // Ignore click events that had mousedown on the popup but mouseup on the container
6984 // This can happen when the user drags a slider
6985 handleModalMousedown(domCache);
6986
6987 // Ignore click events that had mousedown on the container but mouseup on the popup
6988 handleContainerMousedown(domCache);
6989 handleModalClick(innerParams, domCache, dismissWith);
6990 }
6991 };
6992
6993 /**
6994 * @param {SweetAlertOptions} innerParams
6995 * @param {DomCache} domCache
6996 * @param {(dismiss: DismissReason) => void} dismissWith
6997 */
6998 const handleToastClick = (innerParams, domCache, dismissWith) => {
6999 // Closing toast by internal click
7000 domCache.popup.onclick = () => {
7001 if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
7002 return;
7003 }
7004 dismissWith(DismissReason.close);
7005 };
7006 };
7007
7008 /**
7009 * @param {SweetAlertOptions} innerParams
7010 * @returns {boolean}
7011 */
7012 const isAnyButtonShown = innerParams => {
7013 return Boolean(innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton);
7014 };
7015 let ignoreOutsideClick = false;
7016
7017 /**
7018 * @param {DomCache} domCache
7019 */
7020 const handleModalMousedown = domCache => {
7021 domCache.popup.onmousedown = () => {
7022 domCache.container.onmouseup = function (e) {
7023 domCache.container.onmouseup = () => {};
7024 // We only check if the mouseup target is the container because usually it doesn't
7025 // have any other direct children aside of the popup
7026 if (e.target === domCache.container) {
7027 ignoreOutsideClick = true;
7028 }
7029 };
7030 };
7031 };
7032
7033 /**
7034 * @param {DomCache} domCache
7035 */
7036 const handleContainerMousedown = domCache => {
7037 domCache.container.onmousedown = e => {
7038 // prevent the modal text from being selected on double click on the container (allowOutsideClick: false)
7039 if (e.target === domCache.container) {
7040 e.preventDefault();
7041 }
7042 domCache.popup.onmouseup = function (e) {
7043 domCache.popup.onmouseup = () => {};
7044 // We also need to check if the mouseup target is a child of the popup
7045 if (e.target === domCache.popup || e.target instanceof HTMLElement && domCache.popup.contains(e.target)) {
7046 ignoreOutsideClick = true;
7047 }
7048 };
7049 };
7050 };
7051
7052 /**
7053 * @param {SweetAlertOptions} innerParams
7054 * @param {DomCache} domCache
7055 * @param {(dismiss: DismissReason) => void} dismissWith
7056 */
7057 const handleModalClick = (innerParams, domCache, dismissWith) => {
7058 domCache.container.onclick = e => {
7059 if (ignoreOutsideClick) {
7060 ignoreOutsideClick = false;
7061 return;
7062 }
7063 if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
7064 dismissWith(DismissReason.backdrop);
7065 }
7066 };
7067 };
7068
7069 /**
7070 * @param {any} elem
7071 * @returns {boolean}
7072 */
7073 const isJqueryElement = elem => typeof elem === 'object' && elem.jquery;
7074
7075 /**
7076 * @param {any} elem
7077 * @returns {boolean}
7078 */
7079 const isElement = elem => elem instanceof Element || isJqueryElement(elem);
7080
7081 /**
7082 * @param {any[]} args
7083 * @returns {SweetAlertOptions}
7084 */
7085 const argsToParams = args => {
7086 /** @type {Record<string, any>} */
7087 const params = {};
7088 if (typeof args[0] === 'object' && !isElement(args[0])) {
7089 Object.assign(params, args[0]);
7090 } else {
7091 ['title', 'html', 'icon'].forEach((name, index) => {
7092 const arg = args[index];
7093 if (typeof arg === 'string' || isElement(arg)) {
7094 params[name] = arg;
7095 } else if (arg !== undefined) {
7096 error(`Unexpected type of ${name}! Expected "string" or "Element", got ${typeof arg}`);
7097 }
7098 });
7099 }
7100 return params;
7101 };
7102
7103 /**
7104 * Main method to create a new SweetAlert2 popup
7105 *
7106 * @this {new (...args: any[]) => any}
7107 * @param {...SweetAlertOptions} args
7108 * @returns {Promise<SweetAlertResult>}
7109 */
7110 function fire(...args) {
7111 return new this(...args);
7112 }
7113
7114 /**
7115 * Returns an extended version of `Swal` containing `params` as defaults.
7116 * Useful for reusing Swal configuration.
7117 *
7118 * For example:
7119 *
7120 * Before:
7121 * const textPromptOptions = { input: 'text', showCancelButton: true }
7122 * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
7123 * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
7124 *
7125 * After:
7126 * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
7127 * const {value: firstName} = await TextPrompt('What is your first name?')
7128 * const {value: lastName} = await TextPrompt('What is your last name?')
7129 *
7130 * @param {SweetAlertOptions} mixinParams
7131 * @returns {SweetAlert}
7132 * @this {typeof import('../SweetAlert.js').SweetAlert}
7133 */
7134 function mixin(mixinParams) {
7135 // @ts-ignore: 'this' refers to the SweetAlert constructor
7136 class MixinSwal extends this {
7137 /**
7138 * @param {any} params
7139 * @param {any} priorityMixinParams
7140 */
7141 _main(params, priorityMixinParams) {
7142 return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
7143 }
7144 }
7145 // @ts-ignore
7146 return MixinSwal;
7147 }
7148
7149 /**
7150 * If `timer` parameter is set, returns number of milliseconds of timer remained.
7151 * Otherwise, returns undefined.
7152 *
7153 * @returns {number | undefined}
7154 */
7155 const getTimerLeft = () => {
7156 return globalState.timeout && globalState.timeout.getTimerLeft();
7157 };
7158
7159 /**
7160 * Stop timer. Returns number of milliseconds of timer remained.
7161 * If `timer` parameter isn't set, returns undefined.
7162 *
7163 * @returns {number | undefined}
7164 */
7165 const stopTimer = () => {
7166 if (globalState.timeout) {
7167 stopTimerProgressBar();
7168 return globalState.timeout.stop();
7169 }
7170 };
7171
7172 /**
7173 * Resume timer. Returns number of milliseconds of timer remained.
7174 * If `timer` parameter isn't set, returns undefined.
7175 *
7176 * @returns {number | undefined}
7177 */
7178 const resumeTimer = () => {
7179 if (globalState.timeout) {
7180 const remaining = globalState.timeout.start();
7181 animateTimerProgressBar(remaining);
7182 return remaining;
7183 }
7184 };
7185
7186 /**
7187 * Resume timer. Returns number of milliseconds of timer remained.
7188 * If `timer` parameter isn't set, returns undefined.
7189 *
7190 * @returns {number | undefined}
7191 */
7192 const toggleTimer = () => {
7193 const timer = globalState.timeout;
7194 return timer && (timer.running ? stopTimer() : resumeTimer());
7195 };
7196
7197 /**
7198 * Increase timer. Returns number of milliseconds of an updated timer.
7199 * If `timer` parameter isn't set, returns undefined.
7200 *
7201 * @param {number} ms
7202 * @returns {number | undefined}
7203 */
7204 const increaseTimer = ms => {
7205 if (globalState.timeout) {
7206 const remaining = globalState.timeout.increase(ms);
7207 animateTimerProgressBar(remaining, true);
7208 return remaining;
7209 }
7210 };
7211
7212 /**
7213 * Check if timer is running. Returns true if timer is running
7214 * or false if timer is paused or stopped.
7215 * If `timer` parameter isn't set, returns undefined
7216 *
7217 * @returns {boolean}
7218 */
7219 const isTimerRunning = () => {
7220 return Boolean(globalState.timeout && globalState.timeout.isRunning());
7221 };
7222
7223 let bodyClickListenerAdded = false;
7224 /** @type {Record<string, any>} */
7225 const clickHandlers = {};
7226
7227 /**
7228 * @this {any}
7229 * @param {string} attr
7230 */
7231 function bindClickHandler(attr = 'data-swal-template') {
7232 clickHandlers[attr] = this;
7233 if (!bodyClickListenerAdded) {
7234 document.body.addEventListener('click', bodyClickListener);
7235 bodyClickListenerAdded = true;
7236 }
7237 }
7238
7239 /**
7240 * @param {MouseEvent} event
7241 */
7242 const bodyClickListener = event => {
7243 for (let el = /** @type {any} */event.target; el && el !== document; el = el.parentNode) {
7244 for (const attr in clickHandlers) {
7245 const template = el.getAttribute && el.getAttribute(attr);
7246 if (template) {
7247 clickHandlers[attr].fire({
7248 template
7249 });
7250 return;
7251 }
7252 }
7253 }
7254 };
7255
7256 // Source: https://gist.github.com/mudge/5830382?permalink_comment_id=2691957#gistcomment-2691957
7257
7258 class EventEmitter {
7259 constructor() {
7260 /** @type {Events} */
7261 this.events = {};
7262 }
7263
7264 /**
7265 * @param {string} eventName
7266 * @returns {EventHandlers}
7267 */
7268 _getHandlersByEventName(eventName) {
7269 if (typeof this.events[eventName] === 'undefined') {
7270 // not Set because we need to keep the FIFO order
7271 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1748990334
7272 this.events[eventName] = [];
7273 }
7274 return this.events[eventName];
7275 }
7276
7277 /**
7278 * @param {string} eventName
7279 * @param {EventHandler} eventHandler
7280 */
7281 on(eventName, eventHandler) {
7282 const currentHandlers = this._getHandlersByEventName(eventName);
7283 if (!currentHandlers.includes(eventHandler)) {
7284 currentHandlers.push(eventHandler);
7285 }
7286 }
7287
7288 /**
7289 * @param {string} eventName
7290 * @param {EventHandler} eventHandler
7291 */
7292 once(eventName, eventHandler) {
7293 /**
7294 * @param {...any} args
7295 */
7296 const onceFn = (...args) => {
7297 this.removeListener(eventName, onceFn);
7298 // @ts-ignore
7299 eventHandler.apply(this, args);
7300 };
7301 this.on(eventName, onceFn);
7302 }
7303
7304 /**
7305 * @param {string} eventName
7306 * @param {...any} args
7307 */
7308 emit(eventName, ...args) {
7309 this._getHandlersByEventName(eventName).forEach(
7310 /**
7311 * @param {EventHandler} eventHandler
7312 */
7313 eventHandler => {
7314 try {
7315 // @ts-ignore
7316 eventHandler.apply(this, args);
7317 } catch (error) {
7318 console.error(error);
7319 }
7320 });
7321 }
7322
7323 /**
7324 * @param {string} eventName
7325 * @param {EventHandler} eventHandler
7326 */
7327 removeListener(eventName, eventHandler) {
7328 const currentHandlers = this._getHandlersByEventName(eventName);
7329 const index = currentHandlers.indexOf(eventHandler);
7330 if (index > -1) {
7331 currentHandlers.splice(index, 1);
7332 }
7333 }
7334
7335 /**
7336 * @param {string} eventName
7337 */
7338 removeAllListeners(eventName) {
7339 if (this.events[eventName] !== undefined) {
7340 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1749239222
7341 this.events[eventName].length = 0;
7342 }
7343 }
7344 reset() {
7345 this.events = {};
7346 }
7347 }
7348
7349 globalState.eventEmitter = new EventEmitter();
7350
7351 /**
7352 * @param {string} eventName
7353 * @param {EventHandler} eventHandler
7354 */
7355 const on = (eventName, eventHandler) => {
7356 if (globalState.eventEmitter) {
7357 globalState.eventEmitter.on(eventName, eventHandler);
7358 }
7359 };
7360
7361 /**
7362 * @param {string} eventName
7363 * @param {EventHandler} eventHandler
7364 */
7365 const once = (eventName, eventHandler) => {
7366 if (globalState.eventEmitter) {
7367 globalState.eventEmitter.once(eventName, eventHandler);
7368 }
7369 };
7370
7371 /**
7372 * @param {string} [eventName]
7373 * @param {EventHandler} [eventHandler]
7374 */
7375 const off = (eventName, eventHandler) => {
7376 if (!globalState.eventEmitter) {
7377 return;
7378 }
7379
7380 // Remove all handlers for all events
7381 if (!eventName) {
7382 globalState.eventEmitter.reset();
7383 return;
7384 }
7385 if (eventHandler) {
7386 // Remove a specific handler
7387 globalState.eventEmitter.removeListener(eventName, eventHandler);
7388 } else {
7389 // Remove all handlers for a specific event
7390 globalState.eventEmitter.removeAllListeners(eventName);
7391 }
7392 };
7393
7394 var staticMethods = /*#__PURE__*/Object.freeze({
7395 __proto__: null,
7396 argsToParams: argsToParams,
7397 bindClickHandler: bindClickHandler,
7398 clickCancel: clickCancel,
7399 clickConfirm: clickConfirm,
7400 clickDeny: clickDeny,
7401 enableLoading: showLoading,
7402 fire: fire,
7403 getActions: getActions,
7404 getCancelButton: getCancelButton,
7405 getCloseButton: getCloseButton,
7406 getConfirmButton: getConfirmButton,
7407 getContainer: getContainer,
7408 getDenyButton: getDenyButton,
7409 getFocusableElements: getFocusableElements,
7410 getFooter: getFooter,
7411 getHtmlContainer: getHtmlContainer,
7412 getIcon: getIcon,
7413 getIconContent: getIconContent,
7414 getImage: getImage,
7415 getInputLabel: getInputLabel,
7416 getLoader: getLoader,
7417 getPopup: getPopup,
7418 getProgressSteps: getProgressSteps,
7419 getTimerLeft: getTimerLeft,
7420 getTimerProgressBar: getTimerProgressBar,
7421 getTitle: getTitle,
7422 getValidationMessage: getValidationMessage,
7423 increaseTimer: increaseTimer,
7424 isDeprecatedParameter: isDeprecatedParameter,
7425 isLoading: isLoading,
7426 isTimerRunning: isTimerRunning,
7427 isUpdatableParameter: isUpdatableParameter,
7428 isValidParameter: isValidParameter,
7429 isVisible: isVisible,
7430 mixin: mixin,
7431 off: off,
7432 on: on,
7433 once: once,
7434 resumeTimer: resumeTimer,
7435 showLoading: showLoading,
7436 stopTimer: stopTimer,
7437 toggleTimer: toggleTimer
7438 });
7439
7440 class Timer {
7441 /**
7442 * @param {() => void} callback
7443 * @param {number} delay
7444 */
7445 constructor(callback, delay) {
7446 this.callback = callback;
7447 this.remaining = delay;
7448 this.running = false;
7449 this.start();
7450 }
7451
7452 /**
7453 * @returns {number}
7454 */
7455 start() {
7456 if (!this.running) {
7457 this.running = true;
7458 this.started = new Date();
7459 this.id = setTimeout(this.callback, this.remaining);
7460 }
7461 return this.remaining;
7462 }
7463
7464 /**
7465 * @returns {number}
7466 */
7467 stop() {
7468 if (this.started && this.running) {
7469 this.running = false;
7470 clearTimeout(this.id);
7471 this.remaining -= new Date().getTime() - this.started.getTime();
7472 }
7473 return this.remaining;
7474 }
7475
7476 /**
7477 * @param {number} n
7478 * @returns {number}
7479 */
7480 increase(n) {
7481 const running = this.running;
7482 if (running) {
7483 this.stop();
7484 }
7485 this.remaining += n;
7486 if (running) {
7487 this.start();
7488 }
7489 return this.remaining;
7490 }
7491
7492 /**
7493 * @returns {number}
7494 */
7495 getTimerLeft() {
7496 if (this.running) {
7497 this.stop();
7498 this.start();
7499 }
7500 return this.remaining;
7501 }
7502
7503 /**
7504 * @returns {boolean}
7505 */
7506 isRunning() {
7507 return this.running;
7508 }
7509 }
7510
7511 const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
7512
7513 /**
7514 * @param {SweetAlertOptions} params
7515 * @returns {SweetAlertOptions}
7516 */
7517 const getTemplateParams = params => {
7518 const template = typeof params.template === 'string' ? (/** @type {HTMLTemplateElement} */document.querySelector(params.template)) : params.template;
7519 if (!template) {
7520 return {};
7521 }
7522 /** @type {DocumentFragment} */
7523 const templateContent = template.content;
7524 showWarningsForElements(templateContent);
7525 const result = Object.assign(getSwalParams(templateContent), getSwalFunctionParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
7526 return result;
7527 };
7528
7529 /**
7530 * @param {DocumentFragment} templateContent
7531 * @returns {Record<string, string | boolean | number>}
7532 */
7533 const getSwalParams = templateContent => {
7534 /** @type {Record<string, string | boolean | number>} */
7535 const result = {};
7536 /** @type {HTMLElement[]} */
7537 const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
7538 swalParams.forEach(param => {
7539 showWarningsForAttributes(param, ['name', 'value']);
7540 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7541 const value = param.getAttribute('value');
7542 if (!paramName || !value) {
7543 return;
7544 }
7545 if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'boolean') {
7546 result[paramName] = value !== 'false';
7547 } else if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'object') {
7548 result[paramName] = JSON.parse(value);
7549 } else {
7550 result[paramName] = value;
7551 }
7552 });
7553 return result;
7554 };
7555
7556 /**
7557 * @param {DocumentFragment} templateContent
7558 * @returns {Record<string, () => void>}
7559 */
7560 const getSwalFunctionParams = templateContent => {
7561 /** @type {Record<string, () => void>} */
7562 const result = {};
7563 /** @type {HTMLElement[]} */
7564 const swalFunctions = Array.from(templateContent.querySelectorAll('swal-function-param'));
7565 swalFunctions.forEach(param => {
7566 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7567 const value = param.getAttribute('value');
7568 if (!paramName || !value) {
7569 return;
7570 }
7571 result[paramName] = new Function(`return ${value}`)();
7572 });
7573 return result;
7574 };
7575
7576 /**
7577 * @param {DocumentFragment} templateContent
7578 * @returns {Record<string, string | boolean>}
7579 */
7580 const getSwalButtons = templateContent => {
7581 /** @type {Record<string, string | boolean>} */
7582 const result = {};
7583 /** @type {HTMLElement[]} */
7584 const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
7585 swalButtons.forEach(button => {
7586 showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
7587 const type = button.getAttribute('type');
7588 if (!type || !['confirm', 'cancel', 'deny'].includes(type)) {
7589 return;
7590 }
7591 result[`${type}ButtonText`] = button.innerHTML;
7592 result[`show${capitalizeFirstLetter(type)}Button`] = true;
7593 if (button.hasAttribute('color')) {
7594 const color = button.getAttribute('color');
7595 if (color !== null) {
7596 result[`${type}ButtonColor`] = color;
7597 }
7598 }
7599 if (button.hasAttribute('aria-label')) {
7600 const ariaLabel = button.getAttribute('aria-label');
7601 if (ariaLabel !== null) {
7602 result[`${type}ButtonAriaLabel`] = ariaLabel;
7603 }
7604 }
7605 });
7606 return result;
7607 };
7608
7609 /**
7610 * @param {DocumentFragment} templateContent
7611 * @returns {Pick<SweetAlertOptions, 'imageUrl' | 'imageWidth' | 'imageHeight' | 'imageAlt'>}
7612 */
7613 const getSwalImage = templateContent => {
7614 const result = {};
7615 /** @type {HTMLElement | null} */
7616 const image = templateContent.querySelector('swal-image');
7617 if (image) {
7618 showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
7619 if (image.hasAttribute('src')) {
7620 result.imageUrl = image.getAttribute('src') || undefined;
7621 }
7622 if (image.hasAttribute('width')) {
7623 result.imageWidth = image.getAttribute('width') || undefined;
7624 }
7625 if (image.hasAttribute('height')) {
7626 result.imageHeight = image.getAttribute('height') || undefined;
7627 }
7628 if (image.hasAttribute('alt')) {
7629 result.imageAlt = image.getAttribute('alt') || undefined;
7630 }
7631 }
7632 return result;
7633 };
7634
7635 /**
7636 * @param {DocumentFragment} templateContent
7637 * @returns {object}
7638 */
7639 const getSwalIcon = templateContent => {
7640 const result = {};
7641 /** @type {HTMLElement | null} */
7642 const icon = templateContent.querySelector('swal-icon');
7643 if (icon) {
7644 showWarningsForAttributes(icon, ['type', 'color']);
7645 if (icon.hasAttribute('type')) {
7646 result.icon = icon.getAttribute('type');
7647 }
7648 if (icon.hasAttribute('color')) {
7649 result.iconColor = icon.getAttribute('color');
7650 }
7651 result.iconHtml = icon.innerHTML;
7652 }
7653 return result;
7654 };
7655
7656 /**
7657 * @param {DocumentFragment} templateContent
7658 * @returns {object}
7659 */
7660 const getSwalInput = templateContent => {
7661 /** @type {Record<string, any>} */
7662 const result = {};
7663 /** @type {HTMLElement | null} */
7664 const input = templateContent.querySelector('swal-input');
7665 if (input) {
7666 showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
7667 result.input = input.getAttribute('type') || 'text';
7668 if (input.hasAttribute('label')) {
7669 result.inputLabel = input.getAttribute('label');
7670 }
7671 if (input.hasAttribute('placeholder')) {
7672 result.inputPlaceholder = input.getAttribute('placeholder');
7673 }
7674 if (input.hasAttribute('value')) {
7675 result.inputValue = input.getAttribute('value');
7676 }
7677 }
7678 /** @type {HTMLElement[]} */
7679 const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
7680 if (inputOptions.length) {
7681 result.inputOptions = {};
7682 inputOptions.forEach(option => {
7683 showWarningsForAttributes(option, ['value']);
7684 const optionValue = option.getAttribute('value');
7685 if (!optionValue) {
7686 return;
7687 }
7688 const optionName = option.innerHTML;
7689 result.inputOptions[optionValue] = optionName;
7690 });
7691 }
7692 return result;
7693 };
7694
7695 /**
7696 * @param {DocumentFragment} templateContent
7697 * @param {string[]} paramNames
7698 * @returns {Record<string, string>}
7699 */
7700 const getSwalStringParams = (templateContent, paramNames) => {
7701 /** @type {Record<string, string>} */
7702 const result = {};
7703 for (const i in paramNames) {
7704 const paramName = paramNames[i];
7705 /** @type {HTMLElement | null} */
7706 const tag = templateContent.querySelector(paramName);
7707 if (tag) {
7708 showWarningsForAttributes(tag, []);
7709 result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
7710 }
7711 }
7712 return result;
7713 };
7714
7715 /**
7716 * @param {DocumentFragment} templateContent
7717 */
7718 const showWarningsForElements = templateContent => {
7719 const allowedElements = swalStringParams.concat(['swal-param', 'swal-function-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
7720 Array.from(templateContent.children).forEach(el => {
7721 const tagName = el.tagName.toLowerCase();
7722 if (!allowedElements.includes(tagName)) {
7723 warn(`Unrecognized element <${tagName}>`);
7724 }
7725 });
7726 };
7727
7728 /**
7729 * @param {HTMLElement} el
7730 * @param {string[]} allowedAttributes
7731 */
7732 const showWarningsForAttributes = (el, allowedAttributes) => {
7733 Array.from(el.attributes).forEach(attribute => {
7734 if (allowedAttributes.indexOf(attribute.name) === -1) {
7735 warn([`Unrecognized attribute "${attribute.name}" on <${el.tagName.toLowerCase()}>.`, `${allowedAttributes.length ? `Allowed attributes are: ${allowedAttributes.join(', ')}` : 'To set the value, use HTML within the element.'}`]);
7736 }
7737 });
7738 };
7739
7740 const SHOW_CLASS_TIMEOUT = 10;
7741
7742 /**
7743 * Open popup, add necessary classes and styles, fix scrollbar
7744 *
7745 * @param {SweetAlertOptions} params
7746 */
7747 const openPopup = params => {
7748 var _globalState$eventEmi, _globalState$eventEmi2;
7749 const container = getContainer();
7750 const popup = getPopup();
7751 if (!container || !popup) {
7752 return;
7753 }
7754 if (typeof params.willOpen === 'function') {
7755 params.willOpen(popup);
7756 }
7757 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willOpen', popup);
7758 const bodyStyles = window.getComputedStyle(document.body);
7759 const initialBodyOverflow = bodyStyles.overflowY;
7760 addClasses(container, popup, params);
7761
7762 // scrolling is 'hidden' until animation is done, after that 'auto'
7763 setTimeout(() => {
7764 setScrollingVisibility(container, popup);
7765 }, SHOW_CLASS_TIMEOUT);
7766 if (isModal()) {
7767 // Using ternary instead of ?? operator for Webpack 4 compatibility
7768 fixScrollContainer(container, params.scrollbarPadding !== undefined ? params.scrollbarPadding : false, initialBodyOverflow);
7769 setAriaHidden();
7770 }
7771 if (!isToast() && !globalState.previousActiveElement) {
7772 globalState.previousActiveElement = document.activeElement;
7773 }
7774 if (typeof params.didOpen === 'function') {
7775 const didOpen = params.didOpen;
7776 setTimeout(() => didOpen(popup));
7777 }
7778 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didOpen', popup);
7779 };
7780
7781 /**
7782 * @param {Event} event
7783 */
7784 const swalOpenAnimationFinished = event => {
7785 const popup = getPopup();
7786 if (!popup || event.target !== popup) {
7787 return;
7788 }
7789 const container = getContainer();
7790 if (!container) {
7791 return;
7792 }
7793 popup.removeEventListener('animationend', swalOpenAnimationFinished);
7794 popup.removeEventListener('transitionend', swalOpenAnimationFinished);
7795 container.style.overflowY = 'auto';
7796
7797 // no-transition is added in init() in case one swal is opened right after another
7798 removeClass(container, swalClasses['no-transition']);
7799 };
7800
7801 /**
7802 * @param {HTMLElement} container
7803 * @param {HTMLElement} popup
7804 */
7805 const setScrollingVisibility = (container, popup) => {
7806 if (hasCssAnimation(popup)) {
7807 container.style.overflowY = 'hidden';
7808 popup.addEventListener('animationend', swalOpenAnimationFinished);
7809 popup.addEventListener('transitionend', swalOpenAnimationFinished);
7810 } else {
7811 container.style.overflowY = 'auto';
7812 }
7813 };
7814
7815 /**
7816 * @param {HTMLElement} container
7817 * @param {boolean} scrollbarPadding
7818 * @param {string} initialBodyOverflow
7819 */
7820 const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
7821 iOSfix();
7822 if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
7823 replaceScrollbarWithPadding(initialBodyOverflow);
7824 }
7825
7826 // sweetalert2/issues/1247
7827 setTimeout(() => {
7828 container.scrollTop = 0;
7829 });
7830 };
7831
7832 /**
7833 * @param {HTMLElement} container
7834 * @param {HTMLElement} popup
7835 * @param {SweetAlertOptions} params
7836 */
7837 const addClasses = (container, popup, params) => {
7838 var _params$showClass;
7839 if ((_params$showClass = params.showClass) !== null && _params$showClass !== void 0 && _params$showClass.backdrop) {
7840 addClass(container, params.showClass.backdrop);
7841 }
7842 if (params.animation) {
7843 // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
7844 popup.style.setProperty('opacity', '0', 'important');
7845 show(popup, 'grid');
7846 setTimeout(() => {
7847 var _params$showClass2;
7848 // Animate popup right after showing it
7849 if ((_params$showClass2 = params.showClass) !== null && _params$showClass2 !== void 0 && _params$showClass2.popup) {
7850 addClass(popup, params.showClass.popup);
7851 }
7852 // and remove the opacity workaround
7853 popup.style.removeProperty('opacity');
7854 }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
7855 } else {
7856 show(popup, 'grid');
7857 }
7858 addClass([document.documentElement, document.body], swalClasses.shown);
7859 if (params.heightAuto && params.backdrop && !params.toast) {
7860 addClass([document.documentElement, document.body], swalClasses['height-auto']);
7861 }
7862 };
7863
7864 var defaultInputValidators = {
7865 /**
7866 * @param {string} string
7867 * @param {string} [validationMessage]
7868 * @returns {Promise<string | void>}
7869 */
7870 email: (string, validationMessage) => {
7871 return /^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
7872 },
7873 /**
7874 * @param {string} string
7875 * @param {string} [validationMessage]
7876 * @returns {Promise<string | void>}
7877 */
7878 url: (string, validationMessage) => {
7879 // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
7880 return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid URL');
7881 }
7882 };
7883
7884 /**
7885 * @param {SweetAlertOptions} params
7886 */
7887 function setDefaultInputValidators(params) {
7888 // Use default `inputValidator` for supported input types if not provided
7889 if (params.inputValidator) {
7890 return;
7891 }
7892 if (params.input === 'email') {
7893 params.inputValidator = defaultInputValidators['email'];
7894 }
7895 if (params.input === 'url') {
7896 params.inputValidator = defaultInputValidators['url'];
7897 }
7898 }
7899
7900 /**
7901 * @param {SweetAlertOptions} params
7902 */
7903 function validateCustomTargetElement(params) {
7904 // Determine if the custom target element is valid
7905 if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
7906 warn('Target parameter is not valid, defaulting to "body"');
7907 params.target = 'body';
7908 }
7909 }
7910
7911 /**
7912 * Set type, text and actions on popup
7913 *
7914 * @param {SweetAlertOptions} params
7915 */
7916 function setParameters(params) {
7917 setDefaultInputValidators(params);
7918
7919 // showLoaderOnConfirm && preConfirm
7920 if (params.showLoaderOnConfirm && !params.preConfirm) {
7921 warn('showLoaderOnConfirm is set to true, but preConfirm is not defined.\n' + 'showLoaderOnConfirm should be used together with preConfirm, see usage example:\n' + 'https://sweetalert2.github.io/#ajax-request');
7922 }
7923 validateCustomTargetElement(params);
7924
7925 // Replace newlines with <br> in title
7926 if (typeof params.title === 'string') {
7927 params.title = params.title.split('\n').join('<br />');
7928 }
7929 init(params);
7930 }
7931
7932 /** @type {SweetAlert} */
7933 let currentInstance;
7934 var _promise = /*#__PURE__*/new WeakMap();
7935 class SweetAlert {
7936 /**
7937 * @param {...(SweetAlertOptions | string)} args
7938 * @this {SweetAlert}
7939 */
7940 constructor(...args) {
7941 /**
7942 * @type {Promise<SweetAlertResult>}
7943 */
7944 _classPrivateFieldInitSpec(this, _promise, /** @type {Promise<SweetAlertResult>} */Promise.resolve({
7945 isConfirmed: false,
7946 isDenied: false,
7947 isDismissed: true
7948 }));
7949 // Prevent run in Node env
7950 if (typeof window === 'undefined') {
7951 return;
7952 }
7953 currentInstance = this;
7954
7955 // @ts-ignore
7956 const outerParams = Object.freeze(this.constructor.argsToParams(args));
7957
7958 /** @type {Readonly<SweetAlertOptions>} */
7959 this.params = outerParams;
7960
7961 /** @type {boolean} */
7962 this.isAwaitingPromise = false;
7963 _classPrivateFieldSet2(_promise, this, this._main(currentInstance.params));
7964 }
7965
7966 /**
7967 * @param {any} userParams
7968 * @param {any} mixinParams
7969 */
7970 _main(userParams, mixinParams = {}) {
7971 showWarningsForParams(Object.assign({}, mixinParams, userParams));
7972 if (globalState.currentInstance) {
7973 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance);
7974 const {
7975 isAwaitingPromise
7976 } = globalState.currentInstance;
7977 globalState.currentInstance._destroy();
7978 if (!isAwaitingPromise) {
7979 swalPromiseResolve({
7980 isDismissed: true
7981 });
7982 }
7983 if (isModal()) {
7984 unsetAriaHidden();
7985 }
7986 }
7987 globalState.currentInstance = currentInstance;
7988 const innerParams = prepareParams(userParams, mixinParams);
7989 setParameters(innerParams);
7990 Object.freeze(innerParams);
7991
7992 // clear the previous timer
7993 if (globalState.timeout) {
7994 globalState.timeout.stop();
7995 delete globalState.timeout;
7996 }
7997
7998 // clear the restore focus timeout
7999 clearTimeout(globalState.restoreFocusTimeout);
8000 const domCache = populateDomCache(currentInstance);
8001 render(currentInstance, innerParams);
8002 privateProps.innerParams.set(currentInstance, innerParams);
8003 return swalPromise(currentInstance, domCache, innerParams);
8004 }
8005
8006 // `catch` cannot be the name of a module export, so we define our thenable methods here instead
8007 /**
8008 * @param {any} onFulfilled
8009 */
8010 then(onFulfilled) {
8011 return _classPrivateFieldGet2(_promise, this).then(onFulfilled);
8012 }
8013
8014 /**
8015 * @param {any} onFinally
8016 */
8017 finally(onFinally) {
8018 return _classPrivateFieldGet2(_promise, this).finally(onFinally);
8019 }
8020 }
8021
8022 /**
8023 * @param {SweetAlert} instance
8024 * @param {DomCache} domCache
8025 * @param {SweetAlertOptions} innerParams
8026 * @returns {Promise<SweetAlertResult>}
8027 */
8028 const swalPromise = (instance, domCache, innerParams) => {
8029 return new Promise((resolve, reject) => {
8030 // functions to handle all closings/dismissals
8031 /**
8032 * @param {DismissReason} dismiss
8033 */
8034 const dismissWith = dismiss => {
8035 instance.close({
8036 isDismissed: true,
8037 dismiss,
8038 isConfirmed: false,
8039 isDenied: false
8040 });
8041 };
8042 privateMethods.swalPromiseResolve.set(instance, resolve);
8043 privateMethods.swalPromiseReject.set(instance, reject);
8044 domCache.confirmButton.onclick = () => {
8045 handleConfirmButtonClick(instance);
8046 };
8047 domCache.denyButton.onclick = () => {
8048 handleDenyButtonClick(instance);
8049 };
8050 domCache.cancelButton.onclick = () => {
8051 handleCancelButtonClick(instance, dismissWith);
8052 };
8053 domCache.closeButton.onclick = () => {
8054 dismissWith(DismissReason.close);
8055 };
8056 handlePopupClick(innerParams, domCache, dismissWith);
8057 addKeydownHandler(globalState, innerParams, dismissWith);
8058 handleInputOptionsAndValue(instance, innerParams);
8059 openPopup(innerParams);
8060 setupTimer(globalState, innerParams, dismissWith);
8061 initFocus(domCache, innerParams);
8062
8063 // Scroll container to top on open (#1247, #1946)
8064 setTimeout(() => {
8065 domCache.container.scrollTop = 0;
8066 });
8067 });
8068 };
8069
8070 /**
8071 * @param {SweetAlertOptions} userParams
8072 * @param {SweetAlertOptions} mixinParams
8073 * @returns {SweetAlertOptions}
8074 */
8075 const prepareParams = (userParams, mixinParams) => {
8076 const templateParams = getTemplateParams(userParams);
8077 const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams); // precedence is described in #2131
8078 params.showClass = Object.assign({}, defaultParams.showClass, params.showClass);
8079 params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass);
8080 if (params.animation === false) {
8081 params.showClass = {
8082 backdrop: 'swal2-noanimation'
8083 };
8084 params.hideClass = {};
8085 }
8086 return params;
8087 };
8088
8089 /**
8090 * @param {SweetAlert} instance
8091 * @returns {DomCache}
8092 */
8093 const populateDomCache = instance => {
8094 const domCache = /** @type {DomCache} */{
8095 popup: (/** @type {HTMLElement} */getPopup()),
8096 container: (/** @type {HTMLElement} */getContainer()),
8097 actions: (/** @type {HTMLElement} */getActions()),
8098 confirmButton: (/** @type {HTMLElement} */getConfirmButton()),
8099 denyButton: (/** @type {HTMLElement} */getDenyButton()),
8100 cancelButton: (/** @type {HTMLElement} */getCancelButton()),
8101 loader: (/** @type {HTMLElement} */getLoader()),
8102 closeButton: (/** @type {HTMLElement} */getCloseButton()),
8103 validationMessage: (/** @type {HTMLElement} */getValidationMessage()),
8104 progressSteps: (/** @type {HTMLElement} */getProgressSteps())
8105 };
8106 privateProps.domCache.set(instance, domCache);
8107 return domCache;
8108 };
8109
8110 /**
8111 * @param {GlobalState} globalState
8112 * @param {SweetAlertOptions} innerParams
8113 * @param {(dismiss: DismissReason) => void} dismissWith
8114 */
8115 const setupTimer = (globalState, innerParams, dismissWith) => {
8116 const timerProgressBar = getTimerProgressBar();
8117 hide(timerProgressBar);
8118 if (innerParams.timer) {
8119 globalState.timeout = new Timer(() => {
8120 dismissWith('timer');
8121 delete globalState.timeout;
8122 }, innerParams.timer);
8123 if (innerParams.timerProgressBar && timerProgressBar) {
8124 show(timerProgressBar);
8125 applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar');
8126 setTimeout(() => {
8127 if (globalState.timeout && globalState.timeout.running) {
8128 // timer can be already stopped or unset at this point
8129 animateTimerProgressBar(/** @type {number} */innerParams.timer);
8130 }
8131 });
8132 }
8133 }
8134 };
8135
8136 /**
8137 * Initialize focus in the popup:
8138 *
8139 * 1. If `toast` is `true`, don't steal focus from the document.
8140 * 2. Else if there is an [autofocus] element, focus it.
8141 * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it.
8142 * 4. Else if `focusDeny` is `true` and deny button is visible, focus it.
8143 * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it.
8144 * 6. Else focus the first focusable element in a popup (if any).
8145 *
8146 * @param {DomCache} domCache
8147 * @param {SweetAlertOptions} innerParams
8148 */
8149 const initFocus = (domCache, innerParams) => {
8150 if (innerParams.toast) {
8151 return;
8152 }
8153 // TODO: this is dumb, remove `allowEnterKey` param in the next major version
8154 if (!callIfFunction(innerParams.allowEnterKey)) {
8155 warnAboutDeprecation('allowEnterKey');
8156 blurActiveElement();
8157 return;
8158 }
8159 if (focusAutofocus(domCache)) {
8160 return;
8161 }
8162 if (focusButton(domCache, innerParams)) {
8163 return;
8164 }
8165 setFocus(-1, 1);
8166 };
8167
8168 /**
8169 * @param {DomCache} domCache
8170 * @returns {boolean}
8171 */
8172 const focusAutofocus = domCache => {
8173 const autofocusElements = Array.from(domCache.popup.querySelectorAll('[autofocus]'));
8174 for (const autofocusElement of autofocusElements) {
8175 if (autofocusElement instanceof HTMLElement && isVisible$1(autofocusElement)) {
8176 autofocusElement.focus();
8177 return true;
8178 }
8179 }
8180 return false;
8181 };
8182
8183 /**
8184 * @param {DomCache} domCache
8185 * @param {SweetAlertOptions} innerParams
8186 * @returns {boolean}
8187 */
8188 const focusButton = (domCache, innerParams) => {
8189 if (innerParams.focusDeny && isVisible$1(domCache.denyButton)) {
8190 domCache.denyButton.focus();
8191 return true;
8192 }
8193 if (innerParams.focusCancel && isVisible$1(domCache.cancelButton)) {
8194 domCache.cancelButton.focus();
8195 return true;
8196 }
8197 if (innerParams.focusConfirm && isVisible$1(domCache.confirmButton)) {
8198 domCache.confirmButton.focus();
8199 return true;
8200 }
8201 return false;
8202 };
8203 const blurActiveElement = () => {
8204 if (document.activeElement instanceof HTMLElement && typeof document.activeElement.blur === 'function') {
8205 document.activeElement.blur();
8206 }
8207 };
8208
8209 // Assign instance methods from src/instanceMethods/*.js to prototype
8210 SweetAlert.prototype.disableButtons = disableButtons;
8211 SweetAlert.prototype.enableButtons = enableButtons;
8212 SweetAlert.prototype.getInput = getInput;
8213 SweetAlert.prototype.disableInput = disableInput;
8214 SweetAlert.prototype.enableInput = enableInput;
8215 SweetAlert.prototype.hideLoading = hideLoading;
8216 SweetAlert.prototype.disableLoading = hideLoading;
8217 SweetAlert.prototype.showValidationMessage = showValidationMessage;
8218 SweetAlert.prototype.resetValidationMessage = resetValidationMessage;
8219 SweetAlert.prototype.close = close;
8220 SweetAlert.prototype.closePopup = close;
8221 SweetAlert.prototype.closeModal = close;
8222 SweetAlert.prototype.closeToast = close;
8223 SweetAlert.prototype.rejectPromise = rejectPromise;
8224 SweetAlert.prototype.update = update;
8225 SweetAlert.prototype._destroy = _destroy;
8226
8227 // Assign static methods from src/staticMethods/*.js to constructor
8228 Object.assign(SweetAlert, staticMethods);
8229
8230 // Proxy to instance methods to constructor, for now, for backwards compatibility
8231 Object.keys(instanceMethods).forEach(key => {
8232 /**
8233 * @param {...(SweetAlertOptions | string | undefined)} args
8234 * @returns {SweetAlertResult | Promise<SweetAlertResult> | undefined}
8235 */
8236 // @ts-ignore: Dynamic property assignment for backwards compatibility
8237 SweetAlert[key] = function (...args) {
8238 // @ts-ignore
8239 if (currentInstance && currentInstance[key]) {
8240 // @ts-ignore
8241 return currentInstance[key](...args);
8242 }
8243 return undefined;
8244 };
8245 });
8246 SweetAlert.DismissReason = DismissReason;
8247 SweetAlert.version = '11.26.17';
8248
8249 const Swal = SweetAlert;
8250 // @ts-ignore
8251 Swal.default = Swal;
8252
8253 return Swal;
8254
8255 }));
8256 if (typeof this !== 'undefined' && this.Sweetalert2){this.swal = this.sweetAlert = this.Swal = this.SweetAlert = this.Sweetalert2}
8257 "undefined"!=typeof document&&function(e,t){var n=e.createElement("style");if(e.getElementsByTagName("head")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,":root{--swal2-outline: 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-container-padding: 0.625em;--swal2-backdrop: rgba(0, 0, 0, 0.4);--swal2-backdrop-transition: background-color 0.15s;--swal2-width: 32em;--swal2-padding: 0 0 1.25em;--swal2-border: none;--swal2-border-radius: 0.3125rem;--swal2-background: white;--swal2-color: #545454;--swal2-show-animation: swal2-show 0.3s;--swal2-hide-animation: swal2-hide 0.15s forwards;--swal2-icon-zoom: 1;--swal2-icon-animations: true;--swal2-title-padding: 0.8em 1em 0;--swal2-html-container-padding: 1em 1.6em 0.3em;--swal2-input-border: 1px solid #d9d9d9;--swal2-input-border-radius: 0.1875em;--swal2-input-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-background: transparent;--swal2-input-transition: border-color 0.2s, box-shadow 0.2s;--swal2-input-hover-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-focus-border: 1px solid #b4dbed;--swal2-input-focus-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-progress-step-background: #add8e6;--swal2-validation-message-background: #f0f0f0;--swal2-validation-message-color: #666;--swal2-footer-border-color: #eee;--swal2-footer-background: transparent;--swal2-footer-color: inherit;--swal2-timer-progress-bar-background: rgba(0, 0, 0, 0.3);--swal2-close-button-position: initial;--swal2-close-button-inset: auto;--swal2-close-button-font-size: 2.5em;--swal2-close-button-color: #ccc;--swal2-close-button-transition: color 0.2s, box-shadow 0.2s;--swal2-close-button-outline: initial;--swal2-close-button-box-shadow: inset 0 0 0 3px transparent;--swal2-close-button-focus-box-shadow: inset var(--swal2-outline);--swal2-close-button-hover-transform: none;--swal2-actions-justify-content: center;--swal2-actions-width: auto;--swal2-actions-margin: 1.25em auto 0;--swal2-actions-padding: 0;--swal2-actions-border-radius: 0;--swal2-actions-background: transparent;--swal2-action-button-transition: background-color 0.2s, box-shadow 0.2s;--swal2-action-button-hover: black 10%;--swal2-action-button-active: black 10%;--swal2-confirm-button-box-shadow: none;--swal2-confirm-button-border-radius: 0.25em;--swal2-confirm-button-background-color: #7066e0;--swal2-confirm-button-color: #fff;--swal2-deny-button-box-shadow: none;--swal2-deny-button-border-radius: 0.25em;--swal2-deny-button-background-color: #dc3741;--swal2-deny-button-color: #fff;--swal2-cancel-button-box-shadow: none;--swal2-cancel-button-border-radius: 0.25em;--swal2-cancel-button-background-color: #6e7881;--swal2-cancel-button-color: #fff;--swal2-toast-show-animation: swal2-toast-show 0.5s;--swal2-toast-hide-animation: swal2-toast-hide 0.1s forwards;--swal2-toast-border: none;--swal2-toast-box-shadow: 0 0 1px hsl(0deg 0% 0% / 0.075), 0 1px 2px hsl(0deg 0% 0% / 0.075), 1px 2px 4px hsl(0deg 0% 0% / 0.075), 1px 3px 8px hsl(0deg 0% 0% / 0.075), 2px 4px 16px hsl(0deg 0% 0% / 0.075)}[data-swal2-theme=dark]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}@media(prefers-color-scheme: dark){[data-swal2-theme=auto]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto !important}body.swal2-no-backdrop .swal2-container{background-color:rgba(0,0,0,0) !important;pointer-events:none}body.swal2-no-backdrop .swal2-container .swal2-popup{pointer-events:all}body.swal2-no-backdrop .swal2-container .swal2-modal{box-shadow:0 0 10px var(--swal2-backdrop)}body.swal2-toast-shown .swal2-container{box-sizing:border-box;width:360px;max-width:100%;background-color:rgba(0,0,0,0);pointer-events:none}body.swal2-toast-shown .swal2-container.swal2-top{inset:0 auto auto 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{inset:0 0 auto auto}body.swal2-toast-shown .swal2-container.swal2-top-start,body.swal2-toast-shown .swal2-container.swal2-top-left{inset:0 auto auto 0}body.swal2-toast-shown .swal2-container.swal2-center-start,body.swal2-toast-shown .swal2-container.swal2-center-left{inset:50% auto auto 0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{inset:50% auto auto 50%;transform:translate(-50%, -50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{inset:50% 0 auto auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-start,body.swal2-toast-shown .swal2-container.swal2-bottom-left{inset:auto auto 0 0}body.swal2-toast-shown .swal2-container.swal2-bottom{inset:auto auto 0 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{inset:auto 0 0 auto}@media print{body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow-y:scroll !important}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown) .swal2-container{position:static !important}}div:where(.swal2-container){display:grid;position:fixed;z-index:1060;inset:0;box-sizing:border-box;grid-template-areas:\"top-start top top-end\" \"center-start center center-end\" \"bottom-start bottom-center bottom-end\";grid-template-rows:minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);height:100%;padding:var(--swal2-container-padding);overflow-x:hidden;transition:var(--swal2-backdrop-transition);-webkit-overflow-scrolling:touch}div:where(.swal2-container).swal2-backdrop-show,div:where(.swal2-container).swal2-noanimation{background:var(--swal2-backdrop)}div:where(.swal2-container).swal2-backdrop-hide{background:rgba(0,0,0,0) !important}div:where(.swal2-container).swal2-top-start,div:where(.swal2-container).swal2-center-start,div:where(.swal2-container).swal2-bottom-start{grid-template-columns:minmax(0, 1fr) auto auto}div:where(.swal2-container).swal2-top,div:where(.swal2-container).swal2-center,div:where(.swal2-container).swal2-bottom{grid-template-columns:auto minmax(0, 1fr) auto}div:where(.swal2-container).swal2-top-end,div:where(.swal2-container).swal2-center-end,div:where(.swal2-container).swal2-bottom-end{grid-template-columns:auto auto minmax(0, 1fr)}div:where(.swal2-container).swal2-top-start>.swal2-popup{align-self:start}div:where(.swal2-container).swal2-top>.swal2-popup{grid-column:2;place-self:start center}div:where(.swal2-container).swal2-top-end>.swal2-popup,div:where(.swal2-container).swal2-top-right>.swal2-popup{grid-column:3;place-self:start end}div:where(.swal2-container).swal2-center-start>.swal2-popup,div:where(.swal2-container).swal2-center-left>.swal2-popup{grid-row:2;align-self:center}div:where(.swal2-container).swal2-center>.swal2-popup{grid-column:2;grid-row:2;place-self:center center}div:where(.swal2-container).swal2-center-end>.swal2-popup,div:where(.swal2-container).swal2-center-right>.swal2-popup{grid-column:3;grid-row:2;place-self:center end}div:where(.swal2-container).swal2-bottom-start>.swal2-popup,div:where(.swal2-container).swal2-bottom-left>.swal2-popup{grid-column:1;grid-row:3;align-self:end}div:where(.swal2-container).swal2-bottom>.swal2-popup{grid-column:2;grid-row:3;place-self:end center}div:where(.swal2-container).swal2-bottom-end>.swal2-popup,div:where(.swal2-container).swal2-bottom-right>.swal2-popup{grid-column:3;grid-row:3;place-self:end end}div:where(.swal2-container).swal2-grow-row>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-column:1/4;width:100%}div:where(.swal2-container).swal2-grow-column>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-row:1/4;align-self:stretch}div:where(.swal2-container).swal2-no-transition{transition:none !important}div:where(.swal2-container)[popover]{width:auto;border:0}div:where(.swal2-container) div:where(.swal2-popup){display:none;position:relative;box-sizing:border-box;grid-template-columns:minmax(0, 100%);width:var(--swal2-width);max-width:100%;padding:var(--swal2-padding);border:var(--swal2-border);border-radius:var(--swal2-border-radius);background:var(--swal2-background);color:var(--swal2-color);font-family:inherit;font-size:1rem;container-name:swal2-popup}div:where(.swal2-container) div:where(.swal2-popup):focus{outline:none}div:where(.swal2-container) div:where(.swal2-popup).swal2-loading{overflow-y:hidden}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable{cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable div:where(.swal2-icon){cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging{cursor:grabbing}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging div:where(.swal2-icon){cursor:grabbing}div:where(.swal2-container) h2:where(.swal2-title){position:relative;max-width:100%;margin:0;padding:var(--swal2-title-padding);color:inherit;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;overflow-wrap:break-word;cursor:initial}div:where(.swal2-container) div:where(.swal2-actions){display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:var(--swal2-actions-justify-content);width:var(--swal2-actions-width);margin:var(--swal2-actions-margin);padding:var(--swal2-actions-padding);border-radius:var(--swal2-actions-border-radius);background:var(--swal2-actions-background)}div:where(.swal2-container) div:where(.swal2-loader){display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 rgba(0,0,0,0) #2778c4 rgba(0,0,0,0)}div:where(.swal2-container) button:where(.swal2-styled){margin:.3125em;padding:.625em 1.1em;transition:var(--swal2-action-button-transition);border:none;box-shadow:0 0 0 3px rgba(0,0,0,0);font-weight:500}div:where(.swal2-container) button:where(.swal2-styled):not([disabled]){cursor:pointer}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm){border-radius:var(--swal2-confirm-button-border-radius);background:initial;background-color:var(--swal2-confirm-button-background-color);box-shadow:var(--swal2-confirm-button-box-shadow);color:var(--swal2-confirm-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):hover{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):active{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny){border-radius:var(--swal2-deny-button-border-radius);background:initial;background-color:var(--swal2-deny-button-background-color);box-shadow:var(--swal2-deny-button-box-shadow);color:var(--swal2-deny-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):hover{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):active{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel){border-radius:var(--swal2-cancel-button-border-radius);background:initial;background-color:var(--swal2-cancel-button-background-color);box-shadow:var(--swal2-cancel-button-box-shadow);color:var(--swal2-cancel-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):hover{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):active{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):focus-visible{outline:none;box-shadow:var(--swal2-action-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-styled)[disabled]:not(.swal2-loading){opacity:.4}div:where(.swal2-container) button:where(.swal2-styled)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-footer){margin:1em 0 0;padding:1em 1em 0;border-top:1px solid var(--swal2-footer-border-color);background:var(--swal2-footer-background);color:var(--swal2-footer-color);font-size:1em;text-align:center;cursor:initial}div:where(.swal2-container) .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto !important;overflow:hidden;border-bottom-right-radius:var(--swal2-border-radius);border-bottom-left-radius:var(--swal2-border-radius)}div:where(.swal2-container) div:where(.swal2-timer-progress-bar){width:100%;height:.25em;background:var(--swal2-timer-progress-bar-background)}div:where(.swal2-container) img:where(.swal2-image){max-width:100%;margin:2em auto 1em;cursor:initial}div:where(.swal2-container) button:where(.swal2-close){position:var(--swal2-close-button-position);inset:var(--swal2-close-button-inset);z-index:2;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-top:0;margin-right:0;margin-bottom:-1.2em;padding:0;overflow:hidden;transition:var(--swal2-close-button-transition);border:none;border-radius:var(--swal2-border-radius);outline:var(--swal2-close-button-outline);background:rgba(0,0,0,0);color:var(--swal2-close-button-color);font-family:monospace;font-size:var(--swal2-close-button-font-size);cursor:pointer;justify-self:end}div:where(.swal2-container) button:where(.swal2-close):hover{transform:var(--swal2-close-button-hover-transform);background:rgba(0,0,0,0);color:#f27474}div:where(.swal2-container) button:where(.swal2-close):focus-visible{outline:none;box-shadow:var(--swal2-close-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-close)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-html-container){z-index:1;justify-content:center;margin:0;padding:var(--swal2-html-container-padding);overflow:auto;color:inherit;font-size:1.125em;font-weight:normal;line-height:normal;text-align:center;overflow-wrap:break-word;word-break:break-word;cursor:initial}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea),div:where(.swal2-container) select:where(.swal2-select),div:where(.swal2-container) div:where(.swal2-radio),div:where(.swal2-container) label:where(.swal2-checkbox){margin:1em 2em 3px}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea){box-sizing:border-box;width:auto;transition:var(--swal2-input-transition);border:var(--swal2-input-border);border-radius:var(--swal2-input-border-radius);background:var(--swal2-input-background);box-shadow:var(--swal2-input-box-shadow);color:inherit;font-size:1.125em}div:where(.swal2-container) input:where(.swal2-input).swal2-inputerror,div:where(.swal2-container) input:where(.swal2-file).swal2-inputerror,div:where(.swal2-container) textarea:where(.swal2-textarea).swal2-inputerror{border-color:#f27474 !important;box-shadow:0 0 2px #f27474 !important}div:where(.swal2-container) input:where(.swal2-input):hover,div:where(.swal2-container) input:where(.swal2-file):hover,div:where(.swal2-container) textarea:where(.swal2-textarea):hover{box-shadow:var(--swal2-input-hover-box-shadow)}div:where(.swal2-container) input:where(.swal2-input):focus,div:where(.swal2-container) input:where(.swal2-file):focus,div:where(.swal2-container) textarea:where(.swal2-textarea):focus{border:var(--swal2-input-focus-border);outline:none;box-shadow:var(--swal2-input-focus-box-shadow)}div:where(.swal2-container) input:where(.swal2-input)::placeholder,div:where(.swal2-container) input:where(.swal2-file)::placeholder,div:where(.swal2-container) textarea:where(.swal2-textarea)::placeholder{color:#ccc}div:where(.swal2-container) .swal2-range{margin:1em 2em 3px;background:var(--swal2-background)}div:where(.swal2-container) .swal2-range input{width:80%}div:where(.swal2-container) .swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}div:where(.swal2-container) .swal2-range input,div:where(.swal2-container) .swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}div:where(.swal2-container) .swal2-input{height:2.625em;padding:0 .75em}div:where(.swal2-container) .swal2-file{width:75%;margin-right:auto;margin-left:auto;background:var(--swal2-input-background);font-size:1.125em}div:where(.swal2-container) .swal2-textarea{height:6.75em;padding:.75em}div:where(.swal2-container) .swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:var(--swal2-input-background);color:inherit;font-size:1.125em}div:where(.swal2-container) .swal2-radio,div:where(.swal2-container) .swal2-checkbox{align-items:center;justify-content:center;background:var(--swal2-background);color:inherit}div:where(.swal2-container) .swal2-radio label,div:where(.swal2-container) .swal2-checkbox label{margin:0 .6em;font-size:1.125em}div:where(.swal2-container) .swal2-radio input,div:where(.swal2-container) .swal2-checkbox input{flex-shrink:0;margin:0 .4em}div:where(.swal2-container) label:where(.swal2-input-label){display:flex;justify-content:center;margin:1em auto 0}div:where(.swal2-container) div:where(.swal2-validation-message){align-items:center;justify-content:center;margin:1em 0 0;padding:.625em;overflow:hidden;background:var(--swal2-validation-message-background);color:var(--swal2-validation-message-color);font-size:1em;font-weight:300}div:where(.swal2-container) div:where(.swal2-validation-message)::before{content:\"!\";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}div:where(.swal2-container) .swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:1.25em auto;padding:0;background:rgba(0,0,0,0);font-weight:600}div:where(.swal2-container) .swal2-progress-steps li{display:inline-block;position:relative}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:var(--swal2-progress-step-background);color:#fff}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:var(--swal2-progress-step-background)}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}div:where(.swal2-icon){position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:2.5em auto .6em;zoom:var(--swal2-icon-zoom);border:.25em solid rgba(0,0,0,0);border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;user-select:none}div:where(.swal2-icon) .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}div:where(.swal2-icon).swal2-error{border-color:#f27474;color:#f27474}div:where(.swal2-icon).swal2-error .swal2-x-mark{position:relative;flex-grow:1}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-error.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-error.swal2-icon-show .swal2-x-mark{animation:swal2-animate-error-x-mark .5s}}div:where(.swal2-icon).swal2-warning{border-color:#f8bb86;color:#f8bb86}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-warning.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-warning.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .5s}}div:where(.swal2-icon).swal2-info{border-color:#3fc3ee;color:#3fc3ee}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-info.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-info.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .8s}}div:where(.swal2-icon).swal2-question{border-color:#87adbd;color:#87adbd}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-question.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-question.swal2-icon-show .swal2-icon-content{animation:swal2-animate-question-mark .8s}}div:where(.swal2-icon).swal2-success{border-color:#a5dc86;color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;border-radius:50%}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}div:where(.swal2-icon).swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-0.25em;left:-0.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}div:where(.swal2-icon).swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-animate-success-line-tip .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-animate-success-line-long .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-circular-line-right{animation:swal2-rotate-success-circular-line 4.25s ease-in}}[class^=swal2]{-webkit-tap-highlight-color:rgba(0,0,0,0)}.swal2-show{animation:var(--swal2-show-animation)}.swal2-hide{animation:var(--swal2-hide-animation)}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{margin-right:initial;margin-left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}.swal2-toast{box-sizing:border-box;grid-column:1/4 !important;grid-row:1/4 !important;grid-template-columns:min-content auto min-content;padding:1em;overflow-y:hidden;border:var(--swal2-toast-border);background:var(--swal2-background);box-shadow:var(--swal2-toast-box-shadow);pointer-events:all}.swal2-toast>*{grid-column:2}.swal2-toast h2:where(.swal2-title){margin:.5em 1em;padding:0;font-size:1em;text-align:initial}.swal2-toast .swal2-loading{justify-content:center}.swal2-toast input:where(.swal2-input){height:2em;margin:.5em;font-size:1em}.swal2-toast .swal2-validation-message{font-size:1em}.swal2-toast div:where(.swal2-footer){margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-toast button:where(.swal2-close){grid-column:3/3;grid-row:1/99;align-self:center;width:.8em;height:.8em;margin:0;font-size:2em}.swal2-toast div:where(.swal2-html-container){margin:.5em 1em;padding:0;overflow:initial;font-size:1em;text-align:initial}.swal2-toast div:where(.swal2-html-container):empty{padding:0}.swal2-toast .swal2-loader{grid-column:1;grid-row:1/99;align-self:center;width:2em;height:2em;margin:.25em}.swal2-toast .swal2-icon{grid-column:1;grid-row:1/99;align-self:center;width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:bold}.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-toast div:where(.swal2-actions){justify-content:flex-start;height:auto;margin:0;margin-top:.5em;padding:0 .5em}.swal2-toast button:where(.swal2-styled){margin:.25em .5em;padding:.4em .6em;font-size:1em}.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;border-radius:50%}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.8em;left:-0.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}@container swal2-popup style(--swal2-icon-animations:true){.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-toast-animate-success-line-tip .75s}.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-toast-animate-success-line-long .75s}}.swal2-toast.swal2-show{animation:var(--swal2-toast-show-animation)}.swal2-toast.swal2-hide{animation:var(--swal2-toast-hide-animation)}@keyframes swal2-show{0%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}100%{transform:translate3d(0, 0, 0) scale(1);opacity:1}}@keyframes swal2-hide{0%{transform:translate3d(0, 0, 0) scale(1);opacity:1}100%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-0.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(0.4);opacity:0}50%{margin-top:1.625em;transform:scale(0.4);opacity:0}80%{margin-top:-0.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);opacity:1}}@keyframes swal2-rotate-loading{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes swal2-animate-question-mark{0%{transform:rotateY(-360deg)}100%{transform:rotateY(0)}}@keyframes swal2-animate-i-mark{0%{transform:rotateZ(45deg);opacity:0}25%{transform:rotateZ(-25deg);opacity:.4}50%{transform:rotateZ(15deg);opacity:.8}75%{transform:rotateZ(-5deg);opacity:1}100%{transform:rotateX(0);opacity:1}}@keyframes swal2-toast-show{0%{transform:translateY(-0.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(0.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0deg)}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-0.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}");
8258
8259 /***/ },
8260
8261 /***/ "./node_modules/@kurkle/color/dist/color.esm.js"
8262 /*!******************************************************!*\
8263 !*** ./node_modules/@kurkle/color/dist/color.esm.js ***!
8264 \******************************************************/
8265 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8266
8267 "use strict";
8268 __webpack_require__.r(__webpack_exports__);
8269 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8270 /* harmony export */ Color: () => (/* binding */ Color),
8271 /* harmony export */ b2n: () => (/* binding */ b2n),
8272 /* harmony export */ b2p: () => (/* binding */ b2p),
8273 /* harmony export */ "default": () => (/* binding */ index_esm),
8274 /* harmony export */ hexParse: () => (/* binding */ hexParse),
8275 /* harmony export */ hexString: () => (/* binding */ hexString),
8276 /* harmony export */ hsl2rgb: () => (/* binding */ hsl2rgb),
8277 /* harmony export */ hslString: () => (/* binding */ hslString),
8278 /* harmony export */ hsv2rgb: () => (/* binding */ hsv2rgb),
8279 /* harmony export */ hueParse: () => (/* binding */ hueParse),
8280 /* harmony export */ hwb2rgb: () => (/* binding */ hwb2rgb),
8281 /* harmony export */ lim: () => (/* binding */ lim),
8282 /* harmony export */ n2b: () => (/* binding */ n2b),
8283 /* harmony export */ n2p: () => (/* binding */ n2p),
8284 /* harmony export */ nameParse: () => (/* binding */ nameParse),
8285 /* harmony export */ p2b: () => (/* binding */ p2b),
8286 /* harmony export */ rgb2hsl: () => (/* binding */ rgb2hsl),
8287 /* harmony export */ rgbParse: () => (/* binding */ rgbParse),
8288 /* harmony export */ rgbString: () => (/* binding */ rgbString),
8289 /* harmony export */ rotate: () => (/* binding */ rotate),
8290 /* harmony export */ round: () => (/* binding */ round)
8291 /* harmony export */ });
8292 /*!
8293 * @kurkle/color v0.3.4
8294 * https://github.com/kurkle/color#readme
8295 * (c) 2024 Jukka Kurkela
8296 * Released under the MIT License
8297 */
8298 function round(v) {
8299 return v + 0.5 | 0;
8300 }
8301 const lim = (v, l, h) => Math.max(Math.min(v, h), l);
8302 function p2b(v) {
8303 return lim(round(v * 2.55), 0, 255);
8304 }
8305 function b2p(v) {
8306 return lim(round(v / 2.55), 0, 100);
8307 }
8308 function n2b(v) {
8309 return lim(round(v * 255), 0, 255);
8310 }
8311 function b2n(v) {
8312 return lim(round(v / 2.55) / 100, 0, 1);
8313 }
8314 function n2p(v) {
8315 return lim(round(v * 100), 0, 100);
8316 }
8317
8318 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};
8319 const hex = [...'0123456789ABCDEF'];
8320 const h1 = b => hex[b & 0xF];
8321 const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF];
8322 const eq = b => ((b & 0xF0) >> 4) === (b & 0xF);
8323 const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);
8324 function hexParse(str) {
8325 var len = str.length;
8326 var ret;
8327 if (str[0] === '#') {
8328 if (len === 4 || len === 5) {
8329 ret = {
8330 r: 255 & map$1[str[1]] * 17,
8331 g: 255 & map$1[str[2]] * 17,
8332 b: 255 & map$1[str[3]] * 17,
8333 a: len === 5 ? map$1[str[4]] * 17 : 255
8334 };
8335 } else if (len === 7 || len === 9) {
8336 ret = {
8337 r: map$1[str[1]] << 4 | map$1[str[2]],
8338 g: map$1[str[3]] << 4 | map$1[str[4]],
8339 b: map$1[str[5]] << 4 | map$1[str[6]],
8340 a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255
8341 };
8342 }
8343 }
8344 return ret;
8345 }
8346 const alpha = (a, f) => a < 255 ? f(a) : '';
8347 function hexString(v) {
8348 var f = isShort(v) ? h1 : h2;
8349 return v
8350 ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f)
8351 : undefined;
8352 }
8353
8354 const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
8355 function hsl2rgbn(h, s, l) {
8356 const a = s * Math.min(l, 1 - l);
8357 const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
8358 return [f(0), f(8), f(4)];
8359 }
8360 function hsv2rgbn(h, s, v) {
8361 const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
8362 return [f(5), f(3), f(1)];
8363 }
8364 function hwb2rgbn(h, w, b) {
8365 const rgb = hsl2rgbn(h, 1, 0.5);
8366 let i;
8367 if (w + b > 1) {
8368 i = 1 / (w + b);
8369 w *= i;
8370 b *= i;
8371 }
8372 for (i = 0; i < 3; i++) {
8373 rgb[i] *= 1 - w - b;
8374 rgb[i] += w;
8375 }
8376 return rgb;
8377 }
8378 function hueValue(r, g, b, d, max) {
8379 if (r === max) {
8380 return ((g - b) / d) + (g < b ? 6 : 0);
8381 }
8382 if (g === max) {
8383 return (b - r) / d + 2;
8384 }
8385 return (r - g) / d + 4;
8386 }
8387 function rgb2hsl(v) {
8388 const range = 255;
8389 const r = v.r / range;
8390 const g = v.g / range;
8391 const b = v.b / range;
8392 const max = Math.max(r, g, b);
8393 const min = Math.min(r, g, b);
8394 const l = (max + min) / 2;
8395 let h, s, d;
8396 if (max !== min) {
8397 d = max - min;
8398 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
8399 h = hueValue(r, g, b, d, max);
8400 h = h * 60 + 0.5;
8401 }
8402 return [h | 0, s || 0, l];
8403 }
8404 function calln(f, a, b, c) {
8405 return (
8406 Array.isArray(a)
8407 ? f(a[0], a[1], a[2])
8408 : f(a, b, c)
8409 ).map(n2b);
8410 }
8411 function hsl2rgb(h, s, l) {
8412 return calln(hsl2rgbn, h, s, l);
8413 }
8414 function hwb2rgb(h, w, b) {
8415 return calln(hwb2rgbn, h, w, b);
8416 }
8417 function hsv2rgb(h, s, v) {
8418 return calln(hsv2rgbn, h, s, v);
8419 }
8420 function hue(h) {
8421 return (h % 360 + 360) % 360;
8422 }
8423 function hueParse(str) {
8424 const m = HUE_RE.exec(str);
8425 let a = 255;
8426 let v;
8427 if (!m) {
8428 return;
8429 }
8430 if (m[5] !== v) {
8431 a = m[6] ? p2b(+m[5]) : n2b(+m[5]);
8432 }
8433 const h = hue(+m[2]);
8434 const p1 = +m[3] / 100;
8435 const p2 = +m[4] / 100;
8436 if (m[1] === 'hwb') {
8437 v = hwb2rgb(h, p1, p2);
8438 } else if (m[1] === 'hsv') {
8439 v = hsv2rgb(h, p1, p2);
8440 } else {
8441 v = hsl2rgb(h, p1, p2);
8442 }
8443 return {
8444 r: v[0],
8445 g: v[1],
8446 b: v[2],
8447 a: a
8448 };
8449 }
8450 function rotate(v, deg) {
8451 var h = rgb2hsl(v);
8452 h[0] = hue(h[0] + deg);
8453 h = hsl2rgb(h);
8454 v.r = h[0];
8455 v.g = h[1];
8456 v.b = h[2];
8457 }
8458 function hslString(v) {
8459 if (!v) {
8460 return;
8461 }
8462 const a = rgb2hsl(v);
8463 const h = a[0];
8464 const s = n2p(a[1]);
8465 const l = n2p(a[2]);
8466 return v.a < 255
8467 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`
8468 : `hsl(${h}, ${s}%, ${l}%)`;
8469 }
8470
8471 const map = {
8472 x: 'dark',
8473 Z: 'light',
8474 Y: 're',
8475 X: 'blu',
8476 W: 'gr',
8477 V: 'medium',
8478 U: 'slate',
8479 A: 'ee',
8480 T: 'ol',
8481 S: 'or',
8482 B: 'ra',
8483 C: 'lateg',
8484 D: 'ights',
8485 R: 'in',
8486 Q: 'turquois',
8487 E: 'hi',
8488 P: 'ro',
8489 O: 'al',
8490 N: 'le',
8491 M: 'de',
8492 L: 'yello',
8493 F: 'en',
8494 K: 'ch',
8495 G: 'arks',
8496 H: 'ea',
8497 I: 'ightg',
8498 J: 'wh'
8499 };
8500 const names$1 = {
8501 OiceXe: 'f0f8ff',
8502 antiquewEte: 'faebd7',
8503 aqua: 'ffff',
8504 aquamarRe: '7fffd4',
8505 azuY: 'f0ffff',
8506 beige: 'f5f5dc',
8507 bisque: 'ffe4c4',
8508 black: '0',
8509 blanKedOmond: 'ffebcd',
8510 Xe: 'ff',
8511 XeviTet: '8a2be2',
8512 bPwn: 'a52a2a',
8513 burlywood: 'deb887',
8514 caMtXe: '5f9ea0',
8515 KartYuse: '7fff00',
8516 KocTate: 'd2691e',
8517 cSO: 'ff7f50',
8518 cSnflowerXe: '6495ed',
8519 cSnsilk: 'fff8dc',
8520 crimson: 'dc143c',
8521 cyan: 'ffff',
8522 xXe: '8b',
8523 xcyan: '8b8b',
8524 xgTMnPd: 'b8860b',
8525 xWay: 'a9a9a9',
8526 xgYF: '6400',
8527 xgYy: 'a9a9a9',
8528 xkhaki: 'bdb76b',
8529 xmagFta: '8b008b',
8530 xTivegYF: '556b2f',
8531 xSange: 'ff8c00',
8532 xScEd: '9932cc',
8533 xYd: '8b0000',
8534 xsOmon: 'e9967a',
8535 xsHgYF: '8fbc8f',
8536 xUXe: '483d8b',
8537 xUWay: '2f4f4f',
8538 xUgYy: '2f4f4f',
8539 xQe: 'ced1',
8540 xviTet: '9400d3',
8541 dAppRk: 'ff1493',
8542 dApskyXe: 'bfff',
8543 dimWay: '696969',
8544 dimgYy: '696969',
8545 dodgerXe: '1e90ff',
8546 fiYbrick: 'b22222',
8547 flSOwEte: 'fffaf0',
8548 foYstWAn: '228b22',
8549 fuKsia: 'ff00ff',
8550 gaRsbSo: 'dcdcdc',
8551 ghostwEte: 'f8f8ff',
8552 gTd: 'ffd700',
8553 gTMnPd: 'daa520',
8554 Way: '808080',
8555 gYF: '8000',
8556 gYFLw: 'adff2f',
8557 gYy: '808080',
8558 honeyMw: 'f0fff0',
8559 hotpRk: 'ff69b4',
8560 RdianYd: 'cd5c5c',
8561 Rdigo: '4b0082',
8562 ivSy: 'fffff0',
8563 khaki: 'f0e68c',
8564 lavFMr: 'e6e6fa',
8565 lavFMrXsh: 'fff0f5',
8566 lawngYF: '7cfc00',
8567 NmoncEffon: 'fffacd',
8568 ZXe: 'add8e6',
8569 ZcSO: 'f08080',
8570 Zcyan: 'e0ffff',
8571 ZgTMnPdLw: 'fafad2',
8572 ZWay: 'd3d3d3',
8573 ZgYF: '90ee90',
8574 ZgYy: 'd3d3d3',
8575 ZpRk: 'ffb6c1',
8576 ZsOmon: 'ffa07a',
8577 ZsHgYF: '20b2aa',
8578 ZskyXe: '87cefa',
8579 ZUWay: '778899',
8580 ZUgYy: '778899',
8581 ZstAlXe: 'b0c4de',
8582 ZLw: 'ffffe0',
8583 lime: 'ff00',
8584 limegYF: '32cd32',
8585 lRF: 'faf0e6',
8586 magFta: 'ff00ff',
8587 maPon: '800000',
8588 VaquamarRe: '66cdaa',
8589 VXe: 'cd',
8590 VScEd: 'ba55d3',
8591 VpurpN: '9370db',
8592 VsHgYF: '3cb371',
8593 VUXe: '7b68ee',
8594 VsprRggYF: 'fa9a',
8595 VQe: '48d1cc',
8596 VviTetYd: 'c71585',
8597 midnightXe: '191970',
8598 mRtcYam: 'f5fffa',
8599 mistyPse: 'ffe4e1',
8600 moccasR: 'ffe4b5',
8601 navajowEte: 'ffdead',
8602 navy: '80',
8603 Tdlace: 'fdf5e6',
8604 Tive: '808000',
8605 TivedBb: '6b8e23',
8606 Sange: 'ffa500',
8607 SangeYd: 'ff4500',
8608 ScEd: 'da70d6',
8609 pOegTMnPd: 'eee8aa',
8610 pOegYF: '98fb98',
8611 pOeQe: 'afeeee',
8612 pOeviTetYd: 'db7093',
8613 papayawEp: 'ffefd5',
8614 pHKpuff: 'ffdab9',
8615 peru: 'cd853f',
8616 pRk: 'ffc0cb',
8617 plum: 'dda0dd',
8618 powMrXe: 'b0e0e6',
8619 purpN: '800080',
8620 YbeccapurpN: '663399',
8621 Yd: 'ff0000',
8622 Psybrown: 'bc8f8f',
8623 PyOXe: '4169e1',
8624 saddNbPwn: '8b4513',
8625 sOmon: 'fa8072',
8626 sandybPwn: 'f4a460',
8627 sHgYF: '2e8b57',
8628 sHshell: 'fff5ee',
8629 siFna: 'a0522d',
8630 silver: 'c0c0c0',
8631 skyXe: '87ceeb',
8632 UXe: '6a5acd',
8633 UWay: '708090',
8634 UgYy: '708090',
8635 snow: 'fffafa',
8636 sprRggYF: 'ff7f',
8637 stAlXe: '4682b4',
8638 tan: 'd2b48c',
8639 teO: '8080',
8640 tEstN: 'd8bfd8',
8641 tomato: 'ff6347',
8642 Qe: '40e0d0',
8643 viTet: 'ee82ee',
8644 JHt: 'f5deb3',
8645 wEte: 'ffffff',
8646 wEtesmoke: 'f5f5f5',
8647 Lw: 'ffff00',
8648 LwgYF: '9acd32'
8649 };
8650 function unpack() {
8651 const unpacked = {};
8652 const keys = Object.keys(names$1);
8653 const tkeys = Object.keys(map);
8654 let i, j, k, ok, nk;
8655 for (i = 0; i < keys.length; i++) {
8656 ok = nk = keys[i];
8657 for (j = 0; j < tkeys.length; j++) {
8658 k = tkeys[j];
8659 nk = nk.replace(k, map[k]);
8660 }
8661 k = parseInt(names$1[ok], 16);
8662 unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];
8663 }
8664 return unpacked;
8665 }
8666
8667 let names;
8668 function nameParse(str) {
8669 if (!names) {
8670 names = unpack();
8671 names.transparent = [0, 0, 0, 0];
8672 }
8673 const a = names[str.toLowerCase()];
8674 return a && {
8675 r: a[0],
8676 g: a[1],
8677 b: a[2],
8678 a: a.length === 4 ? a[3] : 255
8679 };
8680 }
8681
8682 const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
8683 function rgbParse(str) {
8684 const m = RGB_RE.exec(str);
8685 let a = 255;
8686 let r, g, b;
8687 if (!m) {
8688 return;
8689 }
8690 if (m[7] !== r) {
8691 const v = +m[7];
8692 a = m[8] ? p2b(v) : lim(v * 255, 0, 255);
8693 }
8694 r = +m[1];
8695 g = +m[3];
8696 b = +m[5];
8697 r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255));
8698 g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255));
8699 b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255));
8700 return {
8701 r: r,
8702 g: g,
8703 b: b,
8704 a: a
8705 };
8706 }
8707 function rgbString(v) {
8708 return v && (
8709 v.a < 255
8710 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`
8711 : `rgb(${v.r}, ${v.g}, ${v.b})`
8712 );
8713 }
8714
8715 const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055;
8716 const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
8717 function interpolate(rgb1, rgb2, t) {
8718 const r = from(b2n(rgb1.r));
8719 const g = from(b2n(rgb1.g));
8720 const b = from(b2n(rgb1.b));
8721 return {
8722 r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))),
8723 g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))),
8724 b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))),
8725 a: rgb1.a + t * (rgb2.a - rgb1.a)
8726 };
8727 }
8728
8729 function modHSL(v, i, ratio) {
8730 if (v) {
8731 let tmp = rgb2hsl(v);
8732 tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));
8733 tmp = hsl2rgb(tmp);
8734 v.r = tmp[0];
8735 v.g = tmp[1];
8736 v.b = tmp[2];
8737 }
8738 }
8739 function clone(v, proto) {
8740 return v ? Object.assign(proto || {}, v) : v;
8741 }
8742 function fromObject(input) {
8743 var v = {r: 0, g: 0, b: 0, a: 255};
8744 if (Array.isArray(input)) {
8745 if (input.length >= 3) {
8746 v = {r: input[0], g: input[1], b: input[2], a: 255};
8747 if (input.length > 3) {
8748 v.a = n2b(input[3]);
8749 }
8750 }
8751 } else {
8752 v = clone(input, {r: 0, g: 0, b: 0, a: 1});
8753 v.a = n2b(v.a);
8754 }
8755 return v;
8756 }
8757 function functionParse(str) {
8758 if (str.charAt(0) === 'r') {
8759 return rgbParse(str);
8760 }
8761 return hueParse(str);
8762 }
8763 class Color {
8764 constructor(input) {
8765 if (input instanceof Color) {
8766 return input;
8767 }
8768 const type = typeof input;
8769 let v;
8770 if (type === 'object') {
8771 v = fromObject(input);
8772 } else if (type === 'string') {
8773 v = hexParse(input) || nameParse(input) || functionParse(input);
8774 }
8775 this._rgb = v;
8776 this._valid = !!v;
8777 }
8778 get valid() {
8779 return this._valid;
8780 }
8781 get rgb() {
8782 var v = clone(this._rgb);
8783 if (v) {
8784 v.a = b2n(v.a);
8785 }
8786 return v;
8787 }
8788 set rgb(obj) {
8789 this._rgb = fromObject(obj);
8790 }
8791 rgbString() {
8792 return this._valid ? rgbString(this._rgb) : undefined;
8793 }
8794 hexString() {
8795 return this._valid ? hexString(this._rgb) : undefined;
8796 }
8797 hslString() {
8798 return this._valid ? hslString(this._rgb) : undefined;
8799 }
8800 mix(color, weight) {
8801 if (color) {
8802 const c1 = this.rgb;
8803 const c2 = color.rgb;
8804 let w2;
8805 const p = weight === w2 ? 0.5 : weight;
8806 const w = 2 * p - 1;
8807 const a = c1.a - c2.a;
8808 const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
8809 w2 = 1 - w1;
8810 c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;
8811 c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;
8812 c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;
8813 c1.a = p * c1.a + (1 - p) * c2.a;
8814 this.rgb = c1;
8815 }
8816 return this;
8817 }
8818 interpolate(color, t) {
8819 if (color) {
8820 this._rgb = interpolate(this._rgb, color._rgb, t);
8821 }
8822 return this;
8823 }
8824 clone() {
8825 return new Color(this.rgb);
8826 }
8827 alpha(a) {
8828 this._rgb.a = n2b(a);
8829 return this;
8830 }
8831 clearer(ratio) {
8832 const rgb = this._rgb;
8833 rgb.a *= 1 - ratio;
8834 return this;
8835 }
8836 greyscale() {
8837 const rgb = this._rgb;
8838 const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
8839 rgb.r = rgb.g = rgb.b = val;
8840 return this;
8841 }
8842 opaquer(ratio) {
8843 const rgb = this._rgb;
8844 rgb.a *= 1 + ratio;
8845 return this;
8846 }
8847 negate() {
8848 const v = this._rgb;
8849 v.r = 255 - v.r;
8850 v.g = 255 - v.g;
8851 v.b = 255 - v.b;
8852 return this;
8853 }
8854 lighten(ratio) {
8855 modHSL(this._rgb, 2, ratio);
8856 return this;
8857 }
8858 darken(ratio) {
8859 modHSL(this._rgb, 2, -ratio);
8860 return this;
8861 }
8862 saturate(ratio) {
8863 modHSL(this._rgb, 1, ratio);
8864 return this;
8865 }
8866 desaturate(ratio) {
8867 modHSL(this._rgb, 1, -ratio);
8868 return this;
8869 }
8870 rotate(deg) {
8871 rotate(this._rgb, deg);
8872 return this;
8873 }
8874 }
8875
8876 function index_esm(input) {
8877 return new Color(input);
8878 }
8879
8880
8881
8882
8883 /***/ },
8884
8885 /***/ "./node_modules/chart.js/auto/auto.js"
8886 /*!********************************************!*\
8887 !*** ./node_modules/chart.js/auto/auto.js ***!
8888 \********************************************/
8889 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8890
8891 "use strict";
8892 __webpack_require__.r(__webpack_exports__);
8893 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8894 /* harmony export */ Animation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animation),
8895 /* harmony export */ Animations: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animations),
8896 /* harmony export */ ArcElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ArcElement),
8897 /* harmony export */ BarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarController),
8898 /* harmony export */ BarElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarElement),
8899 /* harmony export */ BasePlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasePlatform),
8900 /* harmony export */ BasicPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasicPlatform),
8901 /* harmony export */ BubbleController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BubbleController),
8902 /* harmony export */ CategoryScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.CategoryScale),
8903 /* harmony export */ Chart: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart),
8904 /* harmony export */ Colors: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Colors),
8905 /* harmony export */ DatasetController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DatasetController),
8906 /* harmony export */ Decimation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Decimation),
8907 /* harmony export */ DomPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DomPlatform),
8908 /* harmony export */ DoughnutController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DoughnutController),
8909 /* harmony export */ Element: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Element),
8910 /* harmony export */ Filler: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Filler),
8911 /* harmony export */ Interaction: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Interaction),
8912 /* harmony export */ Legend: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Legend),
8913 /* harmony export */ LineController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineController),
8914 /* harmony export */ LineElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineElement),
8915 /* harmony export */ LinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LinearScale),
8916 /* harmony export */ LogarithmicScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LogarithmicScale),
8917 /* harmony export */ PieController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PieController),
8918 /* harmony export */ PointElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PointElement),
8919 /* harmony export */ PolarAreaController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PolarAreaController),
8920 /* harmony export */ RadarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadarController),
8921 /* harmony export */ RadialLinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadialLinearScale),
8922 /* harmony export */ Scale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Scale),
8923 /* harmony export */ ScatterController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ScatterController),
8924 /* harmony export */ SubTitle: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.SubTitle),
8925 /* harmony export */ Ticks: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Ticks),
8926 /* harmony export */ TimeScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeScale),
8927 /* harmony export */ TimeSeriesScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeSeriesScale),
8928 /* harmony export */ Title: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Title),
8929 /* harmony export */ Tooltip: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Tooltip),
8930 /* harmony export */ _adapters: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._adapters),
8931 /* harmony export */ _detectPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._detectPlatform),
8932 /* harmony export */ animator: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.animator),
8933 /* harmony export */ controllers: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.controllers),
8934 /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
8935 /* harmony export */ defaults: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.defaults),
8936 /* harmony export */ elements: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.elements),
8937 /* harmony export */ layouts: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.layouts),
8938 /* harmony export */ plugins: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.plugins),
8939 /* harmony export */ registerables: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables),
8940 /* harmony export */ registry: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registry),
8941 /* harmony export */ scales: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.scales)
8942 /* harmony export */ });
8943 /* harmony import */ var _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../dist/chart.js */ "./node_modules/chart.js/dist/chart.js");
8944
8945
8946 _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart.register(..._dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables);
8947
8948
8949 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart);
8950
8951
8952 /***/ },
8953
8954 /***/ "./node_modules/chart.js/dist/chart.js"
8955 /*!*********************************************!*\
8956 !*** ./node_modules/chart.js/dist/chart.js ***!
8957 \*********************************************/
8958 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8959
8960 "use strict";
8961 __webpack_require__.r(__webpack_exports__);
8962 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8963 /* harmony export */ Animation: () => (/* binding */ Animation),
8964 /* harmony export */ Animations: () => (/* binding */ Animations),
8965 /* harmony export */ ArcElement: () => (/* binding */ ArcElement),
8966 /* harmony export */ BarController: () => (/* binding */ BarController),
8967 /* harmony export */ BarElement: () => (/* binding */ BarElement),
8968 /* harmony export */ BasePlatform: () => (/* binding */ BasePlatform),
8969 /* harmony export */ BasicPlatform: () => (/* binding */ BasicPlatform),
8970 /* harmony export */ BubbleController: () => (/* binding */ BubbleController),
8971 /* harmony export */ CategoryScale: () => (/* binding */ CategoryScale),
8972 /* harmony export */ Chart: () => (/* binding */ Chart),
8973 /* harmony export */ Colors: () => (/* binding */ plugin_colors),
8974 /* harmony export */ DatasetController: () => (/* binding */ DatasetController),
8975 /* harmony export */ Decimation: () => (/* binding */ plugin_decimation),
8976 /* harmony export */ DomPlatform: () => (/* binding */ DomPlatform),
8977 /* harmony export */ DoughnutController: () => (/* binding */ DoughnutController),
8978 /* harmony export */ Element: () => (/* binding */ Element),
8979 /* harmony export */ Filler: () => (/* binding */ index),
8980 /* harmony export */ Interaction: () => (/* binding */ Interaction),
8981 /* harmony export */ Legend: () => (/* binding */ plugin_legend),
8982 /* harmony export */ LineController: () => (/* binding */ LineController),
8983 /* harmony export */ LineElement: () => (/* binding */ LineElement),
8984 /* harmony export */ LinearScale: () => (/* binding */ LinearScale),
8985 /* harmony export */ LogarithmicScale: () => (/* binding */ LogarithmicScale),
8986 /* harmony export */ PieController: () => (/* binding */ PieController),
8987 /* harmony export */ PointElement: () => (/* binding */ PointElement),
8988 /* harmony export */ PolarAreaController: () => (/* binding */ PolarAreaController),
8989 /* harmony export */ RadarController: () => (/* binding */ RadarController),
8990 /* harmony export */ RadialLinearScale: () => (/* binding */ RadialLinearScale),
8991 /* harmony export */ Scale: () => (/* binding */ Scale),
8992 /* harmony export */ ScatterController: () => (/* binding */ ScatterController),
8993 /* harmony export */ SubTitle: () => (/* binding */ plugin_subtitle),
8994 /* harmony export */ Ticks: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM),
8995 /* harmony export */ TimeScale: () => (/* binding */ TimeScale),
8996 /* harmony export */ TimeSeriesScale: () => (/* binding */ TimeSeriesScale),
8997 /* harmony export */ Title: () => (/* binding */ plugin_title),
8998 /* harmony export */ Tooltip: () => (/* binding */ plugin_tooltip),
8999 /* harmony export */ _adapters: () => (/* binding */ adapters),
9000 /* harmony export */ _detectPlatform: () => (/* binding */ _detectPlatform),
9001 /* harmony export */ animator: () => (/* binding */ animator),
9002 /* harmony export */ controllers: () => (/* binding */ controllers),
9003 /* harmony export */ defaults: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d),
9004 /* harmony export */ elements: () => (/* binding */ elements),
9005 /* harmony export */ layouts: () => (/* binding */ layouts),
9006 /* harmony export */ plugins: () => (/* binding */ plugins),
9007 /* harmony export */ registerables: () => (/* binding */ registerables),
9008 /* harmony export */ registry: () => (/* binding */ registry),
9009 /* harmony export */ scales: () => (/* binding */ scales)
9010 /* harmony export */ });
9011 /* harmony import */ var _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chunks/helpers.dataset.js */ "./node_modules/chart.js/dist/chunks/helpers.dataset.js");
9012 /*!
9013 * Chart.js v4.5.1
9014 * https://www.chartjs.org
9015 * (c) 2025 Chart.js Contributors
9016 * Released under the MIT License
9017 */
9018
9019
9020
9021 class Animator {
9022 constructor(){
9023 this._request = null;
9024 this._charts = new Map();
9025 this._running = false;
9026 this._lastDate = undefined;
9027 }
9028 _notify(chart, anims, date, type) {
9029 const callbacks = anims.listeners[type];
9030 const numSteps = anims.duration;
9031 callbacks.forEach((fn)=>fn({
9032 chart,
9033 initial: anims.initial,
9034 numSteps,
9035 currentStep: Math.min(date - anims.start, numSteps)
9036 }));
9037 }
9038 _refresh() {
9039 if (this._request) {
9040 return;
9041 }
9042 this._running = true;
9043 this._request = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.r.call(window, ()=>{
9044 this._update();
9045 this._request = null;
9046 if (this._running) {
9047 this._refresh();
9048 }
9049 });
9050 }
9051 _update(date = Date.now()) {
9052 let remaining = 0;
9053 this._charts.forEach((anims, chart)=>{
9054 if (!anims.running || !anims.items.length) {
9055 return;
9056 }
9057 const items = anims.items;
9058 let i = items.length - 1;
9059 let draw = false;
9060 let item;
9061 for(; i >= 0; --i){
9062 item = items[i];
9063 if (item._active) {
9064 if (item._total > anims.duration) {
9065 anims.duration = item._total;
9066 }
9067 item.tick(date);
9068 draw = true;
9069 } else {
9070 items[i] = items[items.length - 1];
9071 items.pop();
9072 }
9073 }
9074 if (draw) {
9075 chart.draw();
9076 this._notify(chart, anims, date, 'progress');
9077 }
9078 if (!items.length) {
9079 anims.running = false;
9080 this._notify(chart, anims, date, 'complete');
9081 anims.initial = false;
9082 }
9083 remaining += items.length;
9084 });
9085 this._lastDate = date;
9086 if (remaining === 0) {
9087 this._running = false;
9088 }
9089 }
9090 _getAnims(chart) {
9091 const charts = this._charts;
9092 let anims = charts.get(chart);
9093 if (!anims) {
9094 anims = {
9095 running: false,
9096 initial: true,
9097 items: [],
9098 listeners: {
9099 complete: [],
9100 progress: []
9101 }
9102 };
9103 charts.set(chart, anims);
9104 }
9105 return anims;
9106 }
9107 listen(chart, event, cb) {
9108 this._getAnims(chart).listeners[event].push(cb);
9109 }
9110 add(chart, items) {
9111 if (!items || !items.length) {
9112 return;
9113 }
9114 this._getAnims(chart).items.push(...items);
9115 }
9116 has(chart) {
9117 return this._getAnims(chart).items.length > 0;
9118 }
9119 start(chart) {
9120 const anims = this._charts.get(chart);
9121 if (!anims) {
9122 return;
9123 }
9124 anims.running = true;
9125 anims.start = Date.now();
9126 anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0);
9127 this._refresh();
9128 }
9129 running(chart) {
9130 if (!this._running) {
9131 return false;
9132 }
9133 const anims = this._charts.get(chart);
9134 if (!anims || !anims.running || !anims.items.length) {
9135 return false;
9136 }
9137 return true;
9138 }
9139 stop(chart) {
9140 const anims = this._charts.get(chart);
9141 if (!anims || !anims.items.length) {
9142 return;
9143 }
9144 const items = anims.items;
9145 let i = items.length - 1;
9146 for(; i >= 0; --i){
9147 items[i].cancel();
9148 }
9149 anims.items = [];
9150 this._notify(chart, anims, Date.now(), 'complete');
9151 }
9152 remove(chart) {
9153 return this._charts.delete(chart);
9154 }
9155 }
9156 var animator = /* #__PURE__ */ new Animator();
9157
9158 const transparent = 'transparent';
9159 const interpolators = {
9160 boolean (from, to, factor) {
9161 return factor > 0.5 ? to : from;
9162 },
9163 color (from, to, factor) {
9164 const c0 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(from || transparent);
9165 const c1 = c0.valid && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(to || transparent);
9166 return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;
9167 },
9168 number (from, to, factor) {
9169 return from + (to - from) * factor;
9170 }
9171 };
9172 class Animation {
9173 constructor(cfg, target, prop, to){
9174 const currentValue = target[prop];
9175 to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9176 cfg.to,
9177 to,
9178 currentValue,
9179 cfg.from
9180 ]);
9181 const from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9182 cfg.from,
9183 currentValue,
9184 to
9185 ]);
9186 this._active = true;
9187 this._fn = cfg.fn || interpolators[cfg.type || typeof from];
9188 this._easing = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e[cfg.easing] || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e.linear;
9189 this._start = Math.floor(Date.now() + (cfg.delay || 0));
9190 this._duration = this._total = Math.floor(cfg.duration);
9191 this._loop = !!cfg.loop;
9192 this._target = target;
9193 this._prop = prop;
9194 this._from = from;
9195 this._to = to;
9196 this._promises = undefined;
9197 }
9198 active() {
9199 return this._active;
9200 }
9201 update(cfg, to, date) {
9202 if (this._active) {
9203 this._notify(false);
9204 const currentValue = this._target[this._prop];
9205 const elapsed = date - this._start;
9206 const remain = this._duration - elapsed;
9207 this._start = date;
9208 this._duration = Math.floor(Math.max(remain, cfg.duration));
9209 this._total += elapsed;
9210 this._loop = !!cfg.loop;
9211 this._to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9212 cfg.to,
9213 to,
9214 currentValue,
9215 cfg.from
9216 ]);
9217 this._from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9218 cfg.from,
9219 currentValue,
9220 to
9221 ]);
9222 }
9223 }
9224 cancel() {
9225 if (this._active) {
9226 this.tick(Date.now());
9227 this._active = false;
9228 this._notify(false);
9229 }
9230 }
9231 tick(date) {
9232 const elapsed = date - this._start;
9233 const duration = this._duration;
9234 const prop = this._prop;
9235 const from = this._from;
9236 const loop = this._loop;
9237 const to = this._to;
9238 let factor;
9239 this._active = from !== to && (loop || elapsed < duration);
9240 if (!this._active) {
9241 this._target[prop] = to;
9242 this._notify(true);
9243 return;
9244 }
9245 if (elapsed < 0) {
9246 this._target[prop] = from;
9247 return;
9248 }
9249 factor = elapsed / duration % 2;
9250 factor = loop && factor > 1 ? 2 - factor : factor;
9251 factor = this._easing(Math.min(1, Math.max(0, factor)));
9252 this._target[prop] = this._fn(from, to, factor);
9253 }
9254 wait() {
9255 const promises = this._promises || (this._promises = []);
9256 return new Promise((res, rej)=>{
9257 promises.push({
9258 res,
9259 rej
9260 });
9261 });
9262 }
9263 _notify(resolved) {
9264 const method = resolved ? 'res' : 'rej';
9265 const promises = this._promises || [];
9266 for(let i = 0; i < promises.length; i++){
9267 promises[i][method]();
9268 }
9269 }
9270 }
9271
9272 class Animations {
9273 constructor(chart, config){
9274 this._chart = chart;
9275 this._properties = new Map();
9276 this.configure(config);
9277 }
9278 configure(config) {
9279 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(config)) {
9280 return;
9281 }
9282 const animationOptions = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.animation);
9283 const animatedProps = this._properties;
9284 Object.getOwnPropertyNames(config).forEach((key)=>{
9285 const cfg = config[key];
9286 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(cfg)) {
9287 return;
9288 }
9289 const resolved = {};
9290 for (const option of animationOptions){
9291 resolved[option] = cfg[option];
9292 }
9293 ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(cfg.properties) && cfg.properties || [
9294 key
9295 ]).forEach((prop)=>{
9296 if (prop === key || !animatedProps.has(prop)) {
9297 animatedProps.set(prop, resolved);
9298 }
9299 });
9300 });
9301 }
9302 _animateOptions(target, values) {
9303 const newOptions = values.options;
9304 const options = resolveTargetOptions(target, newOptions);
9305 if (!options) {
9306 return [];
9307 }
9308 const animations = this._createAnimations(options, newOptions);
9309 if (newOptions.$shared) {
9310 awaitAll(target.options.$animations, newOptions).then(()=>{
9311 target.options = newOptions;
9312 }, ()=>{
9313 });
9314 }
9315 return animations;
9316 }
9317 _createAnimations(target, values) {
9318 const animatedProps = this._properties;
9319 const animations = [];
9320 const running = target.$animations || (target.$animations = {});
9321 const props = Object.keys(values);
9322 const date = Date.now();
9323 let i;
9324 for(i = props.length - 1; i >= 0; --i){
9325 const prop = props[i];
9326 if (prop.charAt(0) === '$') {
9327 continue;
9328 }
9329 if (prop === 'options') {
9330 animations.push(...this._animateOptions(target, values));
9331 continue;
9332 }
9333 const value = values[prop];
9334 let animation = running[prop];
9335 const cfg = animatedProps.get(prop);
9336 if (animation) {
9337 if (cfg && animation.active()) {
9338 animation.update(cfg, value, date);
9339 continue;
9340 } else {
9341 animation.cancel();
9342 }
9343 }
9344 if (!cfg || !cfg.duration) {
9345 target[prop] = value;
9346 continue;
9347 }
9348 running[prop] = animation = new Animation(cfg, target, prop, value);
9349 animations.push(animation);
9350 }
9351 return animations;
9352 }
9353 update(target, values) {
9354 if (this._properties.size === 0) {
9355 Object.assign(target, values);
9356 return;
9357 }
9358 const animations = this._createAnimations(target, values);
9359 if (animations.length) {
9360 animator.add(this._chart, animations);
9361 return true;
9362 }
9363 }
9364 }
9365 function awaitAll(animations, properties) {
9366 const running = [];
9367 const keys = Object.keys(properties);
9368 for(let i = 0; i < keys.length; i++){
9369 const anim = animations[keys[i]];
9370 if (anim && anim.active()) {
9371 running.push(anim.wait());
9372 }
9373 }
9374 return Promise.all(running);
9375 }
9376 function resolveTargetOptions(target, newOptions) {
9377 if (!newOptions) {
9378 return;
9379 }
9380 let options = target.options;
9381 if (!options) {
9382 target.options = newOptions;
9383 return;
9384 }
9385 if (options.$shared) {
9386 target.options = options = Object.assign({}, options, {
9387 $shared: false,
9388 $animations: {}
9389 });
9390 }
9391 return options;
9392 }
9393
9394 function scaleClip(scale, allowedOverflow) {
9395 const opts = scale && scale.options || {};
9396 const reverse = opts.reverse;
9397 const min = opts.min === undefined ? allowedOverflow : 0;
9398 const max = opts.max === undefined ? allowedOverflow : 0;
9399 return {
9400 start: reverse ? max : min,
9401 end: reverse ? min : max
9402 };
9403 }
9404 function defaultClip(xScale, yScale, allowedOverflow) {
9405 if (allowedOverflow === false) {
9406 return false;
9407 }
9408 const x = scaleClip(xScale, allowedOverflow);
9409 const y = scaleClip(yScale, allowedOverflow);
9410 return {
9411 top: y.end,
9412 right: x.end,
9413 bottom: y.start,
9414 left: x.start
9415 };
9416 }
9417 function toClip(value) {
9418 let t, r, b, l;
9419 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value)) {
9420 t = value.top;
9421 r = value.right;
9422 b = value.bottom;
9423 l = value.left;
9424 } else {
9425 t = r = b = l = value;
9426 }
9427 return {
9428 top: t,
9429 right: r,
9430 bottom: b,
9431 left: l,
9432 disabled: value === false
9433 };
9434 }
9435 function getSortedDatasetIndices(chart, filterVisible) {
9436 const keys = [];
9437 const metasets = chart._getSortedDatasetMetas(filterVisible);
9438 let i, ilen;
9439 for(i = 0, ilen = metasets.length; i < ilen; ++i){
9440 keys.push(metasets[i].index);
9441 }
9442 return keys;
9443 }
9444 function applyStack(stack, value, dsIndex, options = {}) {
9445 const keys = stack.keys;
9446 const singleMode = options.mode === 'single';
9447 let i, ilen, datasetIndex, otherValue;
9448 if (value === null) {
9449 return;
9450 }
9451 let found = false;
9452 for(i = 0, ilen = keys.length; i < ilen; ++i){
9453 datasetIndex = +keys[i];
9454 if (datasetIndex === dsIndex) {
9455 found = true;
9456 if (options.all) {
9457 continue;
9458 }
9459 break;
9460 }
9461 otherValue = stack.values[datasetIndex];
9462 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(otherValue) && (singleMode || value === 0 || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(value) === (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(otherValue))) {
9463 value += otherValue;
9464 }
9465 }
9466 if (!found && !options.all) {
9467 return 0;
9468 }
9469 return value;
9470 }
9471 function convertObjectDataToArray(data, meta) {
9472 const { iScale , vScale } = meta;
9473 const iAxisKey = iScale.axis === 'x' ? 'x' : 'y';
9474 const vAxisKey = vScale.axis === 'x' ? 'x' : 'y';
9475 const keys = Object.keys(data);
9476 const adata = new Array(keys.length);
9477 let i, ilen, key;
9478 for(i = 0, ilen = keys.length; i < ilen; ++i){
9479 key = keys[i];
9480 adata[i] = {
9481 [iAxisKey]: key,
9482 [vAxisKey]: data[key]
9483 };
9484 }
9485 return adata;
9486 }
9487 function isStacked(scale, meta) {
9488 const stacked = scale && scale.options.stacked;
9489 return stacked || stacked === undefined && meta.stack !== undefined;
9490 }
9491 function getStackKey(indexScale, valueScale, meta) {
9492 return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
9493 }
9494 function getUserBounds(scale) {
9495 const { min , max , minDefined , maxDefined } = scale.getUserBounds();
9496 return {
9497 min: minDefined ? min : Number.NEGATIVE_INFINITY,
9498 max: maxDefined ? max : Number.POSITIVE_INFINITY
9499 };
9500 }
9501 function getOrCreateStack(stacks, stackKey, indexValue) {
9502 const subStack = stacks[stackKey] || (stacks[stackKey] = {});
9503 return subStack[indexValue] || (subStack[indexValue] = {});
9504 }
9505 function getLastIndexInStack(stack, vScale, positive, type) {
9506 for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){
9507 const value = stack[meta.index];
9508 if (positive && value > 0 || !positive && value < 0) {
9509 return meta.index;
9510 }
9511 }
9512 return null;
9513 }
9514 function updateStacks(controller, parsed) {
9515 const { chart , _cachedMeta: meta } = controller;
9516 const stacks = chart._stacks || (chart._stacks = {});
9517 const { iScale , vScale , index: datasetIndex } = meta;
9518 const iAxis = iScale.axis;
9519 const vAxis = vScale.axis;
9520 const key = getStackKey(iScale, vScale, meta);
9521 const ilen = parsed.length;
9522 let stack;
9523 for(let i = 0; i < ilen; ++i){
9524 const item = parsed[i];
9525 const { [iAxis]: index , [vAxis]: value } = item;
9526 const itemStacks = item._stacks || (item._stacks = {});
9527 stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
9528 stack[datasetIndex] = value;
9529 stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
9530 stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
9531 const visualValues = stack._visualValues || (stack._visualValues = {});
9532 visualValues[datasetIndex] = value;
9533 }
9534 }
9535 function getFirstScaleId(chart, axis) {
9536 const scales = chart.scales;
9537 return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift();
9538 }
9539 function createDatasetContext(parent, index) {
9540 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9541 active: false,
9542 dataset: undefined,
9543 datasetIndex: index,
9544 index,
9545 mode: 'default',
9546 type: 'dataset'
9547 });
9548 }
9549 function createDataContext(parent, index, element) {
9550 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9551 active: false,
9552 dataIndex: index,
9553 parsed: undefined,
9554 raw: undefined,
9555 element,
9556 index,
9557 mode: 'default',
9558 type: 'data'
9559 });
9560 }
9561 function clearStacks(meta, items) {
9562 const datasetIndex = meta.controller.index;
9563 const axis = meta.vScale && meta.vScale.axis;
9564 if (!axis) {
9565 return;
9566 }
9567 items = items || meta._parsed;
9568 for (const parsed of items){
9569 const stacks = parsed._stacks;
9570 if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {
9571 return;
9572 }
9573 delete stacks[axis][datasetIndex];
9574 if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) {
9575 delete stacks[axis]._visualValues[datasetIndex];
9576 }
9577 }
9578 }
9579 const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none';
9580 const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached);
9581 const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && {
9582 keys: getSortedDatasetIndices(chart, true),
9583 values: null
9584 };
9585 class DatasetController {
9586 static defaults = {};
9587 static datasetElementType = null;
9588 static dataElementType = null;
9589 constructor(chart, datasetIndex){
9590 this.chart = chart;
9591 this._ctx = chart.ctx;
9592 this.index = datasetIndex;
9593 this._cachedDataOpts = {};
9594 this._cachedMeta = this.getMeta();
9595 this._type = this._cachedMeta.type;
9596 this.options = undefined;
9597 this._parsing = false;
9598 this._data = undefined;
9599 this._objectData = undefined;
9600 this._sharedOptions = undefined;
9601 this._drawStart = undefined;
9602 this._drawCount = undefined;
9603 this.enableOptionSharing = false;
9604 this.supportsDecimation = false;
9605 this.$context = undefined;
9606 this._syncList = [];
9607 this.datasetElementType = new.target.datasetElementType;
9608 this.dataElementType = new.target.dataElementType;
9609 this.initialize();
9610 }
9611 initialize() {
9612 const meta = this._cachedMeta;
9613 this.configure();
9614 this.linkScales();
9615 meta._stacked = isStacked(meta.vScale, meta);
9616 this.addElements();
9617 if (this.options.fill && !this.chart.isPluginEnabled('filler')) {
9618 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");
9619 }
9620 }
9621 updateIndex(datasetIndex) {
9622 if (this.index !== datasetIndex) {
9623 clearStacks(this._cachedMeta);
9624 }
9625 this.index = datasetIndex;
9626 }
9627 linkScales() {
9628 const chart = this.chart;
9629 const meta = this._cachedMeta;
9630 const dataset = this.getDataset();
9631 const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y;
9632 const xid = meta.xAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.xAxisID, getFirstScaleId(chart, 'x'));
9633 const yid = meta.yAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.yAxisID, getFirstScaleId(chart, 'y'));
9634 const rid = meta.rAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.rAxisID, getFirstScaleId(chart, 'r'));
9635 const indexAxis = meta.indexAxis;
9636 const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
9637 const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
9638 meta.xScale = this.getScaleForId(xid);
9639 meta.yScale = this.getScaleForId(yid);
9640 meta.rScale = this.getScaleForId(rid);
9641 meta.iScale = this.getScaleForId(iid);
9642 meta.vScale = this.getScaleForId(vid);
9643 }
9644 getDataset() {
9645 return this.chart.data.datasets[this.index];
9646 }
9647 getMeta() {
9648 return this.chart.getDatasetMeta(this.index);
9649 }
9650 getScaleForId(scaleID) {
9651 return this.chart.scales[scaleID];
9652 }
9653 _getOtherScale(scale) {
9654 const meta = this._cachedMeta;
9655 return scale === meta.iScale ? meta.vScale : meta.iScale;
9656 }
9657 reset() {
9658 this._update('reset');
9659 }
9660 _destroy() {
9661 const meta = this._cachedMeta;
9662 if (this._data) {
9663 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(this._data, this);
9664 }
9665 if (meta._stacked) {
9666 clearStacks(meta);
9667 }
9668 }
9669 _dataCheck() {
9670 const dataset = this.getDataset();
9671 const data = dataset.data || (dataset.data = []);
9672 const _data = this._data;
9673 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data)) {
9674 const meta = this._cachedMeta;
9675 this._data = convertObjectDataToArray(data, meta);
9676 } else if (_data !== data) {
9677 if (_data) {
9678 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(_data, this);
9679 const meta = this._cachedMeta;
9680 clearStacks(meta);
9681 meta._parsed = [];
9682 }
9683 if (data && Object.isExtensible(data)) {
9684 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.l)(data, this);
9685 }
9686 this._syncList = [];
9687 this._data = data;
9688 }
9689 }
9690 addElements() {
9691 const meta = this._cachedMeta;
9692 this._dataCheck();
9693 if (this.datasetElementType) {
9694 meta.dataset = new this.datasetElementType();
9695 }
9696 }
9697 buildOrUpdateElements(resetNewElements) {
9698 const meta = this._cachedMeta;
9699 const dataset = this.getDataset();
9700 let stackChanged = false;
9701 this._dataCheck();
9702 const oldStacked = meta._stacked;
9703 meta._stacked = isStacked(meta.vScale, meta);
9704 if (meta.stack !== dataset.stack) {
9705 stackChanged = true;
9706 clearStacks(meta);
9707 meta.stack = dataset.stack;
9708 }
9709 this._resyncElements(resetNewElements);
9710 if (stackChanged || oldStacked !== meta._stacked) {
9711 updateStacks(this, meta._parsed);
9712 meta._stacked = isStacked(meta.vScale, meta);
9713 }
9714 }
9715 configure() {
9716 const config = this.chart.config;
9717 const scopeKeys = config.datasetScopeKeys(this._type);
9718 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
9719 this.options = config.createResolver(scopes, this.getContext());
9720 this._parsing = this.options.parsing;
9721 this._cachedDataOpts = {};
9722 }
9723 parse(start, count) {
9724 const { _cachedMeta: meta , _data: data } = this;
9725 const { iScale , _stacked } = meta;
9726 const iAxis = iScale.axis;
9727 let sorted = start === 0 && count === data.length ? true : meta._sorted;
9728 let prev = start > 0 && meta._parsed[start - 1];
9729 let i, cur, parsed;
9730 if (this._parsing === false) {
9731 meta._parsed = data;
9732 meta._sorted = true;
9733 parsed = data;
9734 } else {
9735 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(data[start])) {
9736 parsed = this.parseArrayData(meta, data, start, count);
9737 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
9738 parsed = this.parseObjectData(meta, data, start, count);
9739 } else {
9740 parsed = this.parsePrimitiveData(meta, data, start, count);
9741 }
9742 const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];
9743 for(i = 0; i < count; ++i){
9744 meta._parsed[i + start] = cur = parsed[i];
9745 if (sorted) {
9746 if (isNotInOrderComparedToPrev()) {
9747 sorted = false;
9748 }
9749 prev = cur;
9750 }
9751 }
9752 meta._sorted = sorted;
9753 }
9754 if (_stacked) {
9755 updateStacks(this, parsed);
9756 }
9757 }
9758 parsePrimitiveData(meta, data, start, count) {
9759 const { iScale , vScale } = meta;
9760 const iAxis = iScale.axis;
9761 const vAxis = vScale.axis;
9762 const labels = iScale.getLabels();
9763 const singleScale = iScale === vScale;
9764 const parsed = new Array(count);
9765 let i, ilen, index;
9766 for(i = 0, ilen = count; i < ilen; ++i){
9767 index = i + start;
9768 parsed[i] = {
9769 [iAxis]: singleScale || iScale.parse(labels[index], index),
9770 [vAxis]: vScale.parse(data[index], index)
9771 };
9772 }
9773 return parsed;
9774 }
9775 parseArrayData(meta, data, start, count) {
9776 const { xScale , yScale } = meta;
9777 const parsed = new Array(count);
9778 let i, ilen, index, item;
9779 for(i = 0, ilen = count; i < ilen; ++i){
9780 index = i + start;
9781 item = data[index];
9782 parsed[i] = {
9783 x: xScale.parse(item[0], index),
9784 y: yScale.parse(item[1], index)
9785 };
9786 }
9787 return parsed;
9788 }
9789 parseObjectData(meta, data, start, count) {
9790 const { xScale , yScale } = meta;
9791 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
9792 const parsed = new Array(count);
9793 let i, ilen, index, item;
9794 for(i = 0, ilen = count; i < ilen; ++i){
9795 index = i + start;
9796 item = data[index];
9797 parsed[i] = {
9798 x: xScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, xAxisKey), index),
9799 y: yScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, yAxisKey), index)
9800 };
9801 }
9802 return parsed;
9803 }
9804 getParsed(index) {
9805 return this._cachedMeta._parsed[index];
9806 }
9807 getDataElement(index) {
9808 return this._cachedMeta.data[index];
9809 }
9810 applyStack(scale, parsed, mode) {
9811 const chart = this.chart;
9812 const meta = this._cachedMeta;
9813 const value = parsed[scale.axis];
9814 const stack = {
9815 keys: getSortedDatasetIndices(chart, true),
9816 values: parsed._stacks[scale.axis]._visualValues
9817 };
9818 return applyStack(stack, value, meta.index, {
9819 mode
9820 });
9821 }
9822 updateRangeFromParsed(range, scale, parsed, stack) {
9823 const parsedValue = parsed[scale.axis];
9824 let value = parsedValue === null ? NaN : parsedValue;
9825 const values = stack && parsed._stacks[scale.axis];
9826 if (stack && values) {
9827 stack.values = values;
9828 value = applyStack(stack, parsedValue, this._cachedMeta.index);
9829 }
9830 range.min = Math.min(range.min, value);
9831 range.max = Math.max(range.max, value);
9832 }
9833 getMinMax(scale, canStack) {
9834 const meta = this._cachedMeta;
9835 const _parsed = meta._parsed;
9836 const sorted = meta._sorted && scale === meta.iScale;
9837 const ilen = _parsed.length;
9838 const otherScale = this._getOtherScale(scale);
9839 const stack = createStack(canStack, meta, this.chart);
9840 const range = {
9841 min: Number.POSITIVE_INFINITY,
9842 max: Number.NEGATIVE_INFINITY
9843 };
9844 const { min: otherMin , max: otherMax } = getUserBounds(otherScale);
9845 let i, parsed;
9846 function _skip() {
9847 parsed = _parsed[i];
9848 const otherValue = parsed[otherScale.axis];
9849 return !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
9850 }
9851 for(i = 0; i < ilen; ++i){
9852 if (_skip()) {
9853 continue;
9854 }
9855 this.updateRangeFromParsed(range, scale, parsed, stack);
9856 if (sorted) {
9857 break;
9858 }
9859 }
9860 if (sorted) {
9861 for(i = ilen - 1; i >= 0; --i){
9862 if (_skip()) {
9863 continue;
9864 }
9865 this.updateRangeFromParsed(range, scale, parsed, stack);
9866 break;
9867 }
9868 }
9869 return range;
9870 }
9871 getAllParsedValues(scale) {
9872 const parsed = this._cachedMeta._parsed;
9873 const values = [];
9874 let i, ilen, value;
9875 for(i = 0, ilen = parsed.length; i < ilen; ++i){
9876 value = parsed[i][scale.axis];
9877 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
9878 values.push(value);
9879 }
9880 }
9881 return values;
9882 }
9883 getMaxOverflow() {
9884 return false;
9885 }
9886 getLabelAndValue(index) {
9887 const meta = this._cachedMeta;
9888 const iScale = meta.iScale;
9889 const vScale = meta.vScale;
9890 const parsed = this.getParsed(index);
9891 return {
9892 label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
9893 value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
9894 };
9895 }
9896 _update(mode) {
9897 const meta = this._cachedMeta;
9898 this.update(mode || 'default');
9899 meta._clip = toClip((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
9900 }
9901 update(mode) {}
9902 draw() {
9903 const ctx = this._ctx;
9904 const chart = this.chart;
9905 const meta = this._cachedMeta;
9906 const elements = meta.data || [];
9907 const area = chart.chartArea;
9908 const active = [];
9909 const start = this._drawStart || 0;
9910 const count = this._drawCount || elements.length - start;
9911 const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
9912 let i;
9913 if (meta.dataset) {
9914 meta.dataset.draw(ctx, area, start, count);
9915 }
9916 for(i = start; i < start + count; ++i){
9917 const element = elements[i];
9918 if (element.hidden) {
9919 continue;
9920 }
9921 if (element.active && drawActiveElementsOnTop) {
9922 active.push(element);
9923 } else {
9924 element.draw(ctx, area);
9925 }
9926 }
9927 for(i = 0; i < active.length; ++i){
9928 active[i].draw(ctx, area);
9929 }
9930 }
9931 getStyle(index, active) {
9932 const mode = active ? 'active' : 'default';
9933 return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);
9934 }
9935 getContext(index, active, mode) {
9936 const dataset = this.getDataset();
9937 let context;
9938 if (index >= 0 && index < this._cachedMeta.data.length) {
9939 const element = this._cachedMeta.data[index];
9940 context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));
9941 context.parsed = this.getParsed(index);
9942 context.raw = dataset.data[index];
9943 context.index = context.dataIndex = index;
9944 } else {
9945 context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));
9946 context.dataset = dataset;
9947 context.index = context.datasetIndex = this.index;
9948 }
9949 context.active = !!active;
9950 context.mode = mode;
9951 return context;
9952 }
9953 resolveDatasetElementOptions(mode) {
9954 return this._resolveElementOptions(this.datasetElementType.id, mode);
9955 }
9956 resolveDataElementOptions(index, mode) {
9957 return this._resolveElementOptions(this.dataElementType.id, mode, index);
9958 }
9959 _resolveElementOptions(elementType, mode = 'default', index) {
9960 const active = mode === 'active';
9961 const cache = this._cachedDataOpts;
9962 const cacheKey = elementType + '-' + mode;
9963 const cached = cache[cacheKey];
9964 const sharing = this.enableOptionSharing && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(index);
9965 if (cached) {
9966 return cloneIfNotShared(cached, sharing);
9967 }
9968 const config = this.chart.config;
9969 const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
9970 const prefixes = active ? [
9971 `${elementType}Hover`,
9972 'hover',
9973 elementType,
9974 ''
9975 ] : [
9976 elementType,
9977 ''
9978 ];
9979 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
9980 const names = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.elements[elementType]);
9981 const context = ()=>this.getContext(index, active, mode);
9982 const values = config.resolveNamedOptions(scopes, names, context, prefixes);
9983 if (values.$shared) {
9984 values.$shared = sharing;
9985 cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
9986 }
9987 return values;
9988 }
9989 _resolveAnimations(index, transition, active) {
9990 const chart = this.chart;
9991 const cache = this._cachedDataOpts;
9992 const cacheKey = `animation-${transition}`;
9993 const cached = cache[cacheKey];
9994 if (cached) {
9995 return cached;
9996 }
9997 let options;
9998 if (chart.options.animation !== false) {
9999 const config = this.chart.config;
10000 const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
10001 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
10002 options = config.createResolver(scopes, this.getContext(index, active, transition));
10003 }
10004 const animations = new Animations(chart, options && options.animations);
10005 if (options && options._cacheable) {
10006 cache[cacheKey] = Object.freeze(animations);
10007 }
10008 return animations;
10009 }
10010 getSharedOptions(options) {
10011 if (!options.$shared) {
10012 return;
10013 }
10014 return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
10015 }
10016 includeOptions(mode, sharedOptions) {
10017 return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
10018 }
10019 _getSharedOptions(start, mode) {
10020 const firstOpts = this.resolveDataElementOptions(start, mode);
10021 const previouslySharedOptions = this._sharedOptions;
10022 const sharedOptions = this.getSharedOptions(firstOpts);
10023 const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;
10024 this.updateSharedOptions(sharedOptions, mode, firstOpts);
10025 return {
10026 sharedOptions,
10027 includeOptions
10028 };
10029 }
10030 updateElement(element, index, properties, mode) {
10031 if (isDirectUpdateMode(mode)) {
10032 Object.assign(element, properties);
10033 } else {
10034 this._resolveAnimations(index, mode).update(element, properties);
10035 }
10036 }
10037 updateSharedOptions(sharedOptions, mode, newOptions) {
10038 if (sharedOptions && !isDirectUpdateMode(mode)) {
10039 this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);
10040 }
10041 }
10042 _setStyle(element, index, mode, active) {
10043 element.active = active;
10044 const options = this.getStyle(index, active);
10045 this._resolveAnimations(index, mode, active).update(element, {
10046 options: !active && this.getSharedOptions(options) || options
10047 });
10048 }
10049 removeHoverStyle(element, datasetIndex, index) {
10050 this._setStyle(element, index, 'active', false);
10051 }
10052 setHoverStyle(element, datasetIndex, index) {
10053 this._setStyle(element, index, 'active', true);
10054 }
10055 _removeDatasetHoverStyle() {
10056 const element = this._cachedMeta.dataset;
10057 if (element) {
10058 this._setStyle(element, undefined, 'active', false);
10059 }
10060 }
10061 _setDatasetHoverStyle() {
10062 const element = this._cachedMeta.dataset;
10063 if (element) {
10064 this._setStyle(element, undefined, 'active', true);
10065 }
10066 }
10067 _resyncElements(resetNewElements) {
10068 const data = this._data;
10069 const elements = this._cachedMeta.data;
10070 for (const [method, arg1, arg2] of this._syncList){
10071 this[method](arg1, arg2);
10072 }
10073 this._syncList = [];
10074 const numMeta = elements.length;
10075 const numData = data.length;
10076 const count = Math.min(numData, numMeta);
10077 if (count) {
10078 this.parse(0, count);
10079 }
10080 if (numData > numMeta) {
10081 this._insertElements(numMeta, numData - numMeta, resetNewElements);
10082 } else if (numData < numMeta) {
10083 this._removeElements(numData, numMeta - numData);
10084 }
10085 }
10086 _insertElements(start, count, resetNewElements = true) {
10087 const meta = this._cachedMeta;
10088 const data = meta.data;
10089 const end = start + count;
10090 let i;
10091 const move = (arr)=>{
10092 arr.length += count;
10093 for(i = arr.length - 1; i >= end; i--){
10094 arr[i] = arr[i - count];
10095 }
10096 };
10097 move(data);
10098 for(i = start; i < end; ++i){
10099 data[i] = new this.dataElementType();
10100 }
10101 if (this._parsing) {
10102 move(meta._parsed);
10103 }
10104 this.parse(start, count);
10105 if (resetNewElements) {
10106 this.updateElements(data, start, count, 'reset');
10107 }
10108 }
10109 updateElements(element, start, count, mode) {}
10110 _removeElements(start, count) {
10111 const meta = this._cachedMeta;
10112 if (this._parsing) {
10113 const removed = meta._parsed.splice(start, count);
10114 if (meta._stacked) {
10115 clearStacks(meta, removed);
10116 }
10117 }
10118 meta.data.splice(start, count);
10119 }
10120 _sync(args) {
10121 if (this._parsing) {
10122 this._syncList.push(args);
10123 } else {
10124 const [method, arg1, arg2] = args;
10125 this[method](arg1, arg2);
10126 }
10127 this.chart._dataChanges.push([
10128 this.index,
10129 ...args
10130 ]);
10131 }
10132 _onDataPush() {
10133 const count = arguments.length;
10134 this._sync([
10135 '_insertElements',
10136 this.getDataset().data.length - count,
10137 count
10138 ]);
10139 }
10140 _onDataPop() {
10141 this._sync([
10142 '_removeElements',
10143 this._cachedMeta.data.length - 1,
10144 1
10145 ]);
10146 }
10147 _onDataShift() {
10148 this._sync([
10149 '_removeElements',
10150 0,
10151 1
10152 ]);
10153 }
10154 _onDataSplice(start, count) {
10155 if (count) {
10156 this._sync([
10157 '_removeElements',
10158 start,
10159 count
10160 ]);
10161 }
10162 const newCount = arguments.length - 2;
10163 if (newCount) {
10164 this._sync([
10165 '_insertElements',
10166 start,
10167 newCount
10168 ]);
10169 }
10170 }
10171 _onDataUnshift() {
10172 this._sync([
10173 '_insertElements',
10174 0,
10175 arguments.length
10176 ]);
10177 }
10178 }
10179
10180 function getAllScaleValues(scale, type) {
10181 if (!scale._cache.$bar) {
10182 const visibleMetas = scale.getMatchingVisibleMetas(type);
10183 let values = [];
10184 for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){
10185 values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));
10186 }
10187 scale._cache.$bar = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort((a, b)=>a - b));
10188 }
10189 return scale._cache.$bar;
10190 }
10191 function computeMinSampleSize(meta) {
10192 const scale = meta.iScale;
10193 const values = getAllScaleValues(scale, meta.type);
10194 let min = scale._length;
10195 let i, ilen, curr, prev;
10196 const updateMinAndPrev = ()=>{
10197 if (curr === 32767 || curr === -32768) {
10198 return;
10199 }
10200 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(prev)) {
10201 min = Math.min(min, Math.abs(curr - prev) || min);
10202 }
10203 prev = curr;
10204 };
10205 for(i = 0, ilen = values.length; i < ilen; ++i){
10206 curr = scale.getPixelForValue(values[i]);
10207 updateMinAndPrev();
10208 }
10209 prev = undefined;
10210 for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){
10211 curr = scale.getPixelForTick(i);
10212 updateMinAndPrev();
10213 }
10214 return min;
10215 }
10216 function computeFitCategoryTraits(index, ruler, options, stackCount) {
10217 const thickness = options.barThickness;
10218 let size, ratio;
10219 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(thickness)) {
10220 size = ruler.min * options.categoryPercentage;
10221 ratio = options.barPercentage;
10222 } else {
10223 size = thickness * stackCount;
10224 ratio = 1;
10225 }
10226 return {
10227 chunk: size / stackCount,
10228 ratio,
10229 start: ruler.pixels[index] - size / 2
10230 };
10231 }
10232 function computeFlexCategoryTraits(index, ruler, options, stackCount) {
10233 const pixels = ruler.pixels;
10234 const curr = pixels[index];
10235 let prev = index > 0 ? pixels[index - 1] : null;
10236 let next = index < pixels.length - 1 ? pixels[index + 1] : null;
10237 const percent = options.categoryPercentage;
10238 if (prev === null) {
10239 prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
10240 }
10241 if (next === null) {
10242 next = curr + curr - prev;
10243 }
10244 const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
10245 const size = Math.abs(next - prev) / 2 * percent;
10246 return {
10247 chunk: size / stackCount,
10248 ratio: options.barPercentage,
10249 start
10250 };
10251 }
10252 function parseFloatBar(entry, item, vScale, i) {
10253 const startValue = vScale.parse(entry[0], i);
10254 const endValue = vScale.parse(entry[1], i);
10255 const min = Math.min(startValue, endValue);
10256 const max = Math.max(startValue, endValue);
10257 let barStart = min;
10258 let barEnd = max;
10259 if (Math.abs(min) > Math.abs(max)) {
10260 barStart = max;
10261 barEnd = min;
10262 }
10263 item[vScale.axis] = barEnd;
10264 item._custom = {
10265 barStart,
10266 barEnd,
10267 start: startValue,
10268 end: endValue,
10269 min,
10270 max
10271 };
10272 }
10273 function parseValue(entry, item, vScale, i) {
10274 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(entry)) {
10275 parseFloatBar(entry, item, vScale, i);
10276 } else {
10277 item[vScale.axis] = vScale.parse(entry, i);
10278 }
10279 return item;
10280 }
10281 function parseArrayOrPrimitive(meta, data, start, count) {
10282 const iScale = meta.iScale;
10283 const vScale = meta.vScale;
10284 const labels = iScale.getLabels();
10285 const singleScale = iScale === vScale;
10286 const parsed = [];
10287 let i, ilen, item, entry;
10288 for(i = start, ilen = start + count; i < ilen; ++i){
10289 entry = data[i];
10290 item = {};
10291 item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
10292 parsed.push(parseValue(entry, item, vScale, i));
10293 }
10294 return parsed;
10295 }
10296 function isFloatBar(custom) {
10297 return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
10298 }
10299 function barSign(size, vScale, actualBase) {
10300 if (size !== 0) {
10301 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size);
10302 }
10303 return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
10304 }
10305 function borderProps(properties) {
10306 let reverse, start, end, top, bottom;
10307 if (properties.horizontal) {
10308 reverse = properties.base > properties.x;
10309 start = 'left';
10310 end = 'right';
10311 } else {
10312 reverse = properties.base < properties.y;
10313 start = 'bottom';
10314 end = 'top';
10315 }
10316 if (reverse) {
10317 top = 'end';
10318 bottom = 'start';
10319 } else {
10320 top = 'start';
10321 bottom = 'end';
10322 }
10323 return {
10324 start,
10325 end,
10326 reverse,
10327 top,
10328 bottom
10329 };
10330 }
10331 function setBorderSkipped(properties, options, stack, index) {
10332 let edge = options.borderSkipped;
10333 const res = {};
10334 if (!edge) {
10335 properties.borderSkipped = res;
10336 return;
10337 }
10338 if (edge === true) {
10339 properties.borderSkipped = {
10340 top: true,
10341 right: true,
10342 bottom: true,
10343 left: true
10344 };
10345 return;
10346 }
10347 const { start , end , reverse , top , bottom } = borderProps(properties);
10348 if (edge === 'middle' && stack) {
10349 properties.enableBorderRadius = true;
10350 if ((stack._top || 0) === index) {
10351 edge = top;
10352 } else if ((stack._bottom || 0) === index) {
10353 edge = bottom;
10354 } else {
10355 res[parseEdge(bottom, start, end, reverse)] = true;
10356 edge = top;
10357 }
10358 }
10359 res[parseEdge(edge, start, end, reverse)] = true;
10360 properties.borderSkipped = res;
10361 }
10362 function parseEdge(edge, a, b, reverse) {
10363 if (reverse) {
10364 edge = swap(edge, a, b);
10365 edge = startEnd(edge, b, a);
10366 } else {
10367 edge = startEnd(edge, a, b);
10368 }
10369 return edge;
10370 }
10371 function swap(orig, v1, v2) {
10372 return orig === v1 ? v2 : orig === v2 ? v1 : orig;
10373 }
10374 function startEnd(v, start, end) {
10375 return v === 'start' ? start : v === 'end' ? end : v;
10376 }
10377 function setInflateAmount(properties, { inflateAmount }, ratio) {
10378 properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount;
10379 }
10380 class BarController extends DatasetController {
10381 static id = 'bar';
10382 static defaults = {
10383 datasetElementType: false,
10384 dataElementType: 'bar',
10385 categoryPercentage: 0.8,
10386 barPercentage: 0.9,
10387 grouped: true,
10388 animations: {
10389 numbers: {
10390 type: 'number',
10391 properties: [
10392 'x',
10393 'y',
10394 'base',
10395 'width',
10396 'height'
10397 ]
10398 }
10399 }
10400 };
10401 static overrides = {
10402 scales: {
10403 _index_: {
10404 type: 'category',
10405 offset: true,
10406 grid: {
10407 offset: true
10408 }
10409 },
10410 _value_: {
10411 type: 'linear',
10412 beginAtZero: true
10413 }
10414 }
10415 };
10416 parsePrimitiveData(meta, data, start, count) {
10417 return parseArrayOrPrimitive(meta, data, start, count);
10418 }
10419 parseArrayData(meta, data, start, count) {
10420 return parseArrayOrPrimitive(meta, data, start, count);
10421 }
10422 parseObjectData(meta, data, start, count) {
10423 const { iScale , vScale } = meta;
10424 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
10425 const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
10426 const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
10427 const parsed = [];
10428 let i, ilen, item, obj;
10429 for(i = start, ilen = start + count; i < ilen; ++i){
10430 obj = data[i];
10431 item = {};
10432 item[iScale.axis] = iScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, iAxisKey), i);
10433 parsed.push(parseValue((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, vAxisKey), item, vScale, i));
10434 }
10435 return parsed;
10436 }
10437 updateRangeFromParsed(range, scale, parsed, stack) {
10438 super.updateRangeFromParsed(range, scale, parsed, stack);
10439 const custom = parsed._custom;
10440 if (custom && scale === this._cachedMeta.vScale) {
10441 range.min = Math.min(range.min, custom.min);
10442 range.max = Math.max(range.max, custom.max);
10443 }
10444 }
10445 getMaxOverflow() {
10446 return 0;
10447 }
10448 getLabelAndValue(index) {
10449 const meta = this._cachedMeta;
10450 const { iScale , vScale } = meta;
10451 const parsed = this.getParsed(index);
10452 const custom = parsed._custom;
10453 const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]);
10454 return {
10455 label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
10456 value
10457 };
10458 }
10459 initialize() {
10460 this.enableOptionSharing = true;
10461 super.initialize();
10462 const meta = this._cachedMeta;
10463 meta.stack = this.getDataset().stack;
10464 }
10465 update(mode) {
10466 const meta = this._cachedMeta;
10467 this.updateElements(meta.data, 0, meta.data.length, mode);
10468 }
10469 updateElements(bars, start, count, mode) {
10470 const reset = mode === 'reset';
10471 const { index , _cachedMeta: { vScale } } = this;
10472 const base = vScale.getBasePixel();
10473 const horizontal = vScale.isHorizontal();
10474 const ruler = this._getRuler();
10475 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10476 for(let i = start; i < start + count; i++){
10477 const parsed = this.getParsed(i);
10478 const vpixels = reset || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vScale.axis]) ? {
10479 base,
10480 head: base
10481 } : this._calculateBarValuePixels(i);
10482 const ipixels = this._calculateBarIndexPixels(i, ruler);
10483 const stack = (parsed._stacks || {})[vScale.axis];
10484 const properties = {
10485 horizontal,
10486 base: vpixels.base,
10487 enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,
10488 x: horizontal ? vpixels.head : ipixels.center,
10489 y: horizontal ? ipixels.center : vpixels.head,
10490 height: horizontal ? ipixels.size : Math.abs(vpixels.size),
10491 width: horizontal ? Math.abs(vpixels.size) : ipixels.size
10492 };
10493 if (includeOptions) {
10494 properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);
10495 }
10496 const options = properties.options || bars[i].options;
10497 setBorderSkipped(properties, options, stack, index);
10498 setInflateAmount(properties, options, ruler.ratio);
10499 this.updateElement(bars[i], i, properties, mode);
10500 }
10501 }
10502 _getStacks(last, dataIndex) {
10503 const { iScale } = this._cachedMeta;
10504 const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped);
10505 const stacked = iScale.options.stacked;
10506 const stacks = [];
10507 const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);
10508 const iScaleValue = currentParsed && currentParsed[iScale.axis];
10509 const skipNull = (meta)=>{
10510 const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue);
10511 const val = parsed && parsed[meta.vScale.axis];
10512 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(val) || isNaN(val)) {
10513 return true;
10514 }
10515 };
10516 for (const meta of metasets){
10517 if (dataIndex !== undefined && skipNull(meta)) {
10518 continue;
10519 }
10520 if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) {
10521 stacks.push(meta.stack);
10522 }
10523 if (meta.index === last) {
10524 break;
10525 }
10526 }
10527 if (!stacks.length) {
10528 stacks.push(undefined);
10529 }
10530 return stacks;
10531 }
10532 _getStackCount(index) {
10533 return this._getStacks(undefined, index).length;
10534 }
10535 _getAxisCount() {
10536 return this._getAxis().length;
10537 }
10538 getFirstScaleIdForIndexAxis() {
10539 const scales = this.chart.scales;
10540 const indexScaleId = this.chart.options.indexAxis;
10541 return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift();
10542 }
10543 _getAxis() {
10544 const axis = {};
10545 const firstScaleAxisId = this.getFirstScaleIdForIndexAxis();
10546 for (const dataset of this.chart.data.datasets){
10547 axis[(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true;
10548 }
10549 return Object.keys(axis);
10550 }
10551 _getStackIndex(datasetIndex, name, dataIndex) {
10552 const stacks = this._getStacks(datasetIndex, dataIndex);
10553 const index = name !== undefined ? stacks.indexOf(name) : -1;
10554 return index === -1 ? stacks.length - 1 : index;
10555 }
10556 _getRuler() {
10557 const opts = this.options;
10558 const meta = this._cachedMeta;
10559 const iScale = meta.iScale;
10560 const pixels = [];
10561 let i, ilen;
10562 for(i = 0, ilen = meta.data.length; i < ilen; ++i){
10563 pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));
10564 }
10565 const barThickness = opts.barThickness;
10566 const min = barThickness || computeMinSampleSize(meta);
10567 return {
10568 min,
10569 pixels,
10570 start: iScale._startPixel,
10571 end: iScale._endPixel,
10572 stackCount: this._getStackCount(),
10573 scale: iScale,
10574 grouped: opts.grouped,
10575 ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
10576 };
10577 }
10578 _calculateBarValuePixels(index) {
10579 const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this;
10580 const actualBase = baseValue || 0;
10581 const parsed = this.getParsed(index);
10582 const custom = parsed._custom;
10583 const floating = isFloatBar(custom);
10584 let value = parsed[vScale.axis];
10585 let start = 0;
10586 let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
10587 let head, size;
10588 if (length !== value) {
10589 start = length - value;
10590 length = value;
10591 }
10592 if (floating) {
10593 value = custom.barStart;
10594 length = custom.barEnd - custom.barStart;
10595 if (value !== 0 && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(value) !== (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(custom.barEnd)) {
10596 start = 0;
10597 }
10598 start += value;
10599 }
10600 const startValue = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(baseValue) && !floating ? baseValue : start;
10601 let base = vScale.getPixelForValue(startValue);
10602 if (this.chart.getDataVisibility(index)) {
10603 head = vScale.getPixelForValue(start + length);
10604 } else {
10605 head = base;
10606 }
10607 size = head - base;
10608 if (Math.abs(size) < minBarLength) {
10609 size = barSign(size, vScale, actualBase) * minBarLength;
10610 if (value === actualBase) {
10611 base -= size / 2;
10612 }
10613 const startPixel = vScale.getPixelForDecimal(0);
10614 const endPixel = vScale.getPixelForDecimal(1);
10615 const min = Math.min(startPixel, endPixel);
10616 const max = Math.max(startPixel, endPixel);
10617 base = Math.max(Math.min(base, max), min);
10618 head = base + size;
10619 if (_stacked && !floating) {
10620 parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);
10621 }
10622 }
10623 if (base === vScale.getPixelForValue(actualBase)) {
10624 const halfGrid = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size) * vScale.getLineWidthForValue(actualBase) / 2;
10625 base += halfGrid;
10626 size -= halfGrid;
10627 }
10628 return {
10629 size,
10630 base,
10631 head,
10632 center: head + size / 2
10633 };
10634 }
10635 _calculateBarIndexPixels(index, ruler) {
10636 const scale = ruler.scale;
10637 const options = this.options;
10638 const skipNull = options.skipNull;
10639 const maxBarThickness = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.maxBarThickness, Infinity);
10640 let center, size;
10641 const axisCount = this._getAxisCount();
10642 if (ruler.grouped) {
10643 const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
10644 const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount);
10645 const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID;
10646 const axisNumber = this._getAxis().indexOf((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(axisID, this.getFirstScaleIdForIndexAxis()));
10647 const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber;
10648 center = range.start + range.chunk * stackIndex + range.chunk / 2;
10649 size = Math.min(maxBarThickness, range.chunk * range.ratio);
10650 } else {
10651 center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
10652 size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
10653 }
10654 return {
10655 base: center - size / 2,
10656 head: center + size / 2,
10657 center,
10658 size
10659 };
10660 }
10661 draw() {
10662 const meta = this._cachedMeta;
10663 const vScale = meta.vScale;
10664 const rects = meta.data;
10665 const ilen = rects.length;
10666 let i = 0;
10667 for(; i < ilen; ++i){
10668 if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) {
10669 rects[i].draw(this._ctx);
10670 }
10671 }
10672 }
10673 }
10674
10675 class BubbleController extends DatasetController {
10676 static id = 'bubble';
10677 static defaults = {
10678 datasetElementType: false,
10679 dataElementType: 'point',
10680 animations: {
10681 numbers: {
10682 type: 'number',
10683 properties: [
10684 'x',
10685 'y',
10686 'borderWidth',
10687 'radius'
10688 ]
10689 }
10690 }
10691 };
10692 static overrides = {
10693 scales: {
10694 x: {
10695 type: 'linear'
10696 },
10697 y: {
10698 type: 'linear'
10699 }
10700 }
10701 };
10702 initialize() {
10703 this.enableOptionSharing = true;
10704 super.initialize();
10705 }
10706 parsePrimitiveData(meta, data, start, count) {
10707 const parsed = super.parsePrimitiveData(meta, data, start, count);
10708 for(let i = 0; i < parsed.length; i++){
10709 parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;
10710 }
10711 return parsed;
10712 }
10713 parseArrayData(meta, data, start, count) {
10714 const parsed = super.parseArrayData(meta, data, start, count);
10715 for(let i = 0; i < parsed.length; i++){
10716 const item = data[start + i];
10717 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item[2], this.resolveDataElementOptions(i + start).radius);
10718 }
10719 return parsed;
10720 }
10721 parseObjectData(meta, data, start, count) {
10722 const parsed = super.parseObjectData(meta, data, start, count);
10723 for(let i = 0; i < parsed.length; i++){
10724 const item = data[start + i];
10725 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);
10726 }
10727 return parsed;
10728 }
10729 getMaxOverflow() {
10730 const data = this._cachedMeta.data;
10731 let max = 0;
10732 for(let i = data.length - 1; i >= 0; --i){
10733 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
10734 }
10735 return max > 0 && max;
10736 }
10737 getLabelAndValue(index) {
10738 const meta = this._cachedMeta;
10739 const labels = this.chart.data.labels || [];
10740 const { xScale , yScale } = meta;
10741 const parsed = this.getParsed(index);
10742 const x = xScale.getLabelForValue(parsed.x);
10743 const y = yScale.getLabelForValue(parsed.y);
10744 const r = parsed._custom;
10745 return {
10746 label: labels[index] || '',
10747 value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
10748 };
10749 }
10750 update(mode) {
10751 const points = this._cachedMeta.data;
10752 this.updateElements(points, 0, points.length, mode);
10753 }
10754 updateElements(points, start, count, mode) {
10755 const reset = mode === 'reset';
10756 const { iScale , vScale } = this._cachedMeta;
10757 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10758 const iAxis = iScale.axis;
10759 const vAxis = vScale.axis;
10760 for(let i = start; i < start + count; i++){
10761 const point = points[i];
10762 const parsed = !reset && this.getParsed(i);
10763 const properties = {};
10764 const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);
10765 const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);
10766 properties.skip = isNaN(iPixel) || isNaN(vPixel);
10767 if (includeOptions) {
10768 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
10769 if (reset) {
10770 properties.options.radius = 0;
10771 }
10772 }
10773 this.updateElement(point, i, properties, mode);
10774 }
10775 }
10776 resolveDataElementOptions(index, mode) {
10777 const parsed = this.getParsed(index);
10778 let values = super.resolveDataElementOptions(index, mode);
10779 if (values.$shared) {
10780 values = Object.assign({}, values, {
10781 $shared: false
10782 });
10783 }
10784 const radius = values.radius;
10785 if (mode !== 'active') {
10786 values.radius = 0;
10787 }
10788 values.radius += (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(parsed && parsed._custom, radius);
10789 return values;
10790 }
10791 }
10792
10793 function getRatioAndOffset(rotation, circumference, cutout) {
10794 let ratioX = 1;
10795 let ratioY = 1;
10796 let offsetX = 0;
10797 let offsetY = 0;
10798 if (circumference < _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) {
10799 const startAngle = rotation;
10800 const endAngle = startAngle + circumference;
10801 const startX = Math.cos(startAngle);
10802 const startY = Math.sin(startAngle);
10803 const endX = Math.cos(endAngle);
10804 const endY = Math.sin(endAngle);
10805 const calcMax = (angle, a, b)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout);
10806 const calcMin = (angle, a, b)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout);
10807 const maxX = calcMax(0, startX, endX);
10808 const maxY = calcMax(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10809 const minX = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, startX, endX);
10810 const minY = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10811 ratioX = (maxX - minX) / 2;
10812 ratioY = (maxY - minY) / 2;
10813 offsetX = -(maxX + minX) / 2;
10814 offsetY = -(maxY + minY) / 2;
10815 }
10816 return {
10817 ratioX,
10818 ratioY,
10819 offsetX,
10820 offsetY
10821 };
10822 }
10823 class DoughnutController extends DatasetController {
10824 static id = 'doughnut';
10825 static defaults = {
10826 datasetElementType: false,
10827 dataElementType: 'arc',
10828 animation: {
10829 animateRotate: true,
10830 animateScale: false
10831 },
10832 animations: {
10833 numbers: {
10834 type: 'number',
10835 properties: [
10836 'circumference',
10837 'endAngle',
10838 'innerRadius',
10839 'outerRadius',
10840 'startAngle',
10841 'x',
10842 'y',
10843 'offset',
10844 'borderWidth',
10845 'spacing'
10846 ]
10847 }
10848 },
10849 cutout: '50%',
10850 rotation: 0,
10851 circumference: 360,
10852 radius: '100%',
10853 spacing: 0,
10854 indexAxis: 'r'
10855 };
10856 static descriptors = {
10857 _scriptable: (name)=>name !== 'spacing',
10858 _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash')
10859 };
10860 static overrides = {
10861 aspectRatio: 1,
10862 plugins: {
10863 legend: {
10864 labels: {
10865 generateLabels (chart) {
10866 const data = chart.data;
10867 const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
10868 if (data.labels.length && data.datasets.length) {
10869 return data.labels.map((label, i)=>{
10870 const meta = chart.getDatasetMeta(0);
10871 const style = meta.controller.getStyle(i);
10872 return {
10873 text: label,
10874 fillStyle: style.backgroundColor,
10875 fontColor: color,
10876 hidden: !chart.getDataVisibility(i),
10877 lineDash: style.borderDash,
10878 lineDashOffset: style.borderDashOffset,
10879 lineJoin: style.borderJoinStyle,
10880 lineWidth: style.borderWidth,
10881 strokeStyle: style.borderColor,
10882 textAlign: textAlign,
10883 pointStyle: pointStyle,
10884 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
10885 index: i
10886 };
10887 });
10888 }
10889 return [];
10890 }
10891 },
10892 onClick (e, legendItem, legend) {
10893 legend.chart.toggleDataVisibility(legendItem.index);
10894 legend.chart.update();
10895 }
10896 }
10897 }
10898 };
10899 constructor(chart, datasetIndex){
10900 super(chart, datasetIndex);
10901 this.enableOptionSharing = true;
10902 this.innerRadius = undefined;
10903 this.outerRadius = undefined;
10904 this.offsetX = undefined;
10905 this.offsetY = undefined;
10906 }
10907 linkScales() {}
10908 parse(start, count) {
10909 const data = this.getDataset().data;
10910 const meta = this._cachedMeta;
10911 if (this._parsing === false) {
10912 meta._parsed = data;
10913 } else {
10914 let getter = (i)=>+data[i];
10915 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
10916 const { key ='value' } = this._parsing;
10917 getter = (i)=>+(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(data[i], key);
10918 }
10919 let i, ilen;
10920 for(i = start, ilen = start + count; i < ilen; ++i){
10921 meta._parsed[i] = getter(i);
10922 }
10923 }
10924 }
10925 _getRotation() {
10926 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.rotation - 90);
10927 }
10928 _getCircumference() {
10929 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.circumference);
10930 }
10931 _getRotationExtents() {
10932 let min = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
10933 let max = -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
10934 for(let i = 0; i < this.chart.data.datasets.length; ++i){
10935 if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) {
10936 const controller = this.chart.getDatasetMeta(i).controller;
10937 const rotation = controller._getRotation();
10938 const circumference = controller._getCircumference();
10939 min = Math.min(min, rotation);
10940 max = Math.max(max, rotation + circumference);
10941 }
10942 }
10943 return {
10944 rotation: min,
10945 circumference: max - min
10946 };
10947 }
10948 update(mode) {
10949 const chart = this.chart;
10950 const { chartArea } = chart;
10951 const meta = this._cachedMeta;
10952 const arcs = meta.data;
10953 const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
10954 const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
10955 const cutout = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.m)(this.options.cutout, maxSize), 1);
10956 const chartWeight = this._getRingWeight(this.index);
10957 const { circumference , rotation } = this._getRotationExtents();
10958 const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout);
10959 const maxWidth = (chartArea.width - spacing) / ratioX;
10960 const maxHeight = (chartArea.height - spacing) / ratioY;
10961 const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
10962 const outerRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.n)(this.options.radius, maxRadius);
10963 const innerRadius = Math.max(outerRadius * cutout, 0);
10964 const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
10965 this.offsetX = offsetX * outerRadius;
10966 this.offsetY = offsetY * outerRadius;
10967 meta.total = this.calculateTotal();
10968 this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
10969 this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
10970 this.updateElements(arcs, 0, arcs.length, mode);
10971 }
10972 _circumference(i, reset) {
10973 const opts = this.options;
10974 const meta = this._cachedMeta;
10975 const circumference = this._getCircumference();
10976 if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
10977 return 0;
10978 }
10979 return this.calculateCircumference(meta._parsed[i] * circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
10980 }
10981 updateElements(arcs, start, count, mode) {
10982 const reset = mode === 'reset';
10983 const chart = this.chart;
10984 const chartArea = chart.chartArea;
10985 const opts = chart.options;
10986 const animationOpts = opts.animation;
10987 const centerX = (chartArea.left + chartArea.right) / 2;
10988 const centerY = (chartArea.top + chartArea.bottom) / 2;
10989 const animateScale = reset && animationOpts.animateScale;
10990 const innerRadius = animateScale ? 0 : this.innerRadius;
10991 const outerRadius = animateScale ? 0 : this.outerRadius;
10992 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10993 let startAngle = this._getRotation();
10994 let i;
10995 for(i = 0; i < start; ++i){
10996 startAngle += this._circumference(i, reset);
10997 }
10998 for(i = start; i < start + count; ++i){
10999 const circumference = this._circumference(i, reset);
11000 const arc = arcs[i];
11001 const properties = {
11002 x: centerX + this.offsetX,
11003 y: centerY + this.offsetY,
11004 startAngle,
11005 endAngle: startAngle + circumference,
11006 circumference,
11007 outerRadius,
11008 innerRadius
11009 };
11010 if (includeOptions) {
11011 properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);
11012 }
11013 startAngle += circumference;
11014 this.updateElement(arc, i, properties, mode);
11015 }
11016 }
11017 calculateTotal() {
11018 const meta = this._cachedMeta;
11019 const metaData = meta.data;
11020 let total = 0;
11021 let i;
11022 for(i = 0; i < metaData.length; i++){
11023 const value = meta._parsed[i];
11024 if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
11025 total += Math.abs(value);
11026 }
11027 }
11028 return total;
11029 }
11030 calculateCircumference(value) {
11031 const total = this._cachedMeta.total;
11032 if (total > 0 && !isNaN(value)) {
11033 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T * (Math.abs(value) / total);
11034 }
11035 return 0;
11036 }
11037 getLabelAndValue(index) {
11038 const meta = this._cachedMeta;
11039 const chart = this.chart;
11040 const labels = chart.data.labels || [];
11041 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index], chart.options.locale);
11042 return {
11043 label: labels[index] || '',
11044 value
11045 };
11046 }
11047 getMaxBorderWidth(arcs) {
11048 let max = 0;
11049 const chart = this.chart;
11050 let i, ilen, meta, controller, options;
11051 if (!arcs) {
11052 for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){
11053 if (chart.isDatasetVisible(i)) {
11054 meta = chart.getDatasetMeta(i);
11055 arcs = meta.data;
11056 controller = meta.controller;
11057 break;
11058 }
11059 }
11060 }
11061 if (!arcs) {
11062 return 0;
11063 }
11064 for(i = 0, ilen = arcs.length; i < ilen; ++i){
11065 options = controller.resolveDataElementOptions(i);
11066 if (options.borderAlign !== 'inner') {
11067 max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
11068 }
11069 }
11070 return max;
11071 }
11072 getMaxOffset(arcs) {
11073 let max = 0;
11074 for(let i = 0, ilen = arcs.length; i < ilen; ++i){
11075 const options = this.resolveDataElementOptions(i);
11076 max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
11077 }
11078 return max;
11079 }
11080 _getRingWeightOffset(datasetIndex) {
11081 let ringWeightOffset = 0;
11082 for(let i = 0; i < datasetIndex; ++i){
11083 if (this.chart.isDatasetVisible(i)) {
11084 ringWeightOffset += this._getRingWeight(i);
11085 }
11086 }
11087 return ringWeightOffset;
11088 }
11089 _getRingWeight(datasetIndex) {
11090 return Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.data.datasets[datasetIndex].weight, 1), 0);
11091 }
11092 _getVisibleDatasetWeightTotal() {
11093 return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
11094 }
11095 }
11096
11097 class LineController extends DatasetController {
11098 static id = 'line';
11099 static defaults = {
11100 datasetElementType: 'line',
11101 dataElementType: 'point',
11102 showLine: true,
11103 spanGaps: false
11104 };
11105 static overrides = {
11106 scales: {
11107 _index_: {
11108 type: 'category'
11109 },
11110 _value_: {
11111 type: 'linear'
11112 }
11113 }
11114 };
11115 initialize() {
11116 this.enableOptionSharing = true;
11117 this.supportsDecimation = true;
11118 super.initialize();
11119 }
11120 update(mode) {
11121 const meta = this._cachedMeta;
11122 const { dataset: line , data: points = [] , _dataset } = meta;
11123 const animationsDisabled = this.chart._animationsDisabled;
11124 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11125 this._drawStart = start;
11126 this._drawCount = count;
11127 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11128 start = 0;
11129 count = points.length;
11130 }
11131 line._chart = this.chart;
11132 line._datasetIndex = this.index;
11133 line._decimated = !!_dataset._decimated;
11134 line.points = points;
11135 const options = this.resolveDatasetElementOptions(mode);
11136 if (!this.options.showLine) {
11137 options.borderWidth = 0;
11138 }
11139 options.segment = this.options.segment;
11140 this.updateElement(line, undefined, {
11141 animated: !animationsDisabled,
11142 options
11143 }, mode);
11144 this.updateElements(points, start, count, mode);
11145 }
11146 updateElements(points, start, count, mode) {
11147 const reset = mode === 'reset';
11148 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11149 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11150 const iAxis = iScale.axis;
11151 const vAxis = vScale.axis;
11152 const { spanGaps , segment } = this.options;
11153 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11154 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11155 const end = start + count;
11156 const pointsCount = points.length;
11157 let prevParsed = start > 0 && this.getParsed(start - 1);
11158 for(let i = 0; i < pointsCount; ++i){
11159 const point = points[i];
11160 const properties = directUpdate ? point : {};
11161 if (i < start || i >= end) {
11162 properties.skip = true;
11163 continue;
11164 }
11165 const parsed = this.getParsed(i);
11166 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11167 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11168 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11169 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11170 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11171 if (segment) {
11172 properties.parsed = parsed;
11173 properties.raw = _dataset.data[i];
11174 }
11175 if (includeOptions) {
11176 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11177 }
11178 if (!directUpdate) {
11179 this.updateElement(point, i, properties, mode);
11180 }
11181 prevParsed = parsed;
11182 }
11183 }
11184 getMaxOverflow() {
11185 const meta = this._cachedMeta;
11186 const dataset = meta.dataset;
11187 const border = dataset.options && dataset.options.borderWidth || 0;
11188 const data = meta.data || [];
11189 if (!data.length) {
11190 return border;
11191 }
11192 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11193 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11194 return Math.max(border, firstPoint, lastPoint) / 2;
11195 }
11196 draw() {
11197 const meta = this._cachedMeta;
11198 meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);
11199 super.draw();
11200 }
11201 }
11202
11203 class PolarAreaController extends DatasetController {
11204 static id = 'polarArea';
11205 static defaults = {
11206 dataElementType: 'arc',
11207 animation: {
11208 animateRotate: true,
11209 animateScale: true
11210 },
11211 animations: {
11212 numbers: {
11213 type: 'number',
11214 properties: [
11215 'x',
11216 'y',
11217 'startAngle',
11218 'endAngle',
11219 'innerRadius',
11220 'outerRadius'
11221 ]
11222 }
11223 },
11224 indexAxis: 'r',
11225 startAngle: 0
11226 };
11227 static overrides = {
11228 aspectRatio: 1,
11229 plugins: {
11230 legend: {
11231 labels: {
11232 generateLabels (chart) {
11233 const data = chart.data;
11234 if (data.labels.length && data.datasets.length) {
11235 const { labels: { pointStyle , color } } = chart.legend.options;
11236 return data.labels.map((label, i)=>{
11237 const meta = chart.getDatasetMeta(0);
11238 const style = meta.controller.getStyle(i);
11239 return {
11240 text: label,
11241 fillStyle: style.backgroundColor,
11242 strokeStyle: style.borderColor,
11243 fontColor: color,
11244 lineWidth: style.borderWidth,
11245 pointStyle: pointStyle,
11246 hidden: !chart.getDataVisibility(i),
11247 index: i
11248 };
11249 });
11250 }
11251 return [];
11252 }
11253 },
11254 onClick (e, legendItem, legend) {
11255 legend.chart.toggleDataVisibility(legendItem.index);
11256 legend.chart.update();
11257 }
11258 }
11259 },
11260 scales: {
11261 r: {
11262 type: 'radialLinear',
11263 angleLines: {
11264 display: false
11265 },
11266 beginAtZero: true,
11267 grid: {
11268 circular: true
11269 },
11270 pointLabels: {
11271 display: false
11272 },
11273 startAngle: 0
11274 }
11275 }
11276 };
11277 constructor(chart, datasetIndex){
11278 super(chart, datasetIndex);
11279 this.innerRadius = undefined;
11280 this.outerRadius = undefined;
11281 }
11282 getLabelAndValue(index) {
11283 const meta = this._cachedMeta;
11284 const chart = this.chart;
11285 const labels = chart.data.labels || [];
11286 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index].r, chart.options.locale);
11287 return {
11288 label: labels[index] || '',
11289 value
11290 };
11291 }
11292 parseObjectData(meta, data, start, count) {
11293 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11294 }
11295 update(mode) {
11296 const arcs = this._cachedMeta.data;
11297 this._updateRadius();
11298 this.updateElements(arcs, 0, arcs.length, mode);
11299 }
11300 getMinMax() {
11301 const meta = this._cachedMeta;
11302 const range = {
11303 min: Number.POSITIVE_INFINITY,
11304 max: Number.NEGATIVE_INFINITY
11305 };
11306 meta.data.forEach((element, index)=>{
11307 const parsed = this.getParsed(index).r;
11308 if (!isNaN(parsed) && this.chart.getDataVisibility(index)) {
11309 if (parsed < range.min) {
11310 range.min = parsed;
11311 }
11312 if (parsed > range.max) {
11313 range.max = parsed;
11314 }
11315 }
11316 });
11317 return range;
11318 }
11319 _updateRadius() {
11320 const chart = this.chart;
11321 const chartArea = chart.chartArea;
11322 const opts = chart.options;
11323 const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
11324 const outerRadius = Math.max(minSize / 2, 0);
11325 const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0);
11326 const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
11327 this.outerRadius = outerRadius - radiusLength * this.index;
11328 this.innerRadius = this.outerRadius - radiusLength;
11329 }
11330 updateElements(arcs, start, count, mode) {
11331 const reset = mode === 'reset';
11332 const chart = this.chart;
11333 const opts = chart.options;
11334 const animationOpts = opts.animation;
11335 const scale = this._cachedMeta.rScale;
11336 const centerX = scale.xCenter;
11337 const centerY = scale.yCenter;
11338 const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P;
11339 let angle = datasetStartAngle;
11340 let i;
11341 const defaultAngle = 360 / this.countVisibleElements();
11342 for(i = 0; i < start; ++i){
11343 angle += this._computeAngle(i, mode, defaultAngle);
11344 }
11345 for(i = start; i < start + count; i++){
11346 const arc = arcs[i];
11347 let startAngle = angle;
11348 let endAngle = angle + this._computeAngle(i, mode, defaultAngle);
11349 let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0;
11350 angle = endAngle;
11351 if (reset) {
11352 if (animationOpts.animateScale) {
11353 outerRadius = 0;
11354 }
11355 if (animationOpts.animateRotate) {
11356 startAngle = endAngle = datasetStartAngle;
11357 }
11358 }
11359 const properties = {
11360 x: centerX,
11361 y: centerY,
11362 innerRadius: 0,
11363 outerRadius,
11364 startAngle,
11365 endAngle,
11366 options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)
11367 };
11368 this.updateElement(arc, i, properties, mode);
11369 }
11370 }
11371 countVisibleElements() {
11372 const meta = this._cachedMeta;
11373 let count = 0;
11374 meta.data.forEach((element, index)=>{
11375 if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) {
11376 count++;
11377 }
11378 });
11379 return count;
11380 }
11381 _computeAngle(index, mode, defaultAngle) {
11382 return this.chart.getDataVisibility(index) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0;
11383 }
11384 }
11385
11386 class PieController extends DoughnutController {
11387 static id = 'pie';
11388 static defaults = {
11389 cutout: 0,
11390 rotation: 0,
11391 circumference: 360,
11392 radius: '100%'
11393 };
11394 }
11395
11396 class RadarController extends DatasetController {
11397 static id = 'radar';
11398 static defaults = {
11399 datasetElementType: 'line',
11400 dataElementType: 'point',
11401 indexAxis: 'r',
11402 showLine: true,
11403 elements: {
11404 line: {
11405 fill: 'start'
11406 }
11407 }
11408 };
11409 static overrides = {
11410 aspectRatio: 1,
11411 scales: {
11412 r: {
11413 type: 'radialLinear'
11414 }
11415 }
11416 };
11417 getLabelAndValue(index) {
11418 const vScale = this._cachedMeta.vScale;
11419 const parsed = this.getParsed(index);
11420 return {
11421 label: vScale.getLabels()[index],
11422 value: '' + vScale.getLabelForValue(parsed[vScale.axis])
11423 };
11424 }
11425 parseObjectData(meta, data, start, count) {
11426 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11427 }
11428 update(mode) {
11429 const meta = this._cachedMeta;
11430 const line = meta.dataset;
11431 const points = meta.data || [];
11432 const labels = meta.iScale.getLabels();
11433 line.points = points;
11434 if (mode !== 'resize') {
11435 const options = this.resolveDatasetElementOptions(mode);
11436 if (!this.options.showLine) {
11437 options.borderWidth = 0;
11438 }
11439 const properties = {
11440 _loop: true,
11441 _fullLoop: labels.length === points.length,
11442 options
11443 };
11444 this.updateElement(line, undefined, properties, mode);
11445 }
11446 this.updateElements(points, 0, points.length, mode);
11447 }
11448 updateElements(points, start, count, mode) {
11449 const scale = this._cachedMeta.rScale;
11450 const reset = mode === 'reset';
11451 for(let i = start; i < start + count; i++){
11452 const point = points[i];
11453 const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11454 const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r);
11455 const x = reset ? scale.xCenter : pointPosition.x;
11456 const y = reset ? scale.yCenter : pointPosition.y;
11457 const properties = {
11458 x,
11459 y,
11460 angle: pointPosition.angle,
11461 skip: isNaN(x) || isNaN(y),
11462 options
11463 };
11464 this.updateElement(point, i, properties, mode);
11465 }
11466 }
11467 }
11468
11469 class ScatterController extends DatasetController {
11470 static id = 'scatter';
11471 static defaults = {
11472 datasetElementType: false,
11473 dataElementType: 'point',
11474 showLine: false,
11475 fill: false
11476 };
11477 static overrides = {
11478 interaction: {
11479 mode: 'point'
11480 },
11481 scales: {
11482 x: {
11483 type: 'linear'
11484 },
11485 y: {
11486 type: 'linear'
11487 }
11488 }
11489 };
11490 getLabelAndValue(index) {
11491 const meta = this._cachedMeta;
11492 const labels = this.chart.data.labels || [];
11493 const { xScale , yScale } = meta;
11494 const parsed = this.getParsed(index);
11495 const x = xScale.getLabelForValue(parsed.x);
11496 const y = yScale.getLabelForValue(parsed.y);
11497 return {
11498 label: labels[index] || '',
11499 value: '(' + x + ', ' + y + ')'
11500 };
11501 }
11502 update(mode) {
11503 const meta = this._cachedMeta;
11504 const { data: points = [] } = meta;
11505 const animationsDisabled = this.chart._animationsDisabled;
11506 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11507 this._drawStart = start;
11508 this._drawCount = count;
11509 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11510 start = 0;
11511 count = points.length;
11512 }
11513 if (this.options.showLine) {
11514 if (!this.datasetElementType) {
11515 this.addElements();
11516 }
11517 const { dataset: line , _dataset } = meta;
11518 line._chart = this.chart;
11519 line._datasetIndex = this.index;
11520 line._decimated = !!_dataset._decimated;
11521 line.points = points;
11522 const options = this.resolveDatasetElementOptions(mode);
11523 options.segment = this.options.segment;
11524 this.updateElement(line, undefined, {
11525 animated: !animationsDisabled,
11526 options
11527 }, mode);
11528 } else if (this.datasetElementType) {
11529 delete meta.dataset;
11530 this.datasetElementType = false;
11531 }
11532 this.updateElements(points, start, count, mode);
11533 }
11534 addElements() {
11535 const { showLine } = this.options;
11536 if (!this.datasetElementType && showLine) {
11537 this.datasetElementType = this.chart.registry.getElement('line');
11538 }
11539 super.addElements();
11540 }
11541 updateElements(points, start, count, mode) {
11542 const reset = mode === 'reset';
11543 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11544 const firstOpts = this.resolveDataElementOptions(start, mode);
11545 const sharedOptions = this.getSharedOptions(firstOpts);
11546 const includeOptions = this.includeOptions(mode, sharedOptions);
11547 const iAxis = iScale.axis;
11548 const vAxis = vScale.axis;
11549 const { spanGaps , segment } = this.options;
11550 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11551 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11552 let prevParsed = start > 0 && this.getParsed(start - 1);
11553 for(let i = start; i < start + count; ++i){
11554 const point = points[i];
11555 const parsed = this.getParsed(i);
11556 const properties = directUpdate ? point : {};
11557 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11558 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11559 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11560 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11561 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11562 if (segment) {
11563 properties.parsed = parsed;
11564 properties.raw = _dataset.data[i];
11565 }
11566 if (includeOptions) {
11567 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11568 }
11569 if (!directUpdate) {
11570 this.updateElement(point, i, properties, mode);
11571 }
11572 prevParsed = parsed;
11573 }
11574 this.updateSharedOptions(sharedOptions, mode, firstOpts);
11575 }
11576 getMaxOverflow() {
11577 const meta = this._cachedMeta;
11578 const data = meta.data || [];
11579 if (!this.options.showLine) {
11580 let max = 0;
11581 for(let i = data.length - 1; i >= 0; --i){
11582 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
11583 }
11584 return max > 0 && max;
11585 }
11586 const dataset = meta.dataset;
11587 const border = dataset.options && dataset.options.borderWidth || 0;
11588 if (!data.length) {
11589 return border;
11590 }
11591 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11592 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11593 return Math.max(border, firstPoint, lastPoint) / 2;
11594 }
11595 }
11596
11597 var controllers = /*#__PURE__*/Object.freeze({
11598 __proto__: null,
11599 BarController: BarController,
11600 BubbleController: BubbleController,
11601 DoughnutController: DoughnutController,
11602 LineController: LineController,
11603 PieController: PieController,
11604 PolarAreaController: PolarAreaController,
11605 RadarController: RadarController,
11606 ScatterController: ScatterController
11607 });
11608
11609 /**
11610 * @namespace Chart._adapters
11611 * @since 2.8.0
11612 * @private
11613 */ function abstract() {
11614 throw new Error('This method is not implemented: Check that a complete date adapter is provided.');
11615 }
11616 /**
11617 * Date adapter (current used by the time scale)
11618 * @namespace Chart._adapters._date
11619 * @memberof Chart._adapters
11620 * @private
11621 */ class DateAdapterBase {
11622 /**
11623 * Override default date adapter methods.
11624 * Accepts type parameter to define options type.
11625 * @example
11626 * Chart._adapters._date.override<{myAdapterOption: string}>({
11627 * init() {
11628 * console.log(this.options.myAdapterOption);
11629 * }
11630 * })
11631 */ static override(members) {
11632 Object.assign(DateAdapterBase.prototype, members);
11633 }
11634 options;
11635 constructor(options){
11636 this.options = options || {};
11637 }
11638 // eslint-disable-next-line @typescript-eslint/no-empty-function
11639 init() {}
11640 formats() {
11641 return abstract();
11642 }
11643 parse() {
11644 return abstract();
11645 }
11646 format() {
11647 return abstract();
11648 }
11649 add() {
11650 return abstract();
11651 }
11652 diff() {
11653 return abstract();
11654 }
11655 startOf() {
11656 return abstract();
11657 }
11658 endOf() {
11659 return abstract();
11660 }
11661 }
11662 var adapters = {
11663 _date: DateAdapterBase
11664 };
11665
11666 function binarySearch(metaset, axis, value, intersect) {
11667 const { controller , data , _sorted } = metaset;
11668 const iScale = controller._cachedMeta.iScale;
11669 const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null;
11670 if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
11671 const lookupMethod = iScale._reversePixels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.A : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B;
11672 if (!intersect) {
11673 const result = lookupMethod(data, axis, value);
11674 if (spanGaps) {
11675 const { vScale } = controller._cachedMeta;
11676 const { _parsed } = metaset;
11677 const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11678 result.lo -= Math.max(0, distanceToDefinedLo);
11679 const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11680 result.hi += Math.max(0, distanceToDefinedHi);
11681 }
11682 return result;
11683 } else if (controller._sharedOptions) {
11684 const el = data[0];
11685 const range = typeof el.getRange === 'function' && el.getRange(axis);
11686 if (range) {
11687 const start = lookupMethod(data, axis, value - range);
11688 const end = lookupMethod(data, axis, value + range);
11689 return {
11690 lo: start.lo,
11691 hi: end.hi
11692 };
11693 }
11694 }
11695 }
11696 return {
11697 lo: 0,
11698 hi: data.length - 1
11699 };
11700 }
11701 function evaluateInteractionItems(chart, axis, position, handler, intersect) {
11702 const metasets = chart.getSortedVisibleDatasetMetas();
11703 const value = position[axis];
11704 for(let i = 0, ilen = metasets.length; i < ilen; ++i){
11705 const { index , data } = metasets[i];
11706 const { lo , hi } = binarySearch(metasets[i], axis, value, intersect);
11707 for(let j = lo; j <= hi; ++j){
11708 const element = data[j];
11709 if (!element.skip) {
11710 handler(element, index, j);
11711 }
11712 }
11713 }
11714 }
11715 function getDistanceMetricForAxis(axis) {
11716 const useX = axis.indexOf('x') !== -1;
11717 const useY = axis.indexOf('y') !== -1;
11718 return function(pt1, pt2) {
11719 const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
11720 const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
11721 return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
11722 };
11723 }
11724 function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {
11725 const items = [];
11726 if (!includeInvisible && !chart.isPointInArea(position)) {
11727 return items;
11728 }
11729 const evaluationFunc = function(element, datasetIndex, index) {
11730 if (!includeInvisible && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(element, chart.chartArea, 0)) {
11731 return;
11732 }
11733 if (element.inRange(position.x, position.y, useFinalPosition)) {
11734 items.push({
11735 element,
11736 datasetIndex,
11737 index
11738 });
11739 }
11740 };
11741 evaluateInteractionItems(chart, axis, position, evaluationFunc, true);
11742 return items;
11743 }
11744 function getNearestRadialItems(chart, position, axis, useFinalPosition) {
11745 let items = [];
11746 function evaluationFunc(element, datasetIndex, index) {
11747 const { startAngle , endAngle } = element.getProps([
11748 'startAngle',
11749 'endAngle'
11750 ], useFinalPosition);
11751 const { angle } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(element, {
11752 x: position.x,
11753 y: position.y
11754 });
11755 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle)) {
11756 items.push({
11757 element,
11758 datasetIndex,
11759 index
11760 });
11761 }
11762 }
11763 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11764 return items;
11765 }
11766 function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11767 let items = [];
11768 const distanceMetric = getDistanceMetricForAxis(axis);
11769 let minDistance = Number.POSITIVE_INFINITY;
11770 function evaluationFunc(element, datasetIndex, index) {
11771 const inRange = element.inRange(position.x, position.y, useFinalPosition);
11772 if (intersect && !inRange) {
11773 return;
11774 }
11775 const center = element.getCenterPoint(useFinalPosition);
11776 const pointInArea = !!includeInvisible || chart.isPointInArea(center);
11777 if (!pointInArea && !inRange) {
11778 return;
11779 }
11780 const distance = distanceMetric(position, center);
11781 if (distance < minDistance) {
11782 items = [
11783 {
11784 element,
11785 datasetIndex,
11786 index
11787 }
11788 ];
11789 minDistance = distance;
11790 } else if (distance === minDistance) {
11791 items.push({
11792 element,
11793 datasetIndex,
11794 index
11795 });
11796 }
11797 }
11798 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11799 return items;
11800 }
11801 function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11802 if (!includeInvisible && !chart.isPointInArea(position)) {
11803 return [];
11804 }
11805 return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);
11806 }
11807 function getAxisItems(chart, position, axis, intersect, useFinalPosition) {
11808 const items = [];
11809 const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
11810 let intersectsItem = false;
11811 evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{
11812 if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {
11813 items.push({
11814 element,
11815 datasetIndex,
11816 index
11817 });
11818 intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);
11819 }
11820 });
11821 if (intersect && !intersectsItem) {
11822 return [];
11823 }
11824 return items;
11825 }
11826 var Interaction = {
11827 evaluateInteractionItems,
11828 modes: {
11829 index (chart, e, options, useFinalPosition) {
11830 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11831 const axis = options.axis || 'x';
11832 const includeInvisible = options.includeInvisible || false;
11833 const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11834 const elements = [];
11835 if (!items.length) {
11836 return [];
11837 }
11838 chart.getSortedVisibleDatasetMetas().forEach((meta)=>{
11839 const index = items[0].index;
11840 const element = meta.data[index];
11841 if (element && !element.skip) {
11842 elements.push({
11843 element,
11844 datasetIndex: meta.index,
11845 index
11846 });
11847 }
11848 });
11849 return elements;
11850 },
11851 dataset (chart, e, options, useFinalPosition) {
11852 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11853 const axis = options.axis || 'xy';
11854 const includeInvisible = options.includeInvisible || false;
11855 let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11856 if (items.length > 0) {
11857 const datasetIndex = items[0].datasetIndex;
11858 const data = chart.getDatasetMeta(datasetIndex).data;
11859 items = [];
11860 for(let i = 0; i < data.length; ++i){
11861 items.push({
11862 element: data[i],
11863 datasetIndex,
11864 index: i
11865 });
11866 }
11867 }
11868 return items;
11869 },
11870 point (chart, e, options, useFinalPosition) {
11871 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11872 const axis = options.axis || 'xy';
11873 const includeInvisible = options.includeInvisible || false;
11874 return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);
11875 },
11876 nearest (chart, e, options, useFinalPosition) {
11877 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11878 const axis = options.axis || 'xy';
11879 const includeInvisible = options.includeInvisible || false;
11880 return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);
11881 },
11882 x (chart, e, options, useFinalPosition) {
11883 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11884 return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition);
11885 },
11886 y (chart, e, options, useFinalPosition) {
11887 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11888 return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition);
11889 }
11890 }
11891 };
11892
11893 const STATIC_POSITIONS = [
11894 'left',
11895 'top',
11896 'right',
11897 'bottom'
11898 ];
11899 function filterByPosition(array, position) {
11900 return array.filter((v)=>v.pos === position);
11901 }
11902 function filterDynamicPositionByAxis(array, axis) {
11903 return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
11904 }
11905 function sortByWeight(array, reverse) {
11906 return array.sort((a, b)=>{
11907 const v0 = reverse ? b : a;
11908 const v1 = reverse ? a : b;
11909 return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;
11910 });
11911 }
11912 function wrapBoxes(boxes) {
11913 const layoutBoxes = [];
11914 let i, ilen, box, pos, stack, stackWeight;
11915 for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){
11916 box = boxes[i];
11917 ({ position: pos , options: { stack , stackWeight =1 } } = box);
11918 layoutBoxes.push({
11919 index: i,
11920 box,
11921 pos,
11922 horizontal: box.isHorizontal(),
11923 weight: box.weight,
11924 stack: stack && pos + stack,
11925 stackWeight
11926 });
11927 }
11928 return layoutBoxes;
11929 }
11930 function buildStacks(layouts) {
11931 const stacks = {};
11932 for (const wrap of layouts){
11933 const { stack , pos , stackWeight } = wrap;
11934 if (!stack || !STATIC_POSITIONS.includes(pos)) {
11935 continue;
11936 }
11937 const _stack = stacks[stack] || (stacks[stack] = {
11938 count: 0,
11939 placed: 0,
11940 weight: 0,
11941 size: 0
11942 });
11943 _stack.count++;
11944 _stack.weight += stackWeight;
11945 }
11946 return stacks;
11947 }
11948 function setLayoutDims(layouts, params) {
11949 const stacks = buildStacks(layouts);
11950 const { vBoxMaxWidth , hBoxMaxHeight } = params;
11951 let i, ilen, layout;
11952 for(i = 0, ilen = layouts.length; i < ilen; ++i){
11953 layout = layouts[i];
11954 const { fullSize } = layout.box;
11955 const stack = stacks[layout.stack];
11956 const factor = stack && layout.stackWeight / stack.weight;
11957 if (layout.horizontal) {
11958 layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
11959 layout.height = hBoxMaxHeight;
11960 } else {
11961 layout.width = vBoxMaxWidth;
11962 layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
11963 }
11964 }
11965 return stacks;
11966 }
11967 function buildLayoutBoxes(boxes) {
11968 const layoutBoxes = wrapBoxes(boxes);
11969 const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true);
11970 const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
11971 const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
11972 const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
11973 const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
11974 const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
11975 const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
11976 return {
11977 fullSize,
11978 leftAndTop: left.concat(top),
11979 rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
11980 chartArea: filterByPosition(layoutBoxes, 'chartArea'),
11981 vertical: left.concat(right).concat(centerVertical),
11982 horizontal: top.concat(bottom).concat(centerHorizontal)
11983 };
11984 }
11985 function getCombinedMax(maxPadding, chartArea, a, b) {
11986 return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
11987 }
11988 function updateMaxPadding(maxPadding, boxPadding) {
11989 maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
11990 maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
11991 maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
11992 maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
11993 }
11994 function updateDims(chartArea, params, layout, stacks) {
11995 const { pos , box } = layout;
11996 const maxPadding = chartArea.maxPadding;
11997 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(pos)) {
11998 if (layout.size) {
11999 chartArea[pos] -= layout.size;
12000 }
12001 const stack = stacks[layout.stack] || {
12002 size: 0,
12003 count: 1
12004 };
12005 stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
12006 layout.size = stack.size / stack.count;
12007 chartArea[pos] += layout.size;
12008 }
12009 if (box.getPadding) {
12010 updateMaxPadding(maxPadding, box.getPadding());
12011 }
12012 const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
12013 const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
12014 const widthChanged = newWidth !== chartArea.w;
12015 const heightChanged = newHeight !== chartArea.h;
12016 chartArea.w = newWidth;
12017 chartArea.h = newHeight;
12018 return layout.horizontal ? {
12019 same: widthChanged,
12020 other: heightChanged
12021 } : {
12022 same: heightChanged,
12023 other: widthChanged
12024 };
12025 }
12026 function handleMaxPadding(chartArea) {
12027 const maxPadding = chartArea.maxPadding;
12028 function updatePos(pos) {
12029 const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
12030 chartArea[pos] += change;
12031 return change;
12032 }
12033 chartArea.y += updatePos('top');
12034 chartArea.x += updatePos('left');
12035 updatePos('right');
12036 updatePos('bottom');
12037 }
12038 function getMargins(horizontal, chartArea) {
12039 const maxPadding = chartArea.maxPadding;
12040 function marginForPositions(positions) {
12041 const margin = {
12042 left: 0,
12043 top: 0,
12044 right: 0,
12045 bottom: 0
12046 };
12047 positions.forEach((pos)=>{
12048 margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
12049 });
12050 return margin;
12051 }
12052 return horizontal ? marginForPositions([
12053 'left',
12054 'right'
12055 ]) : marginForPositions([
12056 'top',
12057 'bottom'
12058 ]);
12059 }
12060 function fitBoxes(boxes, chartArea, params, stacks) {
12061 const refitBoxes = [];
12062 let i, ilen, layout, box, refit, changed;
12063 for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){
12064 layout = boxes[i];
12065 box = layout.box;
12066 box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));
12067 const { same , other } = updateDims(chartArea, params, layout, stacks);
12068 refit |= same && refitBoxes.length;
12069 changed = changed || other;
12070 if (!box.fullSize) {
12071 refitBoxes.push(layout);
12072 }
12073 }
12074 return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
12075 }
12076 function setBoxDims(box, left, top, width, height) {
12077 box.top = top;
12078 box.left = left;
12079 box.right = left + width;
12080 box.bottom = top + height;
12081 box.width = width;
12082 box.height = height;
12083 }
12084 function placeBoxes(boxes, chartArea, params, stacks) {
12085 const userPadding = params.padding;
12086 let { x , y } = chartArea;
12087 for (const layout of boxes){
12088 const box = layout.box;
12089 const stack = stacks[layout.stack] || {
12090 count: 1,
12091 placed: 0,
12092 weight: 1
12093 };
12094 const weight = layout.stackWeight / stack.weight || 1;
12095 if (layout.horizontal) {
12096 const width = chartArea.w * weight;
12097 const height = stack.size || box.height;
12098 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12099 y = stack.start;
12100 }
12101 if (box.fullSize) {
12102 setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);
12103 } else {
12104 setBoxDims(box, chartArea.left + stack.placed, y, width, height);
12105 }
12106 stack.start = y;
12107 stack.placed += width;
12108 y = box.bottom;
12109 } else {
12110 const height = chartArea.h * weight;
12111 const width = stack.size || box.width;
12112 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12113 x = stack.start;
12114 }
12115 if (box.fullSize) {
12116 setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
12117 } else {
12118 setBoxDims(box, x, chartArea.top + stack.placed, width, height);
12119 }
12120 stack.start = x;
12121 stack.placed += height;
12122 x = box.right;
12123 }
12124 }
12125 chartArea.x = x;
12126 chartArea.y = y;
12127 }
12128 var layouts = {
12129 addBox (chart, item) {
12130 if (!chart.boxes) {
12131 chart.boxes = [];
12132 }
12133 item.fullSize = item.fullSize || false;
12134 item.position = item.position || 'top';
12135 item.weight = item.weight || 0;
12136 item._layers = item._layers || function() {
12137 return [
12138 {
12139 z: 0,
12140 draw (chartArea) {
12141 item.draw(chartArea);
12142 }
12143 }
12144 ];
12145 };
12146 chart.boxes.push(item);
12147 },
12148 removeBox (chart, layoutItem) {
12149 const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
12150 if (index !== -1) {
12151 chart.boxes.splice(index, 1);
12152 }
12153 },
12154 configure (chart, item, options) {
12155 item.fullSize = options.fullSize;
12156 item.position = options.position;
12157 item.weight = options.weight;
12158 },
12159 update (chart, width, height, minPadding) {
12160 if (!chart) {
12161 return;
12162 }
12163 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(chart.options.layout.padding);
12164 const availableWidth = Math.max(width - padding.width, 0);
12165 const availableHeight = Math.max(height - padding.height, 0);
12166 const boxes = buildLayoutBoxes(chart.boxes);
12167 const verticalBoxes = boxes.vertical;
12168 const horizontalBoxes = boxes.horizontal;
12169 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(chart.boxes, (box)=>{
12170 if (typeof box.beforeLayout === 'function') {
12171 box.beforeLayout();
12172 }
12173 });
12174 const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
12175 const params = Object.freeze({
12176 outerWidth: width,
12177 outerHeight: height,
12178 padding,
12179 availableWidth,
12180 availableHeight,
12181 vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
12182 hBoxMaxHeight: availableHeight / 2
12183 });
12184 const maxPadding = Object.assign({}, padding);
12185 updateMaxPadding(maxPadding, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(minPadding));
12186 const chartArea = Object.assign({
12187 maxPadding,
12188 w: availableWidth,
12189 h: availableHeight,
12190 x: padding.left,
12191 y: padding.top
12192 }, padding);
12193 const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
12194 fitBoxes(boxes.fullSize, chartArea, params, stacks);
12195 fitBoxes(verticalBoxes, chartArea, params, stacks);
12196 if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
12197 fitBoxes(verticalBoxes, chartArea, params, stacks);
12198 }
12199 handleMaxPadding(chartArea);
12200 placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
12201 chartArea.x += chartArea.w;
12202 chartArea.y += chartArea.h;
12203 placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
12204 chart.chartArea = {
12205 left: chartArea.left,
12206 top: chartArea.top,
12207 right: chartArea.left + chartArea.w,
12208 bottom: chartArea.top + chartArea.h,
12209 height: chartArea.h,
12210 width: chartArea.w
12211 };
12212 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(boxes.chartArea, (layout)=>{
12213 const box = layout.box;
12214 Object.assign(box, chart.chartArea);
12215 box.update(chartArea.w, chartArea.h, {
12216 left: 0,
12217 top: 0,
12218 right: 0,
12219 bottom: 0
12220 });
12221 });
12222 }
12223 };
12224
12225 class BasePlatform {
12226 acquireContext(canvas, aspectRatio) {}
12227 releaseContext(context) {
12228 return false;
12229 }
12230 addEventListener(chart, type, listener) {}
12231 removeEventListener(chart, type, listener) {}
12232 getDevicePixelRatio() {
12233 return 1;
12234 }
12235 getMaximumSize(element, width, height, aspectRatio) {
12236 width = Math.max(0, width || element.width);
12237 height = height || element.height;
12238 return {
12239 width,
12240 height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
12241 };
12242 }
12243 isAttached(canvas) {
12244 return true;
12245 }
12246 updateConfig(config) {
12247 }
12248 }
12249
12250 class BasicPlatform extends BasePlatform {
12251 acquireContext(item) {
12252 return item && item.getContext && item.getContext('2d') || null;
12253 }
12254 updateConfig(config) {
12255 config.options.animation = false;
12256 }
12257 }
12258
12259 const EXPANDO_KEY = '$chartjs';
12260 const EVENT_TYPES = {
12261 touchstart: 'mousedown',
12262 touchmove: 'mousemove',
12263 touchend: 'mouseup',
12264 pointerenter: 'mouseenter',
12265 pointerdown: 'mousedown',
12266 pointermove: 'mousemove',
12267 pointerup: 'mouseup',
12268 pointerleave: 'mouseout',
12269 pointerout: 'mouseout'
12270 };
12271 const isNullOrEmpty = (value)=>value === null || value === '';
12272 function initCanvas(canvas, aspectRatio) {
12273 const style = canvas.style;
12274 const renderHeight = canvas.getAttribute('height');
12275 const renderWidth = canvas.getAttribute('width');
12276 canvas[EXPANDO_KEY] = {
12277 initial: {
12278 height: renderHeight,
12279 width: renderWidth,
12280 style: {
12281 display: style.display,
12282 height: style.height,
12283 width: style.width
12284 }
12285 }
12286 };
12287 style.display = style.display || 'block';
12288 style.boxSizing = style.boxSizing || 'border-box';
12289 if (isNullOrEmpty(renderWidth)) {
12290 const displayWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'width');
12291 if (displayWidth !== undefined) {
12292 canvas.width = displayWidth;
12293 }
12294 }
12295 if (isNullOrEmpty(renderHeight)) {
12296 if (canvas.style.height === '') {
12297 canvas.height = canvas.width / (aspectRatio || 2);
12298 } else {
12299 const displayHeight = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'height');
12300 if (displayHeight !== undefined) {
12301 canvas.height = displayHeight;
12302 }
12303 }
12304 }
12305 return canvas;
12306 }
12307 const eventListenerOptions = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.K ? {
12308 passive: true
12309 } : false;
12310 function addListener(node, type, listener) {
12311 if (node) {
12312 node.addEventListener(type, listener, eventListenerOptions);
12313 }
12314 }
12315 function removeListener(chart, type, listener) {
12316 if (chart && chart.canvas) {
12317 chart.canvas.removeEventListener(type, listener, eventListenerOptions);
12318 }
12319 }
12320 function fromNativeEvent(event, chart) {
12321 const type = EVENT_TYPES[event.type] || event.type;
12322 const { x , y } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(event, chart);
12323 return {
12324 type,
12325 chart,
12326 native: event,
12327 x: x !== undefined ? x : null,
12328 y: y !== undefined ? y : null
12329 };
12330 }
12331 function nodeListContains(nodeList, canvas) {
12332 for (const node of nodeList){
12333 if (node === canvas || node.contains(canvas)) {
12334 return true;
12335 }
12336 }
12337 }
12338 function createAttachObserver(chart, type, listener) {
12339 const canvas = chart.canvas;
12340 const observer = new MutationObserver((entries)=>{
12341 let trigger = false;
12342 for (const entry of entries){
12343 trigger = trigger || nodeListContains(entry.addedNodes, canvas);
12344 trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
12345 }
12346 if (trigger) {
12347 listener();
12348 }
12349 });
12350 observer.observe(document, {
12351 childList: true,
12352 subtree: true
12353 });
12354 return observer;
12355 }
12356 function createDetachObserver(chart, type, listener) {
12357 const canvas = chart.canvas;
12358 const observer = new MutationObserver((entries)=>{
12359 let trigger = false;
12360 for (const entry of entries){
12361 trigger = trigger || nodeListContains(entry.removedNodes, canvas);
12362 trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
12363 }
12364 if (trigger) {
12365 listener();
12366 }
12367 });
12368 observer.observe(document, {
12369 childList: true,
12370 subtree: true
12371 });
12372 return observer;
12373 }
12374 const drpListeningCharts = new Map();
12375 let oldDevicePixelRatio = 0;
12376 function onWindowResize() {
12377 const dpr = window.devicePixelRatio;
12378 if (dpr === oldDevicePixelRatio) {
12379 return;
12380 }
12381 oldDevicePixelRatio = dpr;
12382 drpListeningCharts.forEach((resize, chart)=>{
12383 if (chart.currentDevicePixelRatio !== dpr) {
12384 resize();
12385 }
12386 });
12387 }
12388 function listenDevicePixelRatioChanges(chart, resize) {
12389 if (!drpListeningCharts.size) {
12390 window.addEventListener('resize', onWindowResize);
12391 }
12392 drpListeningCharts.set(chart, resize);
12393 }
12394 function unlistenDevicePixelRatioChanges(chart) {
12395 drpListeningCharts.delete(chart);
12396 if (!drpListeningCharts.size) {
12397 window.removeEventListener('resize', onWindowResize);
12398 }
12399 }
12400 function createResizeObserver(chart, type, listener) {
12401 const canvas = chart.canvas;
12402 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12403 if (!container) {
12404 return;
12405 }
12406 const resize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((width, height)=>{
12407 const w = container.clientWidth;
12408 listener(width, height);
12409 if (w < container.clientWidth) {
12410 listener();
12411 }
12412 }, window);
12413 const observer = new ResizeObserver((entries)=>{
12414 const entry = entries[0];
12415 const width = entry.contentRect.width;
12416 const height = entry.contentRect.height;
12417 if (width === 0 && height === 0) {
12418 return;
12419 }
12420 resize(width, height);
12421 });
12422 observer.observe(container);
12423 listenDevicePixelRatioChanges(chart, resize);
12424 return observer;
12425 }
12426 function releaseObserver(chart, type, observer) {
12427 if (observer) {
12428 observer.disconnect();
12429 }
12430 if (type === 'resize') {
12431 unlistenDevicePixelRatioChanges(chart);
12432 }
12433 }
12434 function createProxyAndListen(chart, type, listener) {
12435 const canvas = chart.canvas;
12436 const proxy = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((event)=>{
12437 if (chart.ctx !== null) {
12438 listener(fromNativeEvent(event, chart));
12439 }
12440 }, chart);
12441 addListener(canvas, type, proxy);
12442 return proxy;
12443 }
12444 class DomPlatform extends BasePlatform {
12445 acquireContext(canvas, aspectRatio) {
12446 const context = canvas && canvas.getContext && canvas.getContext('2d');
12447 if (context && context.canvas === canvas) {
12448 initCanvas(canvas, aspectRatio);
12449 return context;
12450 }
12451 return null;
12452 }
12453 releaseContext(context) {
12454 const canvas = context.canvas;
12455 if (!canvas[EXPANDO_KEY]) {
12456 return false;
12457 }
12458 const initial = canvas[EXPANDO_KEY].initial;
12459 [
12460 'height',
12461 'width'
12462 ].forEach((prop)=>{
12463 const value = initial[prop];
12464 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
12465 canvas.removeAttribute(prop);
12466 } else {
12467 canvas.setAttribute(prop, value);
12468 }
12469 });
12470 const style = initial.style || {};
12471 Object.keys(style).forEach((key)=>{
12472 canvas.style[key] = style[key];
12473 });
12474 canvas.width = canvas.width;
12475 delete canvas[EXPANDO_KEY];
12476 return true;
12477 }
12478 addEventListener(chart, type, listener) {
12479 this.removeEventListener(chart, type);
12480 const proxies = chart.$proxies || (chart.$proxies = {});
12481 const handlers = {
12482 attach: createAttachObserver,
12483 detach: createDetachObserver,
12484 resize: createResizeObserver
12485 };
12486 const handler = handlers[type] || createProxyAndListen;
12487 proxies[type] = handler(chart, type, listener);
12488 }
12489 removeEventListener(chart, type) {
12490 const proxies = chart.$proxies || (chart.$proxies = {});
12491 const proxy = proxies[type];
12492 if (!proxy) {
12493 return;
12494 }
12495 const handlers = {
12496 attach: releaseObserver,
12497 detach: releaseObserver,
12498 resize: releaseObserver
12499 };
12500 const handler = handlers[type] || removeListener;
12501 handler(chart, type, proxy);
12502 proxies[type] = undefined;
12503 }
12504 getDevicePixelRatio() {
12505 return window.devicePixelRatio;
12506 }
12507 getMaximumSize(canvas, width, height, aspectRatio) {
12508 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.G)(canvas, width, height, aspectRatio);
12509 }
12510 isAttached(canvas) {
12511 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12512 return !!(container && container.isConnected);
12513 }
12514 }
12515
12516 function _detectPlatform(canvas) {
12517 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
12518 return BasicPlatform;
12519 }
12520 return DomPlatform;
12521 }
12522
12523 class Element {
12524 static defaults = {};
12525 static defaultRoutes = undefined;
12526 x;
12527 y;
12528 active = false;
12529 options;
12530 $animations;
12531 tooltipPosition(useFinalPosition) {
12532 const { x , y } = this.getProps([
12533 'x',
12534 'y'
12535 ], useFinalPosition);
12536 return {
12537 x,
12538 y
12539 };
12540 }
12541 hasValue() {
12542 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(this.x) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(this.y);
12543 }
12544 getProps(props, final) {
12545 const anims = this.$animations;
12546 if (!final || !anims) {
12547 // let's not create an object, if not needed
12548 return this;
12549 }
12550 const ret = {};
12551 props.forEach((prop)=>{
12552 ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
12553 });
12554 return ret;
12555 }
12556 }
12557
12558 function autoSkip(scale, ticks) {
12559 const tickOpts = scale.options.ticks;
12560 const determinedMaxTicks = determineMaxTicks(scale);
12561 const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);
12562 const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
12563 const numMajorIndices = majorIndices.length;
12564 const first = majorIndices[0];
12565 const last = majorIndices[numMajorIndices - 1];
12566 const newTicks = [];
12567 if (numMajorIndices > ticksLimit) {
12568 skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
12569 return newTicks;
12570 }
12571 const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
12572 if (numMajorIndices > 0) {
12573 let i, ilen;
12574 const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
12575 skip(ticks, newTicks, spacing, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
12576 for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){
12577 skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
12578 }
12579 skip(ticks, newTicks, spacing, last, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
12580 return newTicks;
12581 }
12582 skip(ticks, newTicks, spacing);
12583 return newTicks;
12584 }
12585 function determineMaxTicks(scale) {
12586 const offset = scale.options.offset;
12587 const tickLength = scale._tickSize();
12588 const maxScale = scale._length / tickLength + (offset ? 0 : 1);
12589 const maxChart = scale._maxLength / tickLength;
12590 return Math.floor(Math.min(maxScale, maxChart));
12591 }
12592 function calculateSpacing(majorIndices, ticks, ticksLimit) {
12593 const evenMajorSpacing = getEvenSpacing(majorIndices);
12594 const spacing = ticks.length / ticksLimit;
12595 if (!evenMajorSpacing) {
12596 return Math.max(spacing, 1);
12597 }
12598 const factors = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.N)(evenMajorSpacing);
12599 for(let i = 0, ilen = factors.length - 1; i < ilen; i++){
12600 const factor = factors[i];
12601 if (factor > spacing) {
12602 return factor;
12603 }
12604 }
12605 return Math.max(spacing, 1);
12606 }
12607 function getMajorIndices(ticks) {
12608 const result = [];
12609 let i, ilen;
12610 for(i = 0, ilen = ticks.length; i < ilen; i++){
12611 if (ticks[i].major) {
12612 result.push(i);
12613 }
12614 }
12615 return result;
12616 }
12617 function skipMajors(ticks, newTicks, majorIndices, spacing) {
12618 let count = 0;
12619 let next = majorIndices[0];
12620 let i;
12621 spacing = Math.ceil(spacing);
12622 for(i = 0; i < ticks.length; i++){
12623 if (i === next) {
12624 newTicks.push(ticks[i]);
12625 count++;
12626 next = majorIndices[count * spacing];
12627 }
12628 }
12629 }
12630 function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
12631 const start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorStart, 0);
12632 const end = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorEnd, ticks.length), ticks.length);
12633 let count = 0;
12634 let length, i, next;
12635 spacing = Math.ceil(spacing);
12636 if (majorEnd) {
12637 length = majorEnd - majorStart;
12638 spacing = length / Math.floor(length / spacing);
12639 }
12640 next = start;
12641 while(next < 0){
12642 count++;
12643 next = Math.round(start + count * spacing);
12644 }
12645 for(i = Math.max(start, 0); i < end; i++){
12646 if (i === next) {
12647 newTicks.push(ticks[i]);
12648 count++;
12649 next = Math.round(start + count * spacing);
12650 }
12651 }
12652 }
12653 function getEvenSpacing(arr) {
12654 const len = arr.length;
12655 let i, diff;
12656 if (len < 2) {
12657 return false;
12658 }
12659 for(diff = arr[0], i = 1; i < len; ++i){
12660 if (arr[i] - arr[i - 1] !== diff) {
12661 return false;
12662 }
12663 }
12664 return diff;
12665 }
12666
12667 const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align;
12668 const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
12669 const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength);
12670 function sample(arr, numItems) {
12671 const result = [];
12672 const increment = arr.length / numItems;
12673 const len = arr.length;
12674 let i = 0;
12675 for(; i < len; i += increment){
12676 result.push(arr[Math.floor(i)]);
12677 }
12678 return result;
12679 }
12680 function getPixelForGridLine(scale, index, offsetGridLines) {
12681 const length = scale.ticks.length;
12682 const validIndex = Math.min(index, length - 1);
12683 const start = scale._startPixel;
12684 const end = scale._endPixel;
12685 const epsilon = 1e-6;
12686 let lineValue = scale.getPixelForTick(validIndex);
12687 let offset;
12688 if (offsetGridLines) {
12689 if (length === 1) {
12690 offset = Math.max(lineValue - start, end - lineValue);
12691 } else if (index === 0) {
12692 offset = (scale.getPixelForTick(1) - lineValue) / 2;
12693 } else {
12694 offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
12695 }
12696 lineValue += validIndex < index ? offset : -offset;
12697 if (lineValue < start - epsilon || lineValue > end + epsilon) {
12698 return;
12699 }
12700 }
12701 return lineValue;
12702 }
12703 function garbageCollect(caches, length) {
12704 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(caches, (cache)=>{
12705 const gc = cache.gc;
12706 const gcLen = gc.length / 2;
12707 let i;
12708 if (gcLen > length) {
12709 for(i = 0; i < gcLen; ++i){
12710 delete cache.data[gc[i]];
12711 }
12712 gc.splice(0, gcLen);
12713 }
12714 });
12715 }
12716 function getTickMarkLength(options) {
12717 return options.drawTicks ? options.tickLength : 0;
12718 }
12719 function getTitleHeight(options, fallback) {
12720 if (!options.display) {
12721 return 0;
12722 }
12723 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.font, fallback);
12724 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
12725 const lines = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(options.text) ? options.text.length : 1;
12726 return lines * font.lineHeight + padding.height;
12727 }
12728 function createScaleContext(parent, scale) {
12729 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12730 scale,
12731 type: 'scale'
12732 });
12733 }
12734 function createTickContext(parent, index, tick) {
12735 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12736 tick,
12737 index,
12738 type: 'tick'
12739 });
12740 }
12741 function titleAlign(align, position, reverse) {
12742 let ret = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(align);
12743 if (reverse && position !== 'right' || !reverse && position === 'right') {
12744 ret = reverseAlign(ret);
12745 }
12746 return ret;
12747 }
12748 function titleArgs(scale, offset, position, align) {
12749 const { top , left , bottom , right , chart } = scale;
12750 const { chartArea , scales } = chart;
12751 let rotation = 0;
12752 let maxWidth, titleX, titleY;
12753 const height = bottom - top;
12754 const width = right - left;
12755 if (scale.isHorizontal()) {
12756 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
12757 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12758 const positionAxisID = Object.keys(position)[0];
12759 const value = position[positionAxisID];
12760 titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
12761 } else if (position === 'center') {
12762 titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
12763 } else {
12764 titleY = offsetFromEdge(scale, position, offset);
12765 }
12766 maxWidth = right - left;
12767 } else {
12768 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12769 const positionAxisID = Object.keys(position)[0];
12770 const value = position[positionAxisID];
12771 titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
12772 } else if (position === 'center') {
12773 titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
12774 } else {
12775 titleX = offsetFromEdge(scale, position, offset);
12776 }
12777 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
12778 rotation = position === 'left' ? -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H;
12779 }
12780 return {
12781 titleX,
12782 titleY,
12783 maxWidth,
12784 rotation
12785 };
12786 }
12787 class Scale extends Element {
12788 constructor(cfg){
12789 super();
12790 this.id = cfg.id;
12791 this.type = cfg.type;
12792 this.options = undefined;
12793 this.ctx = cfg.ctx;
12794 this.chart = cfg.chart;
12795 this.top = undefined;
12796 this.bottom = undefined;
12797 this.left = undefined;
12798 this.right = undefined;
12799 this.width = undefined;
12800 this.height = undefined;
12801 this._margins = {
12802 left: 0,
12803 right: 0,
12804 top: 0,
12805 bottom: 0
12806 };
12807 this.maxWidth = undefined;
12808 this.maxHeight = undefined;
12809 this.paddingTop = undefined;
12810 this.paddingBottom = undefined;
12811 this.paddingLeft = undefined;
12812 this.paddingRight = undefined;
12813 this.axis = undefined;
12814 this.labelRotation = undefined;
12815 this.min = undefined;
12816 this.max = undefined;
12817 this._range = undefined;
12818 this.ticks = [];
12819 this._gridLineItems = null;
12820 this._labelItems = null;
12821 this._labelSizes = null;
12822 this._length = 0;
12823 this._maxLength = 0;
12824 this._longestTextCache = {};
12825 this._startPixel = undefined;
12826 this._endPixel = undefined;
12827 this._reversePixels = false;
12828 this._userMax = undefined;
12829 this._userMin = undefined;
12830 this._suggestedMax = undefined;
12831 this._suggestedMin = undefined;
12832 this._ticksLength = 0;
12833 this._borderValue = 0;
12834 this._cache = {};
12835 this._dataLimitsCached = false;
12836 this.$context = undefined;
12837 }
12838 init(options) {
12839 this.options = options.setContext(this.getContext());
12840 this.axis = options.axis;
12841 this._userMin = this.parse(options.min);
12842 this._userMax = this.parse(options.max);
12843 this._suggestedMin = this.parse(options.suggestedMin);
12844 this._suggestedMax = this.parse(options.suggestedMax);
12845 }
12846 parse(raw, index) {
12847 return raw;
12848 }
12849 getUserBounds() {
12850 let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this;
12851 _userMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, Number.POSITIVE_INFINITY);
12852 _userMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, Number.NEGATIVE_INFINITY);
12853 _suggestedMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMin, Number.POSITIVE_INFINITY);
12854 _suggestedMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMax, Number.NEGATIVE_INFINITY);
12855 return {
12856 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, _suggestedMin),
12857 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, _suggestedMax),
12858 minDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMin),
12859 maxDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMax)
12860 };
12861 }
12862 getMinMax(canStack) {
12863 let { min , max , minDefined , maxDefined } = this.getUserBounds();
12864 let range;
12865 if (minDefined && maxDefined) {
12866 return {
12867 min,
12868 max
12869 };
12870 }
12871 const metas = this.getMatchingVisibleMetas();
12872 for(let i = 0, ilen = metas.length; i < ilen; ++i){
12873 range = metas[i].controller.getMinMax(this, canStack);
12874 if (!minDefined) {
12875 min = Math.min(min, range.min);
12876 }
12877 if (!maxDefined) {
12878 max = Math.max(max, range.max);
12879 }
12880 }
12881 min = maxDefined && min > max ? max : min;
12882 max = minDefined && min > max ? min : max;
12883 return {
12884 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, min)),
12885 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, max))
12886 };
12887 }
12888 getPadding() {
12889 return {
12890 left: this.paddingLeft || 0,
12891 top: this.paddingTop || 0,
12892 right: this.paddingRight || 0,
12893 bottom: this.paddingBottom || 0
12894 };
12895 }
12896 getTicks() {
12897 return this.ticks;
12898 }
12899 getLabels() {
12900 const data = this.chart.data;
12901 return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
12902 }
12903 getLabelItems(chartArea = this.chart.chartArea) {
12904 const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
12905 return items;
12906 }
12907 beforeLayout() {
12908 this._cache = {};
12909 this._dataLimitsCached = false;
12910 }
12911 beforeUpdate() {
12912 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeUpdate, [
12913 this
12914 ]);
12915 }
12916 update(maxWidth, maxHeight, margins) {
12917 const { beginAtZero , grace , ticks: tickOpts } = this.options;
12918 const sampleSize = tickOpts.sampleSize;
12919 this.beforeUpdate();
12920 this.maxWidth = maxWidth;
12921 this.maxHeight = maxHeight;
12922 this._margins = margins = Object.assign({
12923 left: 0,
12924 right: 0,
12925 top: 0,
12926 bottom: 0
12927 }, margins);
12928 this.ticks = null;
12929 this._labelSizes = null;
12930 this._gridLineItems = null;
12931 this._labelItems = null;
12932 this.beforeSetDimensions();
12933 this.setDimensions();
12934 this.afterSetDimensions();
12935 this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;
12936 if (!this._dataLimitsCached) {
12937 this.beforeDataLimits();
12938 this.determineDataLimits();
12939 this.afterDataLimits();
12940 this._range = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.R)(this, grace, beginAtZero);
12941 this._dataLimitsCached = true;
12942 }
12943 this.beforeBuildTicks();
12944 this.ticks = this.buildTicks() || [];
12945 this.afterBuildTicks();
12946 const samplingEnabled = sampleSize < this.ticks.length;
12947 this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
12948 this.configure();
12949 this.beforeCalculateLabelRotation();
12950 this.calculateLabelRotation();
12951 this.afterCalculateLabelRotation();
12952 if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
12953 this.ticks = autoSkip(this, this.ticks);
12954 this._labelSizes = null;
12955 this.afterAutoSkip();
12956 }
12957 if (samplingEnabled) {
12958 this._convertTicksToLabels(this.ticks);
12959 }
12960 this.beforeFit();
12961 this.fit();
12962 this.afterFit();
12963 this.afterUpdate();
12964 }
12965 configure() {
12966 let reversePixels = this.options.reverse;
12967 let startPixel, endPixel;
12968 if (this.isHorizontal()) {
12969 startPixel = this.left;
12970 endPixel = this.right;
12971 } else {
12972 startPixel = this.top;
12973 endPixel = this.bottom;
12974 reversePixels = !reversePixels;
12975 }
12976 this._startPixel = startPixel;
12977 this._endPixel = endPixel;
12978 this._reversePixels = reversePixels;
12979 this._length = endPixel - startPixel;
12980 this._alignToPixels = this.options.alignToPixels;
12981 }
12982 afterUpdate() {
12983 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterUpdate, [
12984 this
12985 ]);
12986 }
12987 beforeSetDimensions() {
12988 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeSetDimensions, [
12989 this
12990 ]);
12991 }
12992 setDimensions() {
12993 if (this.isHorizontal()) {
12994 this.width = this.maxWidth;
12995 this.left = 0;
12996 this.right = this.width;
12997 } else {
12998 this.height = this.maxHeight;
12999 this.top = 0;
13000 this.bottom = this.height;
13001 }
13002 this.paddingLeft = 0;
13003 this.paddingTop = 0;
13004 this.paddingRight = 0;
13005 this.paddingBottom = 0;
13006 }
13007 afterSetDimensions() {
13008 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterSetDimensions, [
13009 this
13010 ]);
13011 }
13012 _callHooks(name) {
13013 this.chart.notifyPlugins(name, this.getContext());
13014 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options[name], [
13015 this
13016 ]);
13017 }
13018 beforeDataLimits() {
13019 this._callHooks('beforeDataLimits');
13020 }
13021 determineDataLimits() {}
13022 afterDataLimits() {
13023 this._callHooks('afterDataLimits');
13024 }
13025 beforeBuildTicks() {
13026 this._callHooks('beforeBuildTicks');
13027 }
13028 buildTicks() {
13029 return [];
13030 }
13031 afterBuildTicks() {
13032 this._callHooks('afterBuildTicks');
13033 }
13034 beforeTickToLabelConversion() {
13035 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeTickToLabelConversion, [
13036 this
13037 ]);
13038 }
13039 generateTickLabels(ticks) {
13040 const tickOpts = this.options.ticks;
13041 let i, ilen, tick;
13042 for(i = 0, ilen = ticks.length; i < ilen; i++){
13043 tick = ticks[i];
13044 tick.label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(tickOpts.callback, [
13045 tick.value,
13046 i,
13047 ticks
13048 ], this);
13049 }
13050 }
13051 afterTickToLabelConversion() {
13052 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterTickToLabelConversion, [
13053 this
13054 ]);
13055 }
13056 beforeCalculateLabelRotation() {
13057 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeCalculateLabelRotation, [
13058 this
13059 ]);
13060 }
13061 calculateLabelRotation() {
13062 const options = this.options;
13063 const tickOpts = options.ticks;
13064 const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);
13065 const minRotation = tickOpts.minRotation || 0;
13066 const maxRotation = tickOpts.maxRotation;
13067 let labelRotation = minRotation;
13068 let tickWidth, maxHeight, maxLabelDiagonal;
13069 if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
13070 this.labelRotation = minRotation;
13071 return;
13072 }
13073 const labelSizes = this._getLabelSizes();
13074 const maxLabelWidth = labelSizes.widest.width;
13075 const maxLabelHeight = labelSizes.highest.height;
13076 const maxWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(this.chart.width - maxLabelWidth, 0, this.maxWidth);
13077 tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
13078 if (maxLabelWidth + 6 > tickWidth) {
13079 tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
13080 maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
13081 maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
13082 labelRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(Math.min(Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(maxLabelHeight / maxLabelDiagonal, -1, 1))));
13083 labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
13084 }
13085 this.labelRotation = labelRotation;
13086 }
13087 afterCalculateLabelRotation() {
13088 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterCalculateLabelRotation, [
13089 this
13090 ]);
13091 }
13092 afterAutoSkip() {}
13093 beforeFit() {
13094 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeFit, [
13095 this
13096 ]);
13097 }
13098 fit() {
13099 const minSize = {
13100 width: 0,
13101 height: 0
13102 };
13103 const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this;
13104 const display = this._isVisible();
13105 const isHorizontal = this.isHorizontal();
13106 if (display) {
13107 const titleHeight = getTitleHeight(titleOpts, chart.options.font);
13108 if (isHorizontal) {
13109 minSize.width = this.maxWidth;
13110 minSize.height = getTickMarkLength(gridOpts) + titleHeight;
13111 } else {
13112 minSize.height = this.maxHeight;
13113 minSize.width = getTickMarkLength(gridOpts) + titleHeight;
13114 }
13115 if (tickOpts.display && this.ticks.length) {
13116 const { first , last , widest , highest } = this._getLabelSizes();
13117 const tickPadding = tickOpts.padding * 2;
13118 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13119 const cos = Math.cos(angleRadians);
13120 const sin = Math.sin(angleRadians);
13121 if (isHorizontal) {
13122 const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
13123 minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
13124 } else {
13125 const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
13126 minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
13127 }
13128 this._calculatePadding(first, last, sin, cos);
13129 }
13130 }
13131 this._handleMargins();
13132 if (isHorizontal) {
13133 this.width = this._length = chart.width - this._margins.left - this._margins.right;
13134 this.height = minSize.height;
13135 } else {
13136 this.width = minSize.width;
13137 this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
13138 }
13139 }
13140 _calculatePadding(first, last, sin, cos) {
13141 const { ticks: { align , padding } , position } = this.options;
13142 const isRotated = this.labelRotation !== 0;
13143 const labelsBelowTicks = position !== 'top' && this.axis === 'x';
13144 if (this.isHorizontal()) {
13145 const offsetLeft = this.getPixelForTick(0) - this.left;
13146 const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
13147 let paddingLeft = 0;
13148 let paddingRight = 0;
13149 if (isRotated) {
13150 if (labelsBelowTicks) {
13151 paddingLeft = cos * first.width;
13152 paddingRight = sin * last.height;
13153 } else {
13154 paddingLeft = sin * first.height;
13155 paddingRight = cos * last.width;
13156 }
13157 } else if (align === 'start') {
13158 paddingRight = last.width;
13159 } else if (align === 'end') {
13160 paddingLeft = first.width;
13161 } else if (align !== 'inner') {
13162 paddingLeft = first.width / 2;
13163 paddingRight = last.width / 2;
13164 }
13165 this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
13166 this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
13167 } else {
13168 let paddingTop = last.height / 2;
13169 let paddingBottom = first.height / 2;
13170 if (align === 'start') {
13171 paddingTop = 0;
13172 paddingBottom = first.height;
13173 } else if (align === 'end') {
13174 paddingTop = last.height;
13175 paddingBottom = 0;
13176 }
13177 this.paddingTop = paddingTop + padding;
13178 this.paddingBottom = paddingBottom + padding;
13179 }
13180 }
13181 _handleMargins() {
13182 if (this._margins) {
13183 this._margins.left = Math.max(this.paddingLeft, this._margins.left);
13184 this._margins.top = Math.max(this.paddingTop, this._margins.top);
13185 this._margins.right = Math.max(this.paddingRight, this._margins.right);
13186 this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
13187 }
13188 }
13189 afterFit() {
13190 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterFit, [
13191 this
13192 ]);
13193 }
13194 isHorizontal() {
13195 const { axis , position } = this.options;
13196 return position === 'top' || position === 'bottom' || axis === 'x';
13197 }
13198 isFullSize() {
13199 return this.options.fullSize;
13200 }
13201 _convertTicksToLabels(ticks) {
13202 this.beforeTickToLabelConversion();
13203 this.generateTickLabels(ticks);
13204 let i, ilen;
13205 for(i = 0, ilen = ticks.length; i < ilen; i++){
13206 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(ticks[i].label)) {
13207 ticks.splice(i, 1);
13208 ilen--;
13209 i--;
13210 }
13211 }
13212 this.afterTickToLabelConversion();
13213 }
13214 _getLabelSizes() {
13215 let labelSizes = this._labelSizes;
13216 if (!labelSizes) {
13217 const sampleSize = this.options.ticks.sampleSize;
13218 let ticks = this.ticks;
13219 if (sampleSize < ticks.length) {
13220 ticks = sample(ticks, sampleSize);
13221 }
13222 this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);
13223 }
13224 return labelSizes;
13225 }
13226 _computeLabelSizes(ticks, length, maxTicksLimit) {
13227 const { ctx , _longestTextCache: caches } = this;
13228 const widths = [];
13229 const heights = [];
13230 const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));
13231 let widestLabelSize = 0;
13232 let highestLabelSize = 0;
13233 let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
13234 for(i = 0; i < length; i += increment){
13235 label = ticks[i].label;
13236 tickFont = this._resolveTickFontOptions(i);
13237 ctx.font = fontString = tickFont.string;
13238 cache = caches[fontString] = caches[fontString] || {
13239 data: {},
13240 gc: []
13241 };
13242 lineHeight = tickFont.lineHeight;
13243 width = height = 0;
13244 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(label) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13245 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, label);
13246 height = lineHeight;
13247 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13248 for(j = 0, jlen = label.length; j < jlen; ++j){
13249 nestedLabel = label[j];
13250 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(nestedLabel) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(nestedLabel)) {
13251 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, nestedLabel);
13252 height += lineHeight;
13253 }
13254 }
13255 }
13256 widths.push(width);
13257 heights.push(height);
13258 widestLabelSize = Math.max(width, widestLabelSize);
13259 highestLabelSize = Math.max(height, highestLabelSize);
13260 }
13261 garbageCollect(caches, length);
13262 const widest = widths.indexOf(widestLabelSize);
13263 const highest = heights.indexOf(highestLabelSize);
13264 const valueAt = (idx)=>({
13265 width: widths[idx] || 0,
13266 height: heights[idx] || 0
13267 });
13268 return {
13269 first: valueAt(0),
13270 last: valueAt(length - 1),
13271 widest: valueAt(widest),
13272 highest: valueAt(highest),
13273 widths,
13274 heights
13275 };
13276 }
13277 getLabelForValue(value) {
13278 return value;
13279 }
13280 getPixelForValue(value, index) {
13281 return NaN;
13282 }
13283 getValueForPixel(pixel) {}
13284 getPixelForTick(index) {
13285 const ticks = this.ticks;
13286 if (index < 0 || index > ticks.length - 1) {
13287 return null;
13288 }
13289 return this.getPixelForValue(ticks[index].value);
13290 }
13291 getPixelForDecimal(decimal) {
13292 if (this._reversePixels) {
13293 decimal = 1 - decimal;
13294 }
13295 const pixel = this._startPixel + decimal * this._length;
13296 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.W)(this._alignToPixels ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(this.chart, pixel, 0) : pixel);
13297 }
13298 getDecimalForPixel(pixel) {
13299 const decimal = (pixel - this._startPixel) / this._length;
13300 return this._reversePixels ? 1 - decimal : decimal;
13301 }
13302 getBasePixel() {
13303 return this.getPixelForValue(this.getBaseValue());
13304 }
13305 getBaseValue() {
13306 const { min , max } = this;
13307 return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;
13308 }
13309 getContext(index) {
13310 const ticks = this.ticks || [];
13311 if (index >= 0 && index < ticks.length) {
13312 const tick = ticks[index];
13313 return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));
13314 }
13315 return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));
13316 }
13317 _tickSize() {
13318 const optionTicks = this.options.ticks;
13319 const rot = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13320 const cos = Math.abs(Math.cos(rot));
13321 const sin = Math.abs(Math.sin(rot));
13322 const labelSizes = this._getLabelSizes();
13323 const padding = optionTicks.autoSkipPadding || 0;
13324 const w = labelSizes ? labelSizes.widest.width + padding : 0;
13325 const h = labelSizes ? labelSizes.highest.height + padding : 0;
13326 return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin;
13327 }
13328 _isVisible() {
13329 const display = this.options.display;
13330 if (display !== 'auto') {
13331 return !!display;
13332 }
13333 return this.getMatchingVisibleMetas().length > 0;
13334 }
13335 _computeGridLineItems(chartArea) {
13336 const axis = this.axis;
13337 const chart = this.chart;
13338 const options = this.options;
13339 const { grid , position , border } = options;
13340 const offset = grid.offset;
13341 const isHorizontal = this.isHorizontal();
13342 const ticks = this.ticks;
13343 const ticksLength = ticks.length + (offset ? 1 : 0);
13344 const tl = getTickMarkLength(grid);
13345 const items = [];
13346 const borderOpts = border.setContext(this.getContext());
13347 const axisWidth = borderOpts.display ? borderOpts.width : 0;
13348 const axisHalfWidth = axisWidth / 2;
13349 const alignBorderValue = function(pixel) {
13350 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, pixel, axisWidth);
13351 };
13352 let borderValue, i, lineValue, alignedLineValue;
13353 let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
13354 if (position === 'top') {
13355 borderValue = alignBorderValue(this.bottom);
13356 ty1 = this.bottom - tl;
13357 ty2 = borderValue - axisHalfWidth;
13358 y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
13359 y2 = chartArea.bottom;
13360 } else if (position === 'bottom') {
13361 borderValue = alignBorderValue(this.top);
13362 y1 = chartArea.top;
13363 y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
13364 ty1 = borderValue + axisHalfWidth;
13365 ty2 = this.top + tl;
13366 } else if (position === 'left') {
13367 borderValue = alignBorderValue(this.right);
13368 tx1 = this.right - tl;
13369 tx2 = borderValue - axisHalfWidth;
13370 x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
13371 x2 = chartArea.right;
13372 } else if (position === 'right') {
13373 borderValue = alignBorderValue(this.left);
13374 x1 = chartArea.left;
13375 x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
13376 tx1 = borderValue + axisHalfWidth;
13377 tx2 = this.left + tl;
13378 } else if (axis === 'x') {
13379 if (position === 'center') {
13380 borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
13381 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13382 const positionAxisID = Object.keys(position)[0];
13383 const value = position[positionAxisID];
13384 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13385 }
13386 y1 = chartArea.top;
13387 y2 = chartArea.bottom;
13388 ty1 = borderValue + axisHalfWidth;
13389 ty2 = ty1 + tl;
13390 } else if (axis === 'y') {
13391 if (position === 'center') {
13392 borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
13393 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13394 const positionAxisID = Object.keys(position)[0];
13395 const value = position[positionAxisID];
13396 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13397 }
13398 tx1 = borderValue - axisHalfWidth;
13399 tx2 = tx1 - tl;
13400 x1 = chartArea.left;
13401 x2 = chartArea.right;
13402 }
13403 const limit = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.maxTicksLimit, ticksLength);
13404 const step = Math.max(1, Math.ceil(ticksLength / limit));
13405 for(i = 0; i < ticksLength; i += step){
13406 const context = this.getContext(i);
13407 const optsAtIndex = grid.setContext(context);
13408 const optsAtIndexBorder = border.setContext(context);
13409 const lineWidth = optsAtIndex.lineWidth;
13410 const lineColor = optsAtIndex.color;
13411 const borderDash = optsAtIndexBorder.dash || [];
13412 const borderDashOffset = optsAtIndexBorder.dashOffset;
13413 const tickWidth = optsAtIndex.tickWidth;
13414 const tickColor = optsAtIndex.tickColor;
13415 const tickBorderDash = optsAtIndex.tickBorderDash || [];
13416 const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
13417 lineValue = getPixelForGridLine(this, i, offset);
13418 if (lineValue === undefined) {
13419 continue;
13420 }
13421 alignedLineValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, lineValue, lineWidth);
13422 if (isHorizontal) {
13423 tx1 = tx2 = x1 = x2 = alignedLineValue;
13424 } else {
13425 ty1 = ty2 = y1 = y2 = alignedLineValue;
13426 }
13427 items.push({
13428 tx1,
13429 ty1,
13430 tx2,
13431 ty2,
13432 x1,
13433 y1,
13434 x2,
13435 y2,
13436 width: lineWidth,
13437 color: lineColor,
13438 borderDash,
13439 borderDashOffset,
13440 tickWidth,
13441 tickColor,
13442 tickBorderDash,
13443 tickBorderDashOffset
13444 });
13445 }
13446 this._ticksLength = ticksLength;
13447 this._borderValue = borderValue;
13448 return items;
13449 }
13450 _computeLabelItems(chartArea) {
13451 const axis = this.axis;
13452 const options = this.options;
13453 const { position , ticks: optionTicks } = options;
13454 const isHorizontal = this.isHorizontal();
13455 const ticks = this.ticks;
13456 const { align , crossAlign , padding , mirror } = optionTicks;
13457 const tl = getTickMarkLength(options.grid);
13458 const tickAndPadding = tl + padding;
13459 const hTickAndPadding = mirror ? -padding : tickAndPadding;
13460 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13461 const items = [];
13462 let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
13463 let textBaseline = 'middle';
13464 if (position === 'top') {
13465 y = this.bottom - hTickAndPadding;
13466 textAlign = this._getXAxisLabelAlignment();
13467 } else if (position === 'bottom') {
13468 y = this.top + hTickAndPadding;
13469 textAlign = this._getXAxisLabelAlignment();
13470 } else if (position === 'left') {
13471 const ret = this._getYAxisLabelAlignment(tl);
13472 textAlign = ret.textAlign;
13473 x = ret.x;
13474 } else if (position === 'right') {
13475 const ret = this._getYAxisLabelAlignment(tl);
13476 textAlign = ret.textAlign;
13477 x = ret.x;
13478 } else if (axis === 'x') {
13479 if (position === 'center') {
13480 y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;
13481 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13482 const positionAxisID = Object.keys(position)[0];
13483 const value = position[positionAxisID];
13484 y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
13485 }
13486 textAlign = this._getXAxisLabelAlignment();
13487 } else if (axis === 'y') {
13488 if (position === 'center') {
13489 x = (chartArea.left + chartArea.right) / 2 - tickAndPadding;
13490 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13491 const positionAxisID = Object.keys(position)[0];
13492 const value = position[positionAxisID];
13493 x = this.chart.scales[positionAxisID].getPixelForValue(value);
13494 }
13495 textAlign = this._getYAxisLabelAlignment(tl).textAlign;
13496 }
13497 if (axis === 'y') {
13498 if (align === 'start') {
13499 textBaseline = 'top';
13500 } else if (align === 'end') {
13501 textBaseline = 'bottom';
13502 }
13503 }
13504 const labelSizes = this._getLabelSizes();
13505 for(i = 0, ilen = ticks.length; i < ilen; ++i){
13506 tick = ticks[i];
13507 label = tick.label;
13508 const optsAtIndex = optionTicks.setContext(this.getContext(i));
13509 pixel = this.getPixelForTick(i) + optionTicks.labelOffset;
13510 font = this._resolveTickFontOptions(i);
13511 lineHeight = font.lineHeight;
13512 lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label.length : 1;
13513 const halfCount = lineCount / 2;
13514 const color = optsAtIndex.color;
13515 const strokeColor = optsAtIndex.textStrokeColor;
13516 const strokeWidth = optsAtIndex.textStrokeWidth;
13517 let tickTextAlign = textAlign;
13518 if (isHorizontal) {
13519 x = pixel;
13520 if (textAlign === 'inner') {
13521 if (i === ilen - 1) {
13522 tickTextAlign = !this.options.reverse ? 'right' : 'left';
13523 } else if (i === 0) {
13524 tickTextAlign = !this.options.reverse ? 'left' : 'right';
13525 } else {
13526 tickTextAlign = 'center';
13527 }
13528 }
13529 if (position === 'top') {
13530 if (crossAlign === 'near' || rotation !== 0) {
13531 textOffset = -lineCount * lineHeight + lineHeight / 2;
13532 } else if (crossAlign === 'center') {
13533 textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
13534 } else {
13535 textOffset = -labelSizes.highest.height + lineHeight / 2;
13536 }
13537 } else {
13538 if (crossAlign === 'near' || rotation !== 0) {
13539 textOffset = lineHeight / 2;
13540 } else if (crossAlign === 'center') {
13541 textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
13542 } else {
13543 textOffset = labelSizes.highest.height - lineCount * lineHeight;
13544 }
13545 }
13546 if (mirror) {
13547 textOffset *= -1;
13548 }
13549 if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {
13550 x += lineHeight / 2 * Math.sin(rotation);
13551 }
13552 } else {
13553 y = pixel;
13554 textOffset = (1 - lineCount) * lineHeight / 2;
13555 }
13556 let backdrop;
13557 if (optsAtIndex.showLabelBackdrop) {
13558 const labelPadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
13559 const height = labelSizes.heights[i];
13560 const width = labelSizes.widths[i];
13561 let top = textOffset - labelPadding.top;
13562 let left = 0 - labelPadding.left;
13563 switch(textBaseline){
13564 case 'middle':
13565 top -= height / 2;
13566 break;
13567 case 'bottom':
13568 top -= height;
13569 break;
13570 }
13571 switch(textAlign){
13572 case 'center':
13573 left -= width / 2;
13574 break;
13575 case 'right':
13576 left -= width;
13577 break;
13578 case 'inner':
13579 if (i === ilen - 1) {
13580 left -= width;
13581 } else if (i > 0) {
13582 left -= width / 2;
13583 }
13584 break;
13585 }
13586 backdrop = {
13587 left,
13588 top,
13589 width: width + labelPadding.width,
13590 height: height + labelPadding.height,
13591 color: optsAtIndex.backdropColor
13592 };
13593 }
13594 items.push({
13595 label,
13596 font,
13597 textOffset,
13598 options: {
13599 rotation,
13600 color,
13601 strokeColor,
13602 strokeWidth,
13603 textAlign: tickTextAlign,
13604 textBaseline,
13605 translation: [
13606 x,
13607 y
13608 ],
13609 backdrop
13610 }
13611 });
13612 }
13613 return items;
13614 }
13615 _getXAxisLabelAlignment() {
13616 const { position , ticks } = this.options;
13617 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13618 if (rotation) {
13619 return position === 'top' ? 'left' : 'right';
13620 }
13621 let align = 'center';
13622 if (ticks.align === 'start') {
13623 align = 'left';
13624 } else if (ticks.align === 'end') {
13625 align = 'right';
13626 } else if (ticks.align === 'inner') {
13627 align = 'inner';
13628 }
13629 return align;
13630 }
13631 _getYAxisLabelAlignment(tl) {
13632 const { position , ticks: { crossAlign , mirror , padding } } = this.options;
13633 const labelSizes = this._getLabelSizes();
13634 const tickAndPadding = tl + padding;
13635 const widest = labelSizes.widest.width;
13636 let textAlign;
13637 let x;
13638 if (position === 'left') {
13639 if (mirror) {
13640 x = this.right + padding;
13641 if (crossAlign === 'near') {
13642 textAlign = 'left';
13643 } else if (crossAlign === 'center') {
13644 textAlign = 'center';
13645 x += widest / 2;
13646 } else {
13647 textAlign = 'right';
13648 x += widest;
13649 }
13650 } else {
13651 x = this.right - tickAndPadding;
13652 if (crossAlign === 'near') {
13653 textAlign = 'right';
13654 } else if (crossAlign === 'center') {
13655 textAlign = 'center';
13656 x -= widest / 2;
13657 } else {
13658 textAlign = 'left';
13659 x = this.left;
13660 }
13661 }
13662 } else if (position === 'right') {
13663 if (mirror) {
13664 x = this.left + padding;
13665 if (crossAlign === 'near') {
13666 textAlign = 'right';
13667 } else if (crossAlign === 'center') {
13668 textAlign = 'center';
13669 x -= widest / 2;
13670 } else {
13671 textAlign = 'left';
13672 x -= widest;
13673 }
13674 } else {
13675 x = this.left + tickAndPadding;
13676 if (crossAlign === 'near') {
13677 textAlign = 'left';
13678 } else if (crossAlign === 'center') {
13679 textAlign = 'center';
13680 x += widest / 2;
13681 } else {
13682 textAlign = 'right';
13683 x = this.right;
13684 }
13685 }
13686 } else {
13687 textAlign = 'right';
13688 }
13689 return {
13690 textAlign,
13691 x
13692 };
13693 }
13694 _computeLabelArea() {
13695 if (this.options.ticks.mirror) {
13696 return;
13697 }
13698 const chart = this.chart;
13699 const position = this.options.position;
13700 if (position === 'left' || position === 'right') {
13701 return {
13702 top: 0,
13703 left: this.left,
13704 bottom: chart.height,
13705 right: this.right
13706 };
13707 }
13708 if (position === 'top' || position === 'bottom') {
13709 return {
13710 top: this.top,
13711 left: 0,
13712 bottom: this.bottom,
13713 right: chart.width
13714 };
13715 }
13716 }
13717 drawBackground() {
13718 const { ctx , options: { backgroundColor } , left , top , width , height } = this;
13719 if (backgroundColor) {
13720 ctx.save();
13721 ctx.fillStyle = backgroundColor;
13722 ctx.fillRect(left, top, width, height);
13723 ctx.restore();
13724 }
13725 }
13726 getLineWidthForValue(value) {
13727 const grid = this.options.grid;
13728 if (!this._isVisible() || !grid.display) {
13729 return 0;
13730 }
13731 const ticks = this.ticks;
13732 const index = ticks.findIndex((t)=>t.value === value);
13733 if (index >= 0) {
13734 const opts = grid.setContext(this.getContext(index));
13735 return opts.lineWidth;
13736 }
13737 return 0;
13738 }
13739 drawGrid(chartArea) {
13740 const grid = this.options.grid;
13741 const ctx = this.ctx;
13742 const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
13743 let i, ilen;
13744 const drawLine = (p1, p2, style)=>{
13745 if (!style.width || !style.color) {
13746 return;
13747 }
13748 ctx.save();
13749 ctx.lineWidth = style.width;
13750 ctx.strokeStyle = style.color;
13751 ctx.setLineDash(style.borderDash || []);
13752 ctx.lineDashOffset = style.borderDashOffset;
13753 ctx.beginPath();
13754 ctx.moveTo(p1.x, p1.y);
13755 ctx.lineTo(p2.x, p2.y);
13756 ctx.stroke();
13757 ctx.restore();
13758 };
13759 if (grid.display) {
13760 for(i = 0, ilen = items.length; i < ilen; ++i){
13761 const item = items[i];
13762 if (grid.drawOnChartArea) {
13763 drawLine({
13764 x: item.x1,
13765 y: item.y1
13766 }, {
13767 x: item.x2,
13768 y: item.y2
13769 }, item);
13770 }
13771 if (grid.drawTicks) {
13772 drawLine({
13773 x: item.tx1,
13774 y: item.ty1
13775 }, {
13776 x: item.tx2,
13777 y: item.ty2
13778 }, {
13779 color: item.tickColor,
13780 width: item.tickWidth,
13781 borderDash: item.tickBorderDash,
13782 borderDashOffset: item.tickBorderDashOffset
13783 });
13784 }
13785 }
13786 }
13787 }
13788 drawBorder() {
13789 const { chart , ctx , options: { border , grid } } = this;
13790 const borderOpts = border.setContext(this.getContext());
13791 const axisWidth = border.display ? borderOpts.width : 0;
13792 if (!axisWidth) {
13793 return;
13794 }
13795 const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
13796 const borderValue = this._borderValue;
13797 let x1, x2, y1, y2;
13798 if (this.isHorizontal()) {
13799 x1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.left, axisWidth) - axisWidth / 2;
13800 x2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.right, lastLineWidth) + lastLineWidth / 2;
13801 y1 = y2 = borderValue;
13802 } else {
13803 y1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.top, axisWidth) - axisWidth / 2;
13804 y2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
13805 x1 = x2 = borderValue;
13806 }
13807 ctx.save();
13808 ctx.lineWidth = borderOpts.width;
13809 ctx.strokeStyle = borderOpts.color;
13810 ctx.beginPath();
13811 ctx.moveTo(x1, y1);
13812 ctx.lineTo(x2, y2);
13813 ctx.stroke();
13814 ctx.restore();
13815 }
13816 drawLabels(chartArea) {
13817 const optionTicks = this.options.ticks;
13818 if (!optionTicks.display) {
13819 return;
13820 }
13821 const ctx = this.ctx;
13822 const area = this._computeLabelArea();
13823 if (area) {
13824 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
13825 }
13826 const items = this.getLabelItems(chartArea);
13827 for (const item of items){
13828 const renderTextOptions = item.options;
13829 const tickFont = item.font;
13830 const label = item.label;
13831 const y = item.textOffset;
13832 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, label, 0, y, tickFont, renderTextOptions);
13833 }
13834 if (area) {
13835 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
13836 }
13837 }
13838 drawTitle() {
13839 const { ctx , options: { position , title , reverse } } = this;
13840 if (!title.display) {
13841 return;
13842 }
13843 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(title.font);
13844 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(title.padding);
13845 const align = title.align;
13846 let offset = font.lineHeight / 2;
13847 if (position === 'bottom' || position === 'center' || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13848 offset += padding.bottom;
13849 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(title.text)) {
13850 offset += font.lineHeight * (title.text.length - 1);
13851 }
13852 } else {
13853 offset += padding.top;
13854 }
13855 const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align);
13856 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, title.text, 0, 0, font, {
13857 color: title.color,
13858 maxWidth,
13859 rotation,
13860 textAlign: titleAlign(align, position, reverse),
13861 textBaseline: 'middle',
13862 translation: [
13863 titleX,
13864 titleY
13865 ]
13866 });
13867 }
13868 draw(chartArea) {
13869 if (!this._isVisible()) {
13870 return;
13871 }
13872 this.drawBackground();
13873 this.drawGrid(chartArea);
13874 this.drawBorder();
13875 this.drawTitle();
13876 this.drawLabels(chartArea);
13877 }
13878 _layers() {
13879 const opts = this.options;
13880 const tz = opts.ticks && opts.ticks.z || 0;
13881 const gz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.grid && opts.grid.z, -1);
13882 const bz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.border && opts.border.z, 0);
13883 if (!this._isVisible() || this.draw !== Scale.prototype.draw) {
13884 return [
13885 {
13886 z: tz,
13887 draw: (chartArea)=>{
13888 this.draw(chartArea);
13889 }
13890 }
13891 ];
13892 }
13893 return [
13894 {
13895 z: gz,
13896 draw: (chartArea)=>{
13897 this.drawBackground();
13898 this.drawGrid(chartArea);
13899 this.drawTitle();
13900 }
13901 },
13902 {
13903 z: bz,
13904 draw: ()=>{
13905 this.drawBorder();
13906 }
13907 },
13908 {
13909 z: tz,
13910 draw: (chartArea)=>{
13911 this.drawLabels(chartArea);
13912 }
13913 }
13914 ];
13915 }
13916 getMatchingVisibleMetas(type) {
13917 const metas = this.chart.getSortedVisibleDatasetMetas();
13918 const axisID = this.axis + 'AxisID';
13919 const result = [];
13920 let i, ilen;
13921 for(i = 0, ilen = metas.length; i < ilen; ++i){
13922 const meta = metas[i];
13923 if (meta[axisID] === this.id && (!type || meta.type === type)) {
13924 result.push(meta);
13925 }
13926 }
13927 return result;
13928 }
13929 _resolveTickFontOptions(index) {
13930 const opts = this.options.ticks.setContext(this.getContext(index));
13931 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
13932 }
13933 _maxDigits() {
13934 const fontSize = this._resolveTickFontOptions(0).lineHeight;
13935 return (this.isHorizontal() ? this.width : this.height) / fontSize;
13936 }
13937 }
13938
13939 class TypedRegistry {
13940 constructor(type, scope, override){
13941 this.type = type;
13942 this.scope = scope;
13943 this.override = override;
13944 this.items = Object.create(null);
13945 }
13946 isForType(type) {
13947 return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
13948 }
13949 register(item) {
13950 const proto = Object.getPrototypeOf(item);
13951 let parentScope;
13952 if (isIChartComponent(proto)) {
13953 parentScope = this.register(proto);
13954 }
13955 const items = this.items;
13956 const id = item.id;
13957 const scope = this.scope + '.' + id;
13958 if (!id) {
13959 throw new Error('class does not have id: ' + item);
13960 }
13961 if (id in items) {
13962 return scope;
13963 }
13964 items[id] = item;
13965 registerDefaults(item, scope, parentScope);
13966 if (this.override) {
13967 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.override(item.id, item.overrides);
13968 }
13969 return scope;
13970 }
13971 get(id) {
13972 return this.items[id];
13973 }
13974 unregister(item) {
13975 const items = this.items;
13976 const id = item.id;
13977 const scope = this.scope;
13978 if (id in items) {
13979 delete items[id];
13980 }
13981 if (scope && id in _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope]) {
13982 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope][id];
13983 if (this.override) {
13984 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[id];
13985 }
13986 }
13987 }
13988 }
13989 function registerDefaults(item, scope, parentScope) {
13990 const itemDefaults = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a4)(Object.create(null), [
13991 parentScope ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(parentScope) : {},
13992 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(scope),
13993 item.defaults
13994 ]);
13995 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.set(scope, itemDefaults);
13996 if (item.defaultRoutes) {
13997 routeDefaults(scope, item.defaultRoutes);
13998 }
13999 if (item.descriptors) {
14000 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.describe(scope, item.descriptors);
14001 }
14002 }
14003 function routeDefaults(scope, routes) {
14004 Object.keys(routes).forEach((property)=>{
14005 const propertyParts = property.split('.');
14006 const sourceName = propertyParts.pop();
14007 const sourceScope = [
14008 scope
14009 ].concat(propertyParts).join('.');
14010 const parts = routes[property].split('.');
14011 const targetName = parts.pop();
14012 const targetScope = parts.join('.');
14013 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.route(sourceScope, sourceName, targetScope, targetName);
14014 });
14015 }
14016 function isIChartComponent(proto) {
14017 return 'id' in proto && 'defaults' in proto;
14018 }
14019
14020 class Registry {
14021 constructor(){
14022 this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
14023 this.elements = new TypedRegistry(Element, 'elements');
14024 this.plugins = new TypedRegistry(Object, 'plugins');
14025 this.scales = new TypedRegistry(Scale, 'scales');
14026 this._typedRegistries = [
14027 this.controllers,
14028 this.scales,
14029 this.elements
14030 ];
14031 }
14032 add(...args) {
14033 this._each('register', args);
14034 }
14035 remove(...args) {
14036 this._each('unregister', args);
14037 }
14038 addControllers(...args) {
14039 this._each('register', args, this.controllers);
14040 }
14041 addElements(...args) {
14042 this._each('register', args, this.elements);
14043 }
14044 addPlugins(...args) {
14045 this._each('register', args, this.plugins);
14046 }
14047 addScales(...args) {
14048 this._each('register', args, this.scales);
14049 }
14050 getController(id) {
14051 return this._get(id, this.controllers, 'controller');
14052 }
14053 getElement(id) {
14054 return this._get(id, this.elements, 'element');
14055 }
14056 getPlugin(id) {
14057 return this._get(id, this.plugins, 'plugin');
14058 }
14059 getScale(id) {
14060 return this._get(id, this.scales, 'scale');
14061 }
14062 removeControllers(...args) {
14063 this._each('unregister', args, this.controllers);
14064 }
14065 removeElements(...args) {
14066 this._each('unregister', args, this.elements);
14067 }
14068 removePlugins(...args) {
14069 this._each('unregister', args, this.plugins);
14070 }
14071 removeScales(...args) {
14072 this._each('unregister', args, this.scales);
14073 }
14074 _each(method, args, typedRegistry) {
14075 [
14076 ...args
14077 ].forEach((arg)=>{
14078 const reg = typedRegistry || this._getRegistryForType(arg);
14079 if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {
14080 this._exec(method, reg, arg);
14081 } else {
14082 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(arg, (item)=>{
14083 const itemReg = typedRegistry || this._getRegistryForType(item);
14084 this._exec(method, itemReg, item);
14085 });
14086 }
14087 });
14088 }
14089 _exec(method, registry, component) {
14090 const camelMethod = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a5)(method);
14091 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['before' + camelMethod], [], component);
14092 registry[method](component);
14093 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['after' + camelMethod], [], component);
14094 }
14095 _getRegistryForType(type) {
14096 for(let i = 0; i < this._typedRegistries.length; i++){
14097 const reg = this._typedRegistries[i];
14098 if (reg.isForType(type)) {
14099 return reg;
14100 }
14101 }
14102 return this.plugins;
14103 }
14104 _get(id, typedRegistry, type) {
14105 const item = typedRegistry.get(id);
14106 if (item === undefined) {
14107 throw new Error('"' + id + '" is not a registered ' + type + '.');
14108 }
14109 return item;
14110 }
14111 }
14112 var registry = /* #__PURE__ */ new Registry();
14113
14114 class PluginService {
14115 constructor(){
14116 this._init = undefined;
14117 }
14118 notify(chart, hook, args, filter) {
14119 if (hook === 'beforeInit') {
14120 this._init = this._createDescriptors(chart, true);
14121 this._notify(this._init, chart, 'install');
14122 }
14123 if (this._init === undefined) {
14124 return;
14125 }
14126 const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
14127 const result = this._notify(descriptors, chart, hook, args);
14128 if (hook === 'afterDestroy') {
14129 this._notify(descriptors, chart, 'stop');
14130 this._notify(this._init, chart, 'uninstall');
14131 this._init = undefined;
14132 }
14133 return result;
14134 }
14135 _notify(descriptors, chart, hook, args) {
14136 args = args || {};
14137 for (const descriptor of descriptors){
14138 const plugin = descriptor.plugin;
14139 const method = plugin[hook];
14140 const params = [
14141 chart,
14142 args,
14143 descriptor.options
14144 ];
14145 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(method, params, plugin) === false && args.cancelable) {
14146 return false;
14147 }
14148 }
14149 return true;
14150 }
14151 invalidate() {
14152 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(this._cache)) {
14153 this._oldCache = this._cache;
14154 this._cache = undefined;
14155 }
14156 }
14157 _descriptors(chart) {
14158 if (this._cache) {
14159 return this._cache;
14160 }
14161 const descriptors = this._cache = this._createDescriptors(chart);
14162 this._notifyStateChanges(chart);
14163 return descriptors;
14164 }
14165 _createDescriptors(chart, all) {
14166 const config = chart && chart.config;
14167 const options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(config.options && config.options.plugins, {});
14168 const plugins = allPlugins(config);
14169 return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
14170 }
14171 _notifyStateChanges(chart) {
14172 const previousDescriptors = this._oldCache || [];
14173 const descriptors = this._cache;
14174 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id));
14175 this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
14176 this._notify(diff(descriptors, previousDescriptors), chart, 'start');
14177 }
14178 }
14179 function allPlugins(config) {
14180 const localIds = {};
14181 const plugins = [];
14182 const keys = Object.keys(registry.plugins.items);
14183 for(let i = 0; i < keys.length; i++){
14184 plugins.push(registry.getPlugin(keys[i]));
14185 }
14186 const local = config.plugins || [];
14187 for(let i = 0; i < local.length; i++){
14188 const plugin = local[i];
14189 if (plugins.indexOf(plugin) === -1) {
14190 plugins.push(plugin);
14191 localIds[plugin.id] = true;
14192 }
14193 }
14194 return {
14195 plugins,
14196 localIds
14197 };
14198 }
14199 function getOpts(options, all) {
14200 if (!all && options === false) {
14201 return null;
14202 }
14203 if (options === true) {
14204 return {};
14205 }
14206 return options;
14207 }
14208 function createDescriptors(chart, { plugins , localIds }, options, all) {
14209 const result = [];
14210 const context = chart.getContext();
14211 for (const plugin of plugins){
14212 const id = plugin.id;
14213 const opts = getOpts(options[id], all);
14214 if (opts === null) {
14215 continue;
14216 }
14217 result.push({
14218 plugin,
14219 options: pluginOpts(chart.config, {
14220 plugin,
14221 local: localIds[id]
14222 }, opts, context)
14223 });
14224 }
14225 return result;
14226 }
14227 function pluginOpts(config, { plugin , local }, opts, context) {
14228 const keys = config.pluginScopeKeys(plugin);
14229 const scopes = config.getOptionScopes(opts, keys);
14230 if (local && plugin.defaults) {
14231 scopes.push(plugin.defaults);
14232 }
14233 return config.createResolver(scopes, context, [
14234 ''
14235 ], {
14236 scriptable: false,
14237 indexable: false,
14238 allKeys: true
14239 });
14240 }
14241
14242 function getIndexAxis(type, options) {
14243 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {};
14244 const datasetOptions = (options.datasets || {})[type] || {};
14245 return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
14246 }
14247 function getAxisFromDefaultScaleID(id, indexAxis) {
14248 let axis = id;
14249 if (id === '_index_') {
14250 axis = indexAxis;
14251 } else if (id === '_value_') {
14252 axis = indexAxis === 'x' ? 'y' : 'x';
14253 }
14254 return axis;
14255 }
14256 function getDefaultScaleIDFromAxis(axis, indexAxis) {
14257 return axis === indexAxis ? '_index_' : '_value_';
14258 }
14259 function idMatchesAxis(id) {
14260 if (id === 'x' || id === 'y' || id === 'r') {
14261 return id;
14262 }
14263 }
14264 function axisFromPosition(position) {
14265 if (position === 'top' || position === 'bottom') {
14266 return 'x';
14267 }
14268 if (position === 'left' || position === 'right') {
14269 return 'y';
14270 }
14271 }
14272 function determineAxis(id, ...scaleOptions) {
14273 if (idMatchesAxis(id)) {
14274 return id;
14275 }
14276 for (const opts of scaleOptions){
14277 const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());
14278 if (axis) {
14279 return axis;
14280 }
14281 }
14282 throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
14283 }
14284 function getAxisFromDataset(id, axis, dataset) {
14285 if (dataset[axis + 'AxisID'] === id) {
14286 return {
14287 axis
14288 };
14289 }
14290 }
14291 function retrieveAxisFromDatasets(id, config) {
14292 if (config.data && config.data.datasets) {
14293 const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id);
14294 if (boundDs.length) {
14295 return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);
14296 }
14297 }
14298 return {};
14299 }
14300 function mergeScaleConfig(config, options) {
14301 const chartDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[config.type] || {
14302 scales: {}
14303 };
14304 const configScales = options.scales || {};
14305 const chartIndexAxis = getIndexAxis(config.type, options);
14306 const scales = Object.create(null);
14307 Object.keys(configScales).forEach((id)=>{
14308 const scaleConf = configScales[id];
14309 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(scaleConf)) {
14310 return console.error(`Invalid scale configuration for scale: ${id}`);
14311 }
14312 if (scaleConf._proxy) {
14313 return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
14314 }
14315 const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scaleConf.type]);
14316 const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
14317 const defaultScaleOptions = chartDefaults.scales || {};
14318 scales[id] = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(Object.create(null), [
14319 {
14320 axis
14321 },
14322 scaleConf,
14323 defaultScaleOptions[axis],
14324 defaultScaleOptions[defaultId]
14325 ]);
14326 });
14327 config.data.datasets.forEach((dataset)=>{
14328 const type = dataset.type || config.type;
14329 const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
14330 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {};
14331 const defaultScaleOptions = datasetDefaults.scales || {};
14332 Object.keys(defaultScaleOptions).forEach((defaultID)=>{
14333 const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
14334 const id = dataset[axis + 'AxisID'] || axis;
14335 scales[id] = scales[id] || Object.create(null);
14336 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scales[id], [
14337 {
14338 axis
14339 },
14340 configScales[id],
14341 defaultScaleOptions[defaultID]
14342 ]);
14343 });
14344 });
14345 Object.keys(scales).forEach((key)=>{
14346 const scale = scales[key];
14347 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scale, [
14348 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scale.type],
14349 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scale
14350 ]);
14351 });
14352 return scales;
14353 }
14354 function initOptions(config) {
14355 const options = config.options || (config.options = {});
14356 options.plugins = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.plugins, {});
14357 options.scales = mergeScaleConfig(config, options);
14358 }
14359 function initData(data) {
14360 data = data || {};
14361 data.datasets = data.datasets || [];
14362 data.labels = data.labels || [];
14363 return data;
14364 }
14365 function initConfig(config) {
14366 config = config || {};
14367 config.data = initData(config.data);
14368 initOptions(config);
14369 return config;
14370 }
14371 const keyCache = new Map();
14372 const keysCached = new Set();
14373 function cachedKeys(cacheKey, generate) {
14374 let keys = keyCache.get(cacheKey);
14375 if (!keys) {
14376 keys = generate();
14377 keyCache.set(cacheKey, keys);
14378 keysCached.add(keys);
14379 }
14380 return keys;
14381 }
14382 const addIfFound = (set, obj, key)=>{
14383 const opts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, key);
14384 if (opts !== undefined) {
14385 set.add(opts);
14386 }
14387 };
14388 class Config {
14389 constructor(config){
14390 this._config = initConfig(config);
14391 this._scopeCache = new Map();
14392 this._resolverCache = new Map();
14393 }
14394 get platform() {
14395 return this._config.platform;
14396 }
14397 get type() {
14398 return this._config.type;
14399 }
14400 set type(type) {
14401 this._config.type = type;
14402 }
14403 get data() {
14404 return this._config.data;
14405 }
14406 set data(data) {
14407 this._config.data = initData(data);
14408 }
14409 get options() {
14410 return this._config.options;
14411 }
14412 set options(options) {
14413 this._config.options = options;
14414 }
14415 get plugins() {
14416 return this._config.plugins;
14417 }
14418 update() {
14419 const config = this._config;
14420 this.clearCache();
14421 initOptions(config);
14422 }
14423 clearCache() {
14424 this._scopeCache.clear();
14425 this._resolverCache.clear();
14426 }
14427 datasetScopeKeys(datasetType) {
14428 return cachedKeys(datasetType, ()=>[
14429 [
14430 `datasets.${datasetType}`,
14431 ''
14432 ]
14433 ]);
14434 }
14435 datasetAnimationScopeKeys(datasetType, transition) {
14436 return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[
14437 [
14438 `datasets.${datasetType}.transitions.${transition}`,
14439 `transitions.${transition}`
14440 ],
14441 [
14442 `datasets.${datasetType}`,
14443 ''
14444 ]
14445 ]);
14446 }
14447 datasetElementScopeKeys(datasetType, elementType) {
14448 return cachedKeys(`${datasetType}-${elementType}`, ()=>[
14449 [
14450 `datasets.${datasetType}.elements.${elementType}`,
14451 `datasets.${datasetType}`,
14452 `elements.${elementType}`,
14453 ''
14454 ]
14455 ]);
14456 }
14457 pluginScopeKeys(plugin) {
14458 const id = plugin.id;
14459 const type = this.type;
14460 return cachedKeys(`${type}-plugin-${id}`, ()=>[
14461 [
14462 `plugins.${id}`,
14463 ...plugin.additionalOptionScopes || []
14464 ]
14465 ]);
14466 }
14467 _cachedScopes(mainScope, resetCache) {
14468 const _scopeCache = this._scopeCache;
14469 let cache = _scopeCache.get(mainScope);
14470 if (!cache || resetCache) {
14471 cache = new Map();
14472 _scopeCache.set(mainScope, cache);
14473 }
14474 return cache;
14475 }
14476 getOptionScopes(mainScope, keyLists, resetCache) {
14477 const { options , type } = this;
14478 const cache = this._cachedScopes(mainScope, resetCache);
14479 const cached = cache.get(keyLists);
14480 if (cached) {
14481 return cached;
14482 }
14483 const scopes = new Set();
14484 keyLists.forEach((keys)=>{
14485 if (mainScope) {
14486 scopes.add(mainScope);
14487 keys.forEach((key)=>addIfFound(scopes, mainScope, key));
14488 }
14489 keys.forEach((key)=>addIfFound(scopes, options, key));
14490 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, key));
14491 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, key));
14492 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6, key));
14493 });
14494 const array = Array.from(scopes);
14495 if (array.length === 0) {
14496 array.push(Object.create(null));
14497 }
14498 if (keysCached.has(keyLists)) {
14499 cache.set(keyLists, array);
14500 }
14501 return array;
14502 }
14503 chartOptionScopes() {
14504 const { options , type } = this;
14505 return [
14506 options,
14507 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {},
14508 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {},
14509 {
14510 type
14511 },
14512 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d,
14513 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6
14514 ];
14515 }
14516 resolveNamedOptions(scopes, names, context, prefixes = [
14517 ''
14518 ]) {
14519 const result = {
14520 $shared: true
14521 };
14522 const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);
14523 let options = resolver;
14524 if (needContext(resolver, names)) {
14525 result.$shared = false;
14526 context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(context) ? context() : context;
14527 const subResolver = this.createResolver(scopes, context, subPrefixes);
14528 options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, subResolver);
14529 }
14530 for (const prop of names){
14531 result[prop] = options[prop];
14532 }
14533 return result;
14534 }
14535 createResolver(scopes, context, prefixes = [
14536 ''
14537 ], descriptorDefaults) {
14538 const { resolver } = getResolver(this._resolverCache, scopes, prefixes);
14539 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(context) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, undefined, descriptorDefaults) : resolver;
14540 }
14541 }
14542 function getResolver(resolverCache, scopes, prefixes) {
14543 let cache = resolverCache.get(scopes);
14544 if (!cache) {
14545 cache = new Map();
14546 resolverCache.set(scopes, cache);
14547 }
14548 const cacheKey = prefixes.join();
14549 let cached = cache.get(cacheKey);
14550 if (!cached) {
14551 const resolver = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a9)(scopes, prefixes);
14552 cached = {
14553 resolver,
14554 subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover'))
14555 };
14556 cache.set(cacheKey, cached);
14557 }
14558 return cached;
14559 }
14560 const hasFunction = (value)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value) && Object.getOwnPropertyNames(value).some((key)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(value[key]));
14561 function needContext(proxy, names) {
14562 const { isScriptable , isIndexable } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aa)(proxy);
14563 for (const prop of names){
14564 const scriptable = isScriptable(prop);
14565 const indexable = isIndexable(prop);
14566 const value = (indexable || scriptable) && proxy[prop];
14567 if (scriptable && ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(value) || hasFunction(value)) || indexable && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(value)) {
14568 return true;
14569 }
14570 }
14571 return false;
14572 }
14573
14574 var version = "4.5.1";
14575
14576 const KNOWN_POSITIONS = [
14577 'top',
14578 'bottom',
14579 'left',
14580 'right',
14581 'chartArea'
14582 ];
14583 function positionIsHorizontal(position, axis) {
14584 return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x';
14585 }
14586 function compare2Level(l1, l2) {
14587 return function(a, b) {
14588 return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1];
14589 };
14590 }
14591 function onAnimationsComplete(context) {
14592 const chart = context.chart;
14593 const animationOptions = chart.options.animation;
14594 chart.notifyPlugins('afterRender');
14595 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onComplete, [
14596 context
14597 ], chart);
14598 }
14599 function onAnimationProgress(context) {
14600 const chart = context.chart;
14601 const animationOptions = chart.options.animation;
14602 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onProgress, [
14603 context
14604 ], chart);
14605 }
14606 function getCanvas(item) {
14607 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() && typeof item === 'string') {
14608 item = document.getElementById(item);
14609 } else if (item && item.length) {
14610 item = item[0];
14611 }
14612 if (item && item.canvas) {
14613 item = item.canvas;
14614 }
14615 return item;
14616 }
14617 const instances = {};
14618 const getChart = (key)=>{
14619 const canvas = getCanvas(key);
14620 return Object.values(instances).filter((c)=>c.canvas === canvas).pop();
14621 };
14622 function moveNumericKeys(obj, start, move) {
14623 const keys = Object.keys(obj);
14624 for (const key of keys){
14625 const intKey = +key;
14626 if (intKey >= start) {
14627 const value = obj[key];
14628 delete obj[key];
14629 if (move > 0 || intKey > start) {
14630 obj[intKey + move] = value;
14631 }
14632 }
14633 }
14634 }
14635 function determineLastEvent(e, lastEvent, inChartArea, isClick) {
14636 if (!inChartArea || e.type === 'mouseout') {
14637 return null;
14638 }
14639 if (isClick) {
14640 return lastEvent;
14641 }
14642 return e;
14643 }
14644 class Chart {
14645 static defaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d;
14646 static instances = instances;
14647 static overrides = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3;
14648 static registry = registry;
14649 static version = version;
14650 static getChart = getChart;
14651 static register(...items) {
14652 registry.add(...items);
14653 invalidatePlugins();
14654 }
14655 static unregister(...items) {
14656 registry.remove(...items);
14657 invalidatePlugins();
14658 }
14659 constructor(item, userConfig){
14660 const config = this.config = new Config(userConfig);
14661 const initialCanvas = getCanvas(item);
14662 const existingChart = getChart(initialCanvas);
14663 if (existingChart) {
14664 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.');
14665 }
14666 const options = config.createResolver(config.chartOptionScopes(), this.getContext());
14667 this.platform = new (config.platform || _detectPlatform(initialCanvas))();
14668 this.platform.updateConfig(config);
14669 const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
14670 const canvas = context && context.canvas;
14671 const height = canvas && canvas.height;
14672 const width = canvas && canvas.width;
14673 this.id = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ac)();
14674 this.ctx = context;
14675 this.canvas = canvas;
14676 this.width = width;
14677 this.height = height;
14678 this._options = options;
14679 this._aspectRatio = this.aspectRatio;
14680 this._layers = [];
14681 this._metasets = [];
14682 this._stacks = undefined;
14683 this.boxes = [];
14684 this.currentDevicePixelRatio = undefined;
14685 this.chartArea = undefined;
14686 this._active = [];
14687 this._lastEvent = undefined;
14688 this._listeners = {};
14689 this._responsiveListeners = undefined;
14690 this._sortedMetasets = [];
14691 this.scales = {};
14692 this._plugins = new PluginService();
14693 this.$proxies = {};
14694 this._hiddenIndices = {};
14695 this.attached = false;
14696 this._animationsDisabled = undefined;
14697 this.$context = undefined;
14698 this._doResize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ad)((mode)=>this.update(mode), options.resizeDelay || 0);
14699 this._dataChanges = [];
14700 instances[this.id] = this;
14701 if (!context || !canvas) {
14702 console.error("Failed to create chart: can't acquire context from the given item");
14703 return;
14704 }
14705 animator.listen(this, 'complete', onAnimationsComplete);
14706 animator.listen(this, 'progress', onAnimationProgress);
14707 this._initialize();
14708 if (this.attached) {
14709 this.update();
14710 }
14711 }
14712 get aspectRatio() {
14713 const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this;
14714 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(aspectRatio)) {
14715 return aspectRatio;
14716 }
14717 if (maintainAspectRatio && _aspectRatio) {
14718 return _aspectRatio;
14719 }
14720 return height ? width / height : null;
14721 }
14722 get data() {
14723 return this.config.data;
14724 }
14725 set data(data) {
14726 this.config.data = data;
14727 }
14728 get options() {
14729 return this._options;
14730 }
14731 set options(options) {
14732 this.config.options = options;
14733 }
14734 get registry() {
14735 return registry;
14736 }
14737 _initialize() {
14738 this.notifyPlugins('beforeInit');
14739 if (this.options.responsive) {
14740 this.resize();
14741 } else {
14742 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, this.options.devicePixelRatio);
14743 }
14744 this.bindEvents();
14745 this.notifyPlugins('afterInit');
14746 return this;
14747 }
14748 clear() {
14749 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(this.canvas, this.ctx);
14750 return this;
14751 }
14752 stop() {
14753 animator.stop(this);
14754 return this;
14755 }
14756 resize(width, height) {
14757 if (!animator.running(this)) {
14758 this._resize(width, height);
14759 } else {
14760 this._resizeBeforeDraw = {
14761 width,
14762 height
14763 };
14764 }
14765 }
14766 _resize(width, height) {
14767 const options = this.options;
14768 const canvas = this.canvas;
14769 const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
14770 const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
14771 const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
14772 const mode = this.width ? 'resize' : 'attach';
14773 this.width = newSize.width;
14774 this.height = newSize.height;
14775 this._aspectRatio = this.aspectRatio;
14776 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, newRatio, true)) {
14777 return;
14778 }
14779 this.notifyPlugins('resize', {
14780 size: newSize
14781 });
14782 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onResize, [
14783 this,
14784 newSize
14785 ], this);
14786 if (this.attached) {
14787 if (this._doResize(mode)) {
14788 this.render();
14789 }
14790 }
14791 }
14792 ensureScalesHaveIDs() {
14793 const options = this.options;
14794 const scalesOptions = options.scales || {};
14795 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scalesOptions, (axisOptions, axisID)=>{
14796 axisOptions.id = axisID;
14797 });
14798 }
14799 buildOrUpdateScales() {
14800 const options = this.options;
14801 const scaleOpts = options.scales;
14802 const scales = this.scales;
14803 const updated = Object.keys(scales).reduce((obj, id)=>{
14804 obj[id] = false;
14805 return obj;
14806 }, {});
14807 let items = [];
14808 if (scaleOpts) {
14809 items = items.concat(Object.keys(scaleOpts).map((id)=>{
14810 const scaleOptions = scaleOpts[id];
14811 const axis = determineAxis(id, scaleOptions);
14812 const isRadial = axis === 'r';
14813 const isHorizontal = axis === 'x';
14814 return {
14815 options: scaleOptions,
14816 dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
14817 dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
14818 };
14819 }));
14820 }
14821 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(items, (item)=>{
14822 const scaleOptions = item.options;
14823 const id = scaleOptions.id;
14824 const axis = determineAxis(id, scaleOptions);
14825 const scaleType = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(scaleOptions.type, item.dtype);
14826 if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
14827 scaleOptions.position = item.dposition;
14828 }
14829 updated[id] = true;
14830 let scale = null;
14831 if (id in scales && scales[id].type === scaleType) {
14832 scale = scales[id];
14833 } else {
14834 const scaleClass = registry.getScale(scaleType);
14835 scale = new scaleClass({
14836 id,
14837 type: scaleType,
14838 ctx: this.ctx,
14839 chart: this
14840 });
14841 scales[scale.id] = scale;
14842 }
14843 scale.init(scaleOptions, options);
14844 });
14845 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(updated, (hasUpdated, id)=>{
14846 if (!hasUpdated) {
14847 delete scales[id];
14848 }
14849 });
14850 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scales, (scale)=>{
14851 layouts.configure(this, scale, scale.options);
14852 layouts.addBox(this, scale);
14853 });
14854 }
14855 _updateMetasets() {
14856 const metasets = this._metasets;
14857 const numData = this.data.datasets.length;
14858 const numMeta = metasets.length;
14859 metasets.sort((a, b)=>a.index - b.index);
14860 if (numMeta > numData) {
14861 for(let i = numData; i < numMeta; ++i){
14862 this._destroyDatasetMeta(i);
14863 }
14864 metasets.splice(numData, numMeta - numData);
14865 }
14866 this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
14867 }
14868 _removeUnreferencedMetasets() {
14869 const { _metasets: metasets , data: { datasets } } = this;
14870 if (metasets.length > datasets.length) {
14871 delete this._stacks;
14872 }
14873 metasets.forEach((meta, index)=>{
14874 if (datasets.filter((x)=>x === meta._dataset).length === 0) {
14875 this._destroyDatasetMeta(index);
14876 }
14877 });
14878 }
14879 buildOrUpdateControllers() {
14880 const newControllers = [];
14881 const datasets = this.data.datasets;
14882 let i, ilen;
14883 this._removeUnreferencedMetasets();
14884 for(i = 0, ilen = datasets.length; i < ilen; i++){
14885 const dataset = datasets[i];
14886 let meta = this.getDatasetMeta(i);
14887 const type = dataset.type || this.config.type;
14888 if (meta.type && meta.type !== type) {
14889 this._destroyDatasetMeta(i);
14890 meta = this.getDatasetMeta(i);
14891 }
14892 meta.type = type;
14893 meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
14894 meta.order = dataset.order || 0;
14895 meta.index = i;
14896 meta.label = '' + dataset.label;
14897 meta.visible = this.isDatasetVisible(i);
14898 if (meta.controller) {
14899 meta.controller.updateIndex(i);
14900 meta.controller.linkScales();
14901 } else {
14902 const ControllerClass = registry.getController(type);
14903 const { datasetElementType , dataElementType } = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type];
14904 Object.assign(ControllerClass, {
14905 dataElementType: registry.getElement(dataElementType),
14906 datasetElementType: datasetElementType && registry.getElement(datasetElementType)
14907 });
14908 meta.controller = new ControllerClass(this, i);
14909 newControllers.push(meta.controller);
14910 }
14911 }
14912 this._updateMetasets();
14913 return newControllers;
14914 }
14915 _resetElements() {
14916 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.data.datasets, (dataset, datasetIndex)=>{
14917 this.getDatasetMeta(datasetIndex).controller.reset();
14918 }, this);
14919 }
14920 reset() {
14921 this._resetElements();
14922 this.notifyPlugins('reset');
14923 }
14924 update(mode) {
14925 const config = this.config;
14926 config.update();
14927 const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
14928 const animsDisabled = this._animationsDisabled = !options.animation;
14929 this._updateScales();
14930 this._checkEventBindings();
14931 this._updateHiddenIndices();
14932 this._plugins.invalidate();
14933 if (this.notifyPlugins('beforeUpdate', {
14934 mode,
14935 cancelable: true
14936 }) === false) {
14937 return;
14938 }
14939 const newControllers = this.buildOrUpdateControllers();
14940 this.notifyPlugins('beforeElementsUpdate');
14941 let minPadding = 0;
14942 for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){
14943 const { controller } = this.getDatasetMeta(i);
14944 const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
14945 controller.buildOrUpdateElements(reset);
14946 minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
14947 }
14948 minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
14949 this._updateLayout(minPadding);
14950 if (!animsDisabled) {
14951 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(newControllers, (controller)=>{
14952 controller.reset();
14953 });
14954 }
14955 this._updateDatasets(mode);
14956 this.notifyPlugins('afterUpdate', {
14957 mode
14958 });
14959 this._layers.sort(compare2Level('z', '_idx'));
14960 const { _active , _lastEvent } = this;
14961 if (_lastEvent) {
14962 this._eventHandler(_lastEvent, true);
14963 } else if (_active.length) {
14964 this._updateHoverStyles(_active, _active, true);
14965 }
14966 this.render();
14967 }
14968 _updateScales() {
14969 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.scales, (scale)=>{
14970 layouts.removeBox(this, scale);
14971 });
14972 this.ensureScalesHaveIDs();
14973 this.buildOrUpdateScales();
14974 }
14975 _checkEventBindings() {
14976 const options = this.options;
14977 const existingEvents = new Set(Object.keys(this._listeners));
14978 const newEvents = new Set(options.events);
14979 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
14980 this.unbindEvents();
14981 this.bindEvents();
14982 }
14983 }
14984 _updateHiddenIndices() {
14985 const { _hiddenIndices } = this;
14986 const changes = this._getUniformDataChanges() || [];
14987 for (const { method , start , count } of changes){
14988 const move = method === '_removeElements' ? -count : count;
14989 moveNumericKeys(_hiddenIndices, start, move);
14990 }
14991 }
14992 _getUniformDataChanges() {
14993 const _dataChanges = this._dataChanges;
14994 if (!_dataChanges || !_dataChanges.length) {
14995 return;
14996 }
14997 this._dataChanges = [];
14998 const datasetCount = this.data.datasets.length;
14999 const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(',')));
15000 const changeSet = makeSet(0);
15001 for(let i = 1; i < datasetCount; i++){
15002 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(changeSet, makeSet(i))) {
15003 return;
15004 }
15005 }
15006 return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({
15007 method: a[1],
15008 start: +a[2],
15009 count: +a[3]
15010 }));
15011 }
15012 _updateLayout(minPadding) {
15013 if (this.notifyPlugins('beforeLayout', {
15014 cancelable: true
15015 }) === false) {
15016 return;
15017 }
15018 layouts.update(this, this.width, this.height, minPadding);
15019 const area = this.chartArea;
15020 const noArea = area.width <= 0 || area.height <= 0;
15021 this._layers = [];
15022 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.boxes, (box)=>{
15023 if (noArea && box.position === 'chartArea') {
15024 return;
15025 }
15026 if (box.configure) {
15027 box.configure();
15028 }
15029 this._layers.push(...box._layers());
15030 }, this);
15031 this._layers.forEach((item, index)=>{
15032 item._idx = index;
15033 });
15034 this.notifyPlugins('afterLayout');
15035 }
15036 _updateDatasets(mode) {
15037 if (this.notifyPlugins('beforeDatasetsUpdate', {
15038 mode,
15039 cancelable: true
15040 }) === false) {
15041 return;
15042 }
15043 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15044 this.getDatasetMeta(i).controller.configure();
15045 }
15046 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15047 this._updateDataset(i, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(mode) ? mode({
15048 datasetIndex: i
15049 }) : mode);
15050 }
15051 this.notifyPlugins('afterDatasetsUpdate', {
15052 mode
15053 });
15054 }
15055 _updateDataset(index, mode) {
15056 const meta = this.getDatasetMeta(index);
15057 const args = {
15058 meta,
15059 index,
15060 mode,
15061 cancelable: true
15062 };
15063 if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {
15064 return;
15065 }
15066 meta.controller._update(mode);
15067 args.cancelable = false;
15068 this.notifyPlugins('afterDatasetUpdate', args);
15069 }
15070 render() {
15071 if (this.notifyPlugins('beforeRender', {
15072 cancelable: true
15073 }) === false) {
15074 return;
15075 }
15076 if (animator.has(this)) {
15077 if (this.attached && !animator.running(this)) {
15078 animator.start(this);
15079 }
15080 } else {
15081 this.draw();
15082 onAnimationsComplete({
15083 chart: this
15084 });
15085 }
15086 }
15087 draw() {
15088 let i;
15089 if (this._resizeBeforeDraw) {
15090 const { width , height } = this._resizeBeforeDraw;
15091 this._resizeBeforeDraw = null;
15092 this._resize(width, height);
15093 }
15094 this.clear();
15095 if (this.width <= 0 || this.height <= 0) {
15096 return;
15097 }
15098 if (this.notifyPlugins('beforeDraw', {
15099 cancelable: true
15100 }) === false) {
15101 return;
15102 }
15103 const layers = this._layers;
15104 for(i = 0; i < layers.length && layers[i].z <= 0; ++i){
15105 layers[i].draw(this.chartArea);
15106 }
15107 this._drawDatasets();
15108 for(; i < layers.length; ++i){
15109 layers[i].draw(this.chartArea);
15110 }
15111 this.notifyPlugins('afterDraw');
15112 }
15113 _getSortedDatasetMetas(filterVisible) {
15114 const metasets = this._sortedMetasets;
15115 const result = [];
15116 let i, ilen;
15117 for(i = 0, ilen = metasets.length; i < ilen; ++i){
15118 const meta = metasets[i];
15119 if (!filterVisible || meta.visible) {
15120 result.push(meta);
15121 }
15122 }
15123 return result;
15124 }
15125 getSortedVisibleDatasetMetas() {
15126 return this._getSortedDatasetMetas(true);
15127 }
15128 _drawDatasets() {
15129 if (this.notifyPlugins('beforeDatasetsDraw', {
15130 cancelable: true
15131 }) === false) {
15132 return;
15133 }
15134 const metasets = this.getSortedVisibleDatasetMetas();
15135 for(let i = metasets.length - 1; i >= 0; --i){
15136 this._drawDataset(metasets[i]);
15137 }
15138 this.notifyPlugins('afterDatasetsDraw');
15139 }
15140 _drawDataset(meta) {
15141 const ctx = this.ctx;
15142 const args = {
15143 meta,
15144 index: meta.index,
15145 cancelable: true
15146 };
15147 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(this, meta);
15148 if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
15149 return;
15150 }
15151 if (clip) {
15152 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, clip);
15153 }
15154 meta.controller.draw();
15155 if (clip) {
15156 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
15157 }
15158 args.cancelable = false;
15159 this.notifyPlugins('afterDatasetDraw', args);
15160 }
15161 isPointInArea(point) {
15162 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(point, this.chartArea, this._minPadding);
15163 }
15164 getElementsAtEventForMode(e, mode, options, useFinalPosition) {
15165 const method = Interaction.modes[mode];
15166 if (typeof method === 'function') {
15167 return method(this, e, options, useFinalPosition);
15168 }
15169 return [];
15170 }
15171 getDatasetMeta(datasetIndex) {
15172 const dataset = this.data.datasets[datasetIndex];
15173 const metasets = this._metasets;
15174 let meta = metasets.filter((x)=>x && x._dataset === dataset).pop();
15175 if (!meta) {
15176 meta = {
15177 type: null,
15178 data: [],
15179 dataset: null,
15180 controller: null,
15181 hidden: null,
15182 xAxisID: null,
15183 yAxisID: null,
15184 order: dataset && dataset.order || 0,
15185 index: datasetIndex,
15186 _dataset: dataset,
15187 _parsed: [],
15188 _sorted: false
15189 };
15190 metasets.push(meta);
15191 }
15192 return meta;
15193 }
15194 getContext() {
15195 return this.$context || (this.$context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(null, {
15196 chart: this,
15197 type: 'chart'
15198 }));
15199 }
15200 getVisibleDatasetCount() {
15201 return this.getSortedVisibleDatasetMetas().length;
15202 }
15203 isDatasetVisible(datasetIndex) {
15204 const dataset = this.data.datasets[datasetIndex];
15205 if (!dataset) {
15206 return false;
15207 }
15208 const meta = this.getDatasetMeta(datasetIndex);
15209 return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
15210 }
15211 setDatasetVisibility(datasetIndex, visible) {
15212 const meta = this.getDatasetMeta(datasetIndex);
15213 meta.hidden = !visible;
15214 }
15215 toggleDataVisibility(index) {
15216 this._hiddenIndices[index] = !this._hiddenIndices[index];
15217 }
15218 getDataVisibility(index) {
15219 return !this._hiddenIndices[index];
15220 }
15221 _updateVisibility(datasetIndex, dataIndex, visible) {
15222 const mode = visible ? 'show' : 'hide';
15223 const meta = this.getDatasetMeta(datasetIndex);
15224 const anims = meta.controller._resolveAnimations(undefined, mode);
15225 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(dataIndex)) {
15226 meta.data[dataIndex].hidden = !visible;
15227 this.update();
15228 } else {
15229 this.setDatasetVisibility(datasetIndex, visible);
15230 anims.update(meta, {
15231 visible
15232 });
15233 this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined);
15234 }
15235 }
15236 hide(datasetIndex, dataIndex) {
15237 this._updateVisibility(datasetIndex, dataIndex, false);
15238 }
15239 show(datasetIndex, dataIndex) {
15240 this._updateVisibility(datasetIndex, dataIndex, true);
15241 }
15242 _destroyDatasetMeta(datasetIndex) {
15243 const meta = this._metasets[datasetIndex];
15244 if (meta && meta.controller) {
15245 meta.controller._destroy();
15246 }
15247 delete this._metasets[datasetIndex];
15248 }
15249 _stop() {
15250 let i, ilen;
15251 this.stop();
15252 animator.remove(this);
15253 for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15254 this._destroyDatasetMeta(i);
15255 }
15256 }
15257 destroy() {
15258 this.notifyPlugins('beforeDestroy');
15259 const { canvas , ctx } = this;
15260 this._stop();
15261 this.config.clearCache();
15262 if (canvas) {
15263 this.unbindEvents();
15264 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(canvas, ctx);
15265 this.platform.releaseContext(ctx);
15266 this.canvas = null;
15267 this.ctx = null;
15268 }
15269 delete instances[this.id];
15270 this.notifyPlugins('afterDestroy');
15271 }
15272 toBase64Image(...args) {
15273 return this.canvas.toDataURL(...args);
15274 }
15275 bindEvents() {
15276 this.bindUserEvents();
15277 if (this.options.responsive) {
15278 this.bindResponsiveEvents();
15279 } else {
15280 this.attached = true;
15281 }
15282 }
15283 bindUserEvents() {
15284 const listeners = this._listeners;
15285 const platform = this.platform;
15286 const _add = (type, listener)=>{
15287 platform.addEventListener(this, type, listener);
15288 listeners[type] = listener;
15289 };
15290 const listener = (e, x, y)=>{
15291 e.offsetX = x;
15292 e.offsetY = y;
15293 this._eventHandler(e);
15294 };
15295 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.options.events, (type)=>_add(type, listener));
15296 }
15297 bindResponsiveEvents() {
15298 if (!this._responsiveListeners) {
15299 this._responsiveListeners = {};
15300 }
15301 const listeners = this._responsiveListeners;
15302 const platform = this.platform;
15303 const _add = (type, listener)=>{
15304 platform.addEventListener(this, type, listener);
15305 listeners[type] = listener;
15306 };
15307 const _remove = (type, listener)=>{
15308 if (listeners[type]) {
15309 platform.removeEventListener(this, type, listener);
15310 delete listeners[type];
15311 }
15312 };
15313 const listener = (width, height)=>{
15314 if (this.canvas) {
15315 this.resize(width, height);
15316 }
15317 };
15318 let detached;
15319 const attached = ()=>{
15320 _remove('attach', attached);
15321 this.attached = true;
15322 this.resize();
15323 _add('resize', listener);
15324 _add('detach', detached);
15325 };
15326 detached = ()=>{
15327 this.attached = false;
15328 _remove('resize', listener);
15329 this._stop();
15330 this._resize(0, 0);
15331 _add('attach', attached);
15332 };
15333 if (platform.isAttached(this.canvas)) {
15334 attached();
15335 } else {
15336 detached();
15337 }
15338 }
15339 unbindEvents() {
15340 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._listeners, (listener, type)=>{
15341 this.platform.removeEventListener(this, type, listener);
15342 });
15343 this._listeners = {};
15344 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._responsiveListeners, (listener, type)=>{
15345 this.platform.removeEventListener(this, type, listener);
15346 });
15347 this._responsiveListeners = undefined;
15348 }
15349 updateHoverStyle(items, mode, enabled) {
15350 const prefix = enabled ? 'set' : 'remove';
15351 let meta, item, i, ilen;
15352 if (mode === 'dataset') {
15353 meta = this.getDatasetMeta(items[0].datasetIndex);
15354 meta.controller['_' + prefix + 'DatasetHoverStyle']();
15355 }
15356 for(i = 0, ilen = items.length; i < ilen; ++i){
15357 item = items[i];
15358 const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
15359 if (controller) {
15360 controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
15361 }
15362 }
15363 }
15364 getActiveElements() {
15365 return this._active || [];
15366 }
15367 setActiveElements(activeElements) {
15368 const lastActive = this._active || [];
15369 const active = activeElements.map(({ datasetIndex , index })=>{
15370 const meta = this.getDatasetMeta(datasetIndex);
15371 if (!meta) {
15372 throw new Error('No dataset found at index ' + datasetIndex);
15373 }
15374 return {
15375 datasetIndex,
15376 element: meta.data[index],
15377 index
15378 };
15379 });
15380 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15381 if (changed) {
15382 this._active = active;
15383 this._lastEvent = null;
15384 this._updateHoverStyles(active, lastActive);
15385 }
15386 }
15387 notifyPlugins(hook, args, filter) {
15388 return this._plugins.notify(this, hook, args, filter);
15389 }
15390 isPluginEnabled(pluginId) {
15391 return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1;
15392 }
15393 _updateHoverStyles(active, lastActive, replay) {
15394 const hoverOptions = this.options.hover;
15395 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index));
15396 const deactivated = diff(lastActive, active);
15397 const activated = replay ? active : diff(active, lastActive);
15398 if (deactivated.length) {
15399 this.updateHoverStyle(deactivated, hoverOptions.mode, false);
15400 }
15401 if (activated.length && hoverOptions.mode) {
15402 this.updateHoverStyle(activated, hoverOptions.mode, true);
15403 }
15404 }
15405 _eventHandler(e, replay) {
15406 const args = {
15407 event: e,
15408 replay,
15409 cancelable: true,
15410 inChartArea: this.isPointInArea(e)
15411 };
15412 const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type);
15413 if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
15414 return;
15415 }
15416 const changed = this._handleEvent(e, replay, args.inChartArea);
15417 args.cancelable = false;
15418 this.notifyPlugins('afterEvent', args, eventFilter);
15419 if (changed || args.changed) {
15420 this.render();
15421 }
15422 return this;
15423 }
15424 _handleEvent(e, replay, inChartArea) {
15425 const { _active: lastActive = [] , options } = this;
15426 const useFinalPosition = replay;
15427 const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
15428 const isClick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aj)(e);
15429 const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
15430 if (inChartArea) {
15431 this._lastEvent = null;
15432 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onHover, [
15433 e,
15434 active,
15435 this
15436 ], this);
15437 if (isClick) {
15438 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onClick, [
15439 e,
15440 active,
15441 this
15442 ], this);
15443 }
15444 }
15445 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15446 if (changed || replay) {
15447 this._active = active;
15448 this._updateHoverStyles(active, lastActive, replay);
15449 }
15450 this._lastEvent = lastEvent;
15451 return changed;
15452 }
15453 _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
15454 if (e.type === 'mouseout') {
15455 return [];
15456 }
15457 if (!inChartArea) {
15458 return lastActive;
15459 }
15460 const hoverOptions = this.options.hover;
15461 return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
15462 }
15463 }
15464 function invalidatePlugins() {
15465 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(Chart.instances, (chart)=>chart._plugins.invalidate());
15466 }
15467
15468 function clipSelf(ctx, element, endAngle) {
15469 const { startAngle , x , y , outerRadius , innerRadius , options } = element;
15470 const { borderWidth , borderJoinStyle } = options;
15471 const outerAngleClip = Math.min(borderWidth / outerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15472 ctx.beginPath();
15473 ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2);
15474 if (innerRadius > 0) {
15475 const innerAngleClip = Math.min(borderWidth / innerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15476 ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true);
15477 } else {
15478 const clipWidth = Math.min(borderWidth / 2, outerRadius * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15479 if (borderJoinStyle === 'round') {
15480 ctx.arc(x, y, clipWidth, endAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2, startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2, true);
15481 } else if (borderJoinStyle === 'bevel') {
15482 const r = 2 * clipWidth * clipWidth;
15483 const endX = -r * Math.cos(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15484 const endY = -r * Math.sin(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15485 const startX = r * Math.cos(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15486 const startY = r * Math.sin(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15487 ctx.lineTo(endX, endY);
15488 ctx.lineTo(startX, startY);
15489 }
15490 }
15491 ctx.closePath();
15492 ctx.moveTo(0, 0);
15493 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
15494 ctx.clip('evenodd');
15495 }
15496 function clipArc(ctx, element, endAngle) {
15497 const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element;
15498 let angleMargin = pixelMargin / outerRadius;
15499 // Draw an inner border by clipping the arc and drawing a double-width border
15500 // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
15501 ctx.beginPath();
15502 ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
15503 if (innerRadius > pixelMargin) {
15504 angleMargin = pixelMargin / innerRadius;
15505 ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
15506 } else {
15507 ctx.arc(x, y, pixelMargin, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15508 }
15509 ctx.closePath();
15510 ctx.clip();
15511 }
15512 function toRadiusCorners(value) {
15513 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.am)(value, [
15514 'outerStart',
15515 'outerEnd',
15516 'innerStart',
15517 'innerEnd'
15518 ]);
15519 }
15520 /**
15521 * Parse border radius from the provided options
15522 */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
15523 const o = toRadiusCorners(arc.options.borderRadius);
15524 const halfThickness = (outerRadius - innerRadius) / 2;
15525 const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
15526 // Outer limits are complicated. We want to compute the available angular distance at
15527 // a radius of outerRadius - borderRadius because for small angular distances, this term limits.
15528 // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners.
15529 //
15530 // If the borderRadius is large, that value can become negative.
15531 // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius
15532 // we know that the thickness term will dominate and compute the limits at that point
15533 const computeOuterLimit = (val)=>{
15534 const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
15535 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(val, 0, Math.min(halfThickness, outerArcLimit));
15536 };
15537 return {
15538 outerStart: computeOuterLimit(o.outerStart),
15539 outerEnd: computeOuterLimit(o.outerEnd),
15540 innerStart: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerStart, 0, innerLimit),
15541 innerEnd: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerEnd, 0, innerLimit)
15542 };
15543 }
15544 /**
15545 * Convert (r, 𝜃) to (x, y)
15546 */ function rThetaToXY(r, theta, x, y) {
15547 return {
15548 x: x + r * Math.cos(theta),
15549 y: y + r * Math.sin(theta)
15550 };
15551 }
15552 /**
15553 * Path the arc, respecting border radius by separating into left and right halves.
15554 *
15555 * Start End
15556 *
15557 * 1--->a--->2 Outer
15558 * / \
15559 * 8 3
15560 * | |
15561 * | |
15562 * 7 4
15563 * \ /
15564 * 6<---b<---5 Inner
15565 */ function pathArc(ctx, element, offset, spacing, end, circular) {
15566 const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element;
15567 const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
15568 const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
15569 let spacingOffset = 0;
15570 const alpha = end - start;
15571 if (spacing) {
15572 // When spacing is present, it is the same for all items
15573 // So we adjust the start and end angle of the arc such that
15574 // the distance is the same as it would be without the spacing
15575 const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
15576 const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
15577 const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
15578 const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha;
15579 spacingOffset = (alpha - adjustedAngle) / 2;
15580 }
15581 const beta = Math.max(0.001, alpha * outerRadius - offset / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P) / outerRadius;
15582 const angleOffset = (alpha - beta) / 2;
15583 const startAngle = start + angleOffset + spacingOffset;
15584 const endAngle = end - angleOffset - spacingOffset;
15585 const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
15586 const outerStartAdjustedRadius = outerRadius - outerStart;
15587 const outerEndAdjustedRadius = outerRadius - outerEnd;
15588 const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
15589 const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
15590 const innerStartAdjustedRadius = innerRadius + innerStart;
15591 const innerEndAdjustedRadius = innerRadius + innerEnd;
15592 const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
15593 const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
15594 ctx.beginPath();
15595 if (circular) {
15596 // The first arc segments from point 1 to point a to point 2
15597 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;
15598 ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);
15599 ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);
15600 // The corner segment from point 2 to point 3
15601 if (outerEnd > 0) {
15602 const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
15603 ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15604 }
15605 // The line from point 3 to point 4
15606 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
15607 ctx.lineTo(p4.x, p4.y);
15608 // The corner segment from point 4 to point 5
15609 if (innerEnd > 0) {
15610 const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
15611 ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, innerEndAdjustedAngle + Math.PI);
15612 }
15613 // The inner arc from point 5 to point b to point 6
15614 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;
15615 ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);
15616 ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);
15617 // The corner segment from point 6 to point 7
15618 if (innerStart > 0) {
15619 const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
15620 ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15621 }
15622 // The line from point 7 to point 8
15623 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
15624 ctx.lineTo(p8.x, p8.y);
15625 // The corner segment from point 8 to point 1
15626 if (outerStart > 0) {
15627 const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
15628 ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, outerStartAdjustedAngle);
15629 }
15630 } else {
15631 ctx.moveTo(x, y);
15632 const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;
15633 const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;
15634 ctx.lineTo(outerStartX, outerStartY);
15635 const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;
15636 const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;
15637 ctx.lineTo(outerEndX, outerEndY);
15638 }
15639 ctx.closePath();
15640 }
15641 function drawArc(ctx, element, offset, spacing, circular) {
15642 const { fullCircles , startAngle , circumference } = element;
15643 let endAngle = element.endAngle;
15644 if (fullCircles) {
15645 pathArc(ctx, element, offset, spacing, endAngle, circular);
15646 for(let i = 0; i < fullCircles; ++i){
15647 ctx.fill();
15648 }
15649 if (!isNaN(circumference)) {
15650 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15651 }
15652 }
15653 pathArc(ctx, element, offset, spacing, endAngle, circular);
15654 ctx.fill();
15655 return endAngle;
15656 }
15657 function drawBorder(ctx, element, offset, spacing, circular) {
15658 const { fullCircles , startAngle , circumference , options } = element;
15659 const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options;
15660 const inner = options.borderAlign === 'inner';
15661 if (!borderWidth) {
15662 return;
15663 }
15664 ctx.setLineDash(borderDash || []);
15665 ctx.lineDashOffset = borderDashOffset;
15666 if (inner) {
15667 ctx.lineWidth = borderWidth * 2;
15668 ctx.lineJoin = borderJoinStyle || 'round';
15669 } else {
15670 ctx.lineWidth = borderWidth;
15671 ctx.lineJoin = borderJoinStyle || 'bevel';
15672 }
15673 let endAngle = element.endAngle;
15674 if (fullCircles) {
15675 pathArc(ctx, element, offset, spacing, endAngle, circular);
15676 for(let i = 0; i < fullCircles; ++i){
15677 ctx.stroke();
15678 }
15679 if (!isNaN(circumference)) {
15680 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15681 }
15682 }
15683 if (inner) {
15684 clipArc(ctx, element, endAngle);
15685 }
15686 if (options.selfJoin && endAngle - startAngle >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P && borderRadius === 0 && borderJoinStyle !== 'miter') {
15687 clipSelf(ctx, element, endAngle);
15688 }
15689 if (!fullCircles) {
15690 pathArc(ctx, element, offset, spacing, endAngle, circular);
15691 ctx.stroke();
15692 }
15693 }
15694 class ArcElement extends Element {
15695 static id = 'arc';
15696 static defaults = {
15697 borderAlign: 'center',
15698 borderColor: '#fff',
15699 borderDash: [],
15700 borderDashOffset: 0,
15701 borderJoinStyle: undefined,
15702 borderRadius: 0,
15703 borderWidth: 2,
15704 offset: 0,
15705 spacing: 0,
15706 angle: undefined,
15707 circular: true,
15708 selfJoin: false
15709 };
15710 static defaultRoutes = {
15711 backgroundColor: 'backgroundColor'
15712 };
15713 static descriptors = {
15714 _scriptable: true,
15715 _indexable: (name)=>name !== 'borderDash'
15716 };
15717 circumference;
15718 endAngle;
15719 fullCircles;
15720 innerRadius;
15721 outerRadius;
15722 pixelMargin;
15723 startAngle;
15724 constructor(cfg){
15725 super();
15726 this.options = undefined;
15727 this.circumference = undefined;
15728 this.startAngle = undefined;
15729 this.endAngle = undefined;
15730 this.innerRadius = undefined;
15731 this.outerRadius = undefined;
15732 this.pixelMargin = 0;
15733 this.fullCircles = 0;
15734 if (cfg) {
15735 Object.assign(this, cfg);
15736 }
15737 }
15738 inRange(chartX, chartY, useFinalPosition) {
15739 const point = this.getProps([
15740 'x',
15741 'y'
15742 ], useFinalPosition);
15743 const { angle , distance } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(point, {
15744 x: chartX,
15745 y: chartY
15746 });
15747 const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([
15748 'startAngle',
15749 'endAngle',
15750 'innerRadius',
15751 'outerRadius',
15752 'circumference'
15753 ], useFinalPosition);
15754 const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;
15755 const _circumference = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(circumference, endAngle - startAngle);
15756 const nonZeroBetween = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle) && startAngle !== endAngle;
15757 const betweenAngles = _circumference >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || nonZeroBetween;
15758 const withinRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(distance, innerRadius + rAdjust, outerRadius + rAdjust);
15759 return betweenAngles && withinRadius;
15760 }
15761 getCenterPoint(useFinalPosition) {
15762 const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([
15763 'x',
15764 'y',
15765 'startAngle',
15766 'endAngle',
15767 'innerRadius',
15768 'outerRadius'
15769 ], useFinalPosition);
15770 const { offset , spacing } = this.options;
15771 const halfAngle = (startAngle + endAngle) / 2;
15772 const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
15773 return {
15774 x: x + Math.cos(halfAngle) * halfRadius,
15775 y: y + Math.sin(halfAngle) * halfRadius
15776 };
15777 }
15778 tooltipPosition(useFinalPosition) {
15779 return this.getCenterPoint(useFinalPosition);
15780 }
15781 draw(ctx) {
15782 const { options , circumference } = this;
15783 const offset = (options.offset || 0) / 4;
15784 const spacing = (options.spacing || 0) / 2;
15785 const circular = options.circular;
15786 this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0;
15787 this.fullCircles = circumference > _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T ? Math.floor(circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) : 0;
15788 if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
15789 return;
15790 }
15791 ctx.save();
15792 const halfAngle = (this.startAngle + this.endAngle) / 2;
15793 ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
15794 const fix = 1 - Math.sin(Math.min(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, circumference || 0));
15795 const radiusOffset = offset * fix;
15796 ctx.fillStyle = options.backgroundColor;
15797 ctx.strokeStyle = options.borderColor;
15798 drawArc(ctx, this, radiusOffset, spacing, circular);
15799 drawBorder(ctx, this, radiusOffset, spacing, circular);
15800 ctx.restore();
15801 }
15802 }
15803
15804 function setStyle(ctx, options, style = options) {
15805 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderCapStyle, options.borderCapStyle);
15806 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDash, options.borderDash));
15807 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDashOffset, options.borderDashOffset);
15808 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderJoinStyle, options.borderJoinStyle);
15809 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderWidth, options.borderWidth);
15810 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderColor, options.borderColor);
15811 }
15812 function lineTo(ctx, previous, target) {
15813 ctx.lineTo(target.x, target.y);
15814 }
15815 function getLineMethod(options) {
15816 if (options.stepped) {
15817 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.at;
15818 }
15819 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15820 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.au;
15821 }
15822 return lineTo;
15823 }
15824 function pathVars(points, segment, params = {}) {
15825 const count = points.length;
15826 const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params;
15827 const { start: segmentStart , end: segmentEnd } = segment;
15828 const start = Math.max(paramsStart, segmentStart);
15829 const end = Math.min(paramsEnd, segmentEnd);
15830 const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;
15831 return {
15832 count,
15833 start,
15834 loop: segment.loop,
15835 ilen: end < start && !outside ? count + end - start : end - start
15836 };
15837 }
15838 function pathSegment(ctx, line, segment, params) {
15839 const { points , options } = line;
15840 const { count , start , loop , ilen } = pathVars(points, segment, params);
15841 const lineMethod = getLineMethod(options);
15842 let { move =true , reverse } = params || {};
15843 let i, point, prev;
15844 for(i = 0; i <= ilen; ++i){
15845 point = points[(start + (reverse ? ilen - i : i)) % count];
15846 if (point.skip) {
15847 continue;
15848 } else if (move) {
15849 ctx.moveTo(point.x, point.y);
15850 move = false;
15851 } else {
15852 lineMethod(ctx, prev, point, reverse, options.stepped);
15853 }
15854 prev = point;
15855 }
15856 if (loop) {
15857 point = points[(start + (reverse ? ilen : 0)) % count];
15858 lineMethod(ctx, prev, point, reverse, options.stepped);
15859 }
15860 return !!loop;
15861 }
15862 function fastPathSegment(ctx, line, segment, params) {
15863 const points = line.points;
15864 const { count , start , ilen } = pathVars(points, segment, params);
15865 const { move =true , reverse } = params || {};
15866 let avgX = 0;
15867 let countX = 0;
15868 let i, point, prevX, minY, maxY, lastY;
15869 const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count;
15870 const drawX = ()=>{
15871 if (minY !== maxY) {
15872 ctx.lineTo(avgX, maxY);
15873 ctx.lineTo(avgX, minY);
15874 ctx.lineTo(avgX, lastY);
15875 }
15876 };
15877 if (move) {
15878 point = points[pointIndex(0)];
15879 ctx.moveTo(point.x, point.y);
15880 }
15881 for(i = 0; i <= ilen; ++i){
15882 point = points[pointIndex(i)];
15883 if (point.skip) {
15884 continue;
15885 }
15886 const x = point.x;
15887 const y = point.y;
15888 const truncX = x | 0;
15889 if (truncX === prevX) {
15890 if (y < minY) {
15891 minY = y;
15892 } else if (y > maxY) {
15893 maxY = y;
15894 }
15895 avgX = (countX * avgX + x) / ++countX;
15896 } else {
15897 drawX();
15898 ctx.lineTo(x, y);
15899 prevX = truncX;
15900 countX = 0;
15901 minY = maxY = y;
15902 }
15903 lastY = y;
15904 }
15905 drawX();
15906 }
15907 function _getSegmentMethod(line) {
15908 const opts = line.options;
15909 const borderDash = opts.borderDash && opts.borderDash.length;
15910 const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;
15911 return useFastPath ? fastPathSegment : pathSegment;
15912 }
15913 function _getInterpolationMethod(options) {
15914 if (options.stepped) {
15915 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aq;
15916 }
15917 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15918 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ar;
15919 }
15920 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.as;
15921 }
15922 function strokePathWithCache(ctx, line, start, count) {
15923 let path = line._path;
15924 if (!path) {
15925 path = line._path = new Path2D();
15926 if (line.path(path, start, count)) {
15927 path.closePath();
15928 }
15929 }
15930 setStyle(ctx, line.options);
15931 ctx.stroke(path);
15932 }
15933 function strokePathDirect(ctx, line, start, count) {
15934 const { segments , options } = line;
15935 const segmentMethod = _getSegmentMethod(line);
15936 for (const segment of segments){
15937 setStyle(ctx, options, segment.style);
15938 ctx.beginPath();
15939 if (segmentMethod(ctx, line, segment, {
15940 start,
15941 end: start + count - 1
15942 })) {
15943 ctx.closePath();
15944 }
15945 ctx.stroke();
15946 }
15947 }
15948 const usePath2D = typeof Path2D === 'function';
15949 function draw(ctx, line, start, count) {
15950 if (usePath2D && !line.options.segment) {
15951 strokePathWithCache(ctx, line, start, count);
15952 } else {
15953 strokePathDirect(ctx, line, start, count);
15954 }
15955 }
15956 class LineElement extends Element {
15957 static id = 'line';
15958 static defaults = {
15959 borderCapStyle: 'butt',
15960 borderDash: [],
15961 borderDashOffset: 0,
15962 borderJoinStyle: 'miter',
15963 borderWidth: 3,
15964 capBezierPoints: true,
15965 cubicInterpolationMode: 'default',
15966 fill: false,
15967 spanGaps: false,
15968 stepped: false,
15969 tension: 0
15970 };
15971 static defaultRoutes = {
15972 backgroundColor: 'backgroundColor',
15973 borderColor: 'borderColor'
15974 };
15975 static descriptors = {
15976 _scriptable: true,
15977 _indexable: (name)=>name !== 'borderDash' && name !== 'fill'
15978 };
15979 constructor(cfg){
15980 super();
15981 this.animated = true;
15982 this.options = undefined;
15983 this._chart = undefined;
15984 this._loop = undefined;
15985 this._fullLoop = undefined;
15986 this._path = undefined;
15987 this._points = undefined;
15988 this._segments = undefined;
15989 this._decimated = false;
15990 this._pointsUpdated = false;
15991 this._datasetIndex = undefined;
15992 if (cfg) {
15993 Object.assign(this, cfg);
15994 }
15995 }
15996 updateControlPoints(chartArea, indexAxis) {
15997 const options = this.options;
15998 if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {
15999 const loop = options.spanGaps ? this._loop : this._fullLoop;
16000 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.an)(this._points, options, chartArea, loop, indexAxis);
16001 this._pointsUpdated = true;
16002 }
16003 }
16004 set points(points) {
16005 this._points = points;
16006 delete this._segments;
16007 delete this._path;
16008 this._pointsUpdated = false;
16009 }
16010 get points() {
16011 return this._points;
16012 }
16013 get segments() {
16014 return this._segments || (this._segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ao)(this, this.options.segment));
16015 }
16016 first() {
16017 const segments = this.segments;
16018 const points = this.points;
16019 return segments.length && points[segments[0].start];
16020 }
16021 last() {
16022 const segments = this.segments;
16023 const points = this.points;
16024 const count = segments.length;
16025 return count && points[segments[count - 1].end];
16026 }
16027 interpolate(point, property) {
16028 const options = this.options;
16029 const value = point[property];
16030 const points = this.points;
16031 const segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(this, {
16032 property,
16033 start: value,
16034 end: value
16035 });
16036 if (!segments.length) {
16037 return;
16038 }
16039 const result = [];
16040 const _interpolate = _getInterpolationMethod(options);
16041 let i, ilen;
16042 for(i = 0, ilen = segments.length; i < ilen; ++i){
16043 const { start , end } = segments[i];
16044 const p1 = points[start];
16045 const p2 = points[end];
16046 if (p1 === p2) {
16047 result.push(p1);
16048 continue;
16049 }
16050 const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
16051 const interpolated = _interpolate(p1, p2, t, options.stepped);
16052 interpolated[property] = point[property];
16053 result.push(interpolated);
16054 }
16055 return result.length === 1 ? result[0] : result;
16056 }
16057 pathSegment(ctx, segment, params) {
16058 const segmentMethod = _getSegmentMethod(this);
16059 return segmentMethod(ctx, this, segment, params);
16060 }
16061 path(ctx, start, count) {
16062 const segments = this.segments;
16063 const segmentMethod = _getSegmentMethod(this);
16064 let loop = this._loop;
16065 start = start || 0;
16066 count = count || this.points.length - start;
16067 for (const segment of segments){
16068 loop &= segmentMethod(ctx, this, segment, {
16069 start,
16070 end: start + count - 1
16071 });
16072 }
16073 return !!loop;
16074 }
16075 draw(ctx, chartArea, start, count) {
16076 const options = this.options || {};
16077 const points = this.points || [];
16078 if (points.length && options.borderWidth) {
16079 ctx.save();
16080 draw(ctx, this, start, count);
16081 ctx.restore();
16082 }
16083 if (this.animated) {
16084 this._pointsUpdated = false;
16085 this._path = undefined;
16086 }
16087 }
16088 }
16089
16090 function inRange$1(el, pos, axis, useFinalPosition) {
16091 const options = el.options;
16092 const { [axis]: value } = el.getProps([
16093 axis
16094 ], useFinalPosition);
16095 return Math.abs(pos - value) < options.radius + options.hitRadius;
16096 }
16097 class PointElement extends Element {
16098 static id = 'point';
16099 parsed;
16100 skip;
16101 stop;
16102 /**
16103 * @type {any}
16104 */ static defaults = {
16105 borderWidth: 1,
16106 hitRadius: 1,
16107 hoverBorderWidth: 1,
16108 hoverRadius: 4,
16109 pointStyle: 'circle',
16110 radius: 3,
16111 rotation: 0
16112 };
16113 /**
16114 * @type {any}
16115 */ static defaultRoutes = {
16116 backgroundColor: 'backgroundColor',
16117 borderColor: 'borderColor'
16118 };
16119 constructor(cfg){
16120 super();
16121 this.options = undefined;
16122 this.parsed = undefined;
16123 this.skip = undefined;
16124 this.stop = undefined;
16125 if (cfg) {
16126 Object.assign(this, cfg);
16127 }
16128 }
16129 inRange(mouseX, mouseY, useFinalPosition) {
16130 const options = this.options;
16131 const { x , y } = this.getProps([
16132 'x',
16133 'y'
16134 ], useFinalPosition);
16135 return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2);
16136 }
16137 inXRange(mouseX, useFinalPosition) {
16138 return inRange$1(this, mouseX, 'x', useFinalPosition);
16139 }
16140 inYRange(mouseY, useFinalPosition) {
16141 return inRange$1(this, mouseY, 'y', useFinalPosition);
16142 }
16143 getCenterPoint(useFinalPosition) {
16144 const { x , y } = this.getProps([
16145 'x',
16146 'y'
16147 ], useFinalPosition);
16148 return {
16149 x,
16150 y
16151 };
16152 }
16153 size(options) {
16154 options = options || this.options || {};
16155 let radius = options.radius || 0;
16156 radius = Math.max(radius, radius && options.hoverRadius || 0);
16157 const borderWidth = radius && options.borderWidth || 0;
16158 return (radius + borderWidth) * 2;
16159 }
16160 draw(ctx, area) {
16161 const options = this.options;
16162 if (this.skip || options.radius < 0.1 || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(this, area, this.size(options) / 2)) {
16163 return;
16164 }
16165 ctx.strokeStyle = options.borderColor;
16166 ctx.lineWidth = options.borderWidth;
16167 ctx.fillStyle = options.backgroundColor;
16168 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, options, this.x, this.y);
16169 }
16170 getRange() {
16171 const options = this.options || {};
16172 // @ts-expect-error Fallbacks should never be hit in practice
16173 return options.radius + options.hitRadius;
16174 }
16175 }
16176
16177 function getBarBounds(bar, useFinalPosition) {
16178 const { x , y , base , width , height } = bar.getProps([
16179 'x',
16180 'y',
16181 'base',
16182 'width',
16183 'height'
16184 ], useFinalPosition);
16185 let left, right, top, bottom, half;
16186 if (bar.horizontal) {
16187 half = height / 2;
16188 left = Math.min(x, base);
16189 right = Math.max(x, base);
16190 top = y - half;
16191 bottom = y + half;
16192 } else {
16193 half = width / 2;
16194 left = x - half;
16195 right = x + half;
16196 top = Math.min(y, base);
16197 bottom = Math.max(y, base);
16198 }
16199 return {
16200 left,
16201 top,
16202 right,
16203 bottom
16204 };
16205 }
16206 function skipOrLimit(skip, value, min, max) {
16207 return skip ? 0 : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(value, min, max);
16208 }
16209 function parseBorderWidth(bar, maxW, maxH) {
16210 const value = bar.options.borderWidth;
16211 const skip = bar.borderSkipped;
16212 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ax)(value);
16213 return {
16214 t: skipOrLimit(skip.top, o.top, 0, maxH),
16215 r: skipOrLimit(skip.right, o.right, 0, maxW),
16216 b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
16217 l: skipOrLimit(skip.left, o.left, 0, maxW)
16218 };
16219 }
16220 function parseBorderRadius(bar, maxW, maxH) {
16221 const { enableBorderRadius } = bar.getProps([
16222 'enableBorderRadius'
16223 ]);
16224 const value = bar.options.borderRadius;
16225 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(value);
16226 const maxR = Math.min(maxW, maxH);
16227 const skip = bar.borderSkipped;
16228 const enableBorder = enableBorderRadius || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value);
16229 return {
16230 topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
16231 topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
16232 bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
16233 bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
16234 };
16235 }
16236 function boundingRects(bar) {
16237 const bounds = getBarBounds(bar);
16238 const width = bounds.right - bounds.left;
16239 const height = bounds.bottom - bounds.top;
16240 const border = parseBorderWidth(bar, width / 2, height / 2);
16241 const radius = parseBorderRadius(bar, width / 2, height / 2);
16242 return {
16243 outer: {
16244 x: bounds.left,
16245 y: bounds.top,
16246 w: width,
16247 h: height,
16248 radius
16249 },
16250 inner: {
16251 x: bounds.left + border.l,
16252 y: bounds.top + border.t,
16253 w: width - border.l - border.r,
16254 h: height - border.t - border.b,
16255 radius: {
16256 topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
16257 topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
16258 bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
16259 bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))
16260 }
16261 }
16262 };
16263 }
16264 function inRange(bar, x, y, useFinalPosition) {
16265 const skipX = x === null;
16266 const skipY = y === null;
16267 const skipBoth = skipX && skipY;
16268 const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
16269 return bounds && (skipX || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, bounds.left, bounds.right)) && (skipY || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, bounds.top, bounds.bottom));
16270 }
16271 function hasRadius(radius) {
16272 return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
16273 }
16274 function addNormalRectPath(ctx, rect) {
16275 ctx.rect(rect.x, rect.y, rect.w, rect.h);
16276 }
16277 function inflateRect(rect, amount, refRect = {}) {
16278 const x = rect.x !== refRect.x ? -amount : 0;
16279 const y = rect.y !== refRect.y ? -amount : 0;
16280 const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;
16281 const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;
16282 return {
16283 x: rect.x + x,
16284 y: rect.y + y,
16285 w: rect.w + w,
16286 h: rect.h + h,
16287 radius: rect.radius
16288 };
16289 }
16290 class BarElement extends Element {
16291 static id = 'bar';
16292 static defaults = {
16293 borderSkipped: 'start',
16294 borderWidth: 0,
16295 borderRadius: 0,
16296 inflateAmount: 'auto',
16297 pointStyle: undefined
16298 };
16299 static defaultRoutes = {
16300 backgroundColor: 'backgroundColor',
16301 borderColor: 'borderColor'
16302 };
16303 constructor(cfg){
16304 super();
16305 this.options = undefined;
16306 this.horizontal = undefined;
16307 this.base = undefined;
16308 this.width = undefined;
16309 this.height = undefined;
16310 this.inflateAmount = undefined;
16311 if (cfg) {
16312 Object.assign(this, cfg);
16313 }
16314 }
16315 draw(ctx) {
16316 const { inflateAmount , options: { borderColor , backgroundColor } } = this;
16317 const { inner , outer } = boundingRects(this);
16318 const addRectPath = hasRadius(outer.radius) ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw : addNormalRectPath;
16319 ctx.save();
16320 if (outer.w !== inner.w || outer.h !== inner.h) {
16321 ctx.beginPath();
16322 addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
16323 ctx.clip();
16324 addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
16325 ctx.fillStyle = borderColor;
16326 ctx.fill('evenodd');
16327 }
16328 ctx.beginPath();
16329 addRectPath(ctx, inflateRect(inner, inflateAmount));
16330 ctx.fillStyle = backgroundColor;
16331 ctx.fill();
16332 ctx.restore();
16333 }
16334 inRange(mouseX, mouseY, useFinalPosition) {
16335 return inRange(this, mouseX, mouseY, useFinalPosition);
16336 }
16337 inXRange(mouseX, useFinalPosition) {
16338 return inRange(this, mouseX, null, useFinalPosition);
16339 }
16340 inYRange(mouseY, useFinalPosition) {
16341 return inRange(this, null, mouseY, useFinalPosition);
16342 }
16343 getCenterPoint(useFinalPosition) {
16344 const { x , y , base , horizontal } = this.getProps([
16345 'x',
16346 'y',
16347 'base',
16348 'horizontal'
16349 ], useFinalPosition);
16350 return {
16351 x: horizontal ? (x + base) / 2 : x,
16352 y: horizontal ? y : (y + base) / 2
16353 };
16354 }
16355 getRange(axis) {
16356 return axis === 'x' ? this.width / 2 : this.height / 2;
16357 }
16358 }
16359
16360 var elements = /*#__PURE__*/Object.freeze({
16361 __proto__: null,
16362 ArcElement: ArcElement,
16363 BarElement: BarElement,
16364 LineElement: LineElement,
16365 PointElement: PointElement
16366 });
16367
16368 const BORDER_COLORS = [
16369 'rgb(54, 162, 235)',
16370 'rgb(255, 99, 132)',
16371 'rgb(255, 159, 64)',
16372 'rgb(255, 205, 86)',
16373 'rgb(75, 192, 192)',
16374 'rgb(153, 102, 255)',
16375 'rgb(201, 203, 207)' // grey
16376 ];
16377 // Border colors with 50% transparency
16378 const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)'));
16379 function getBorderColor(i) {
16380 return BORDER_COLORS[i % BORDER_COLORS.length];
16381 }
16382 function getBackgroundColor(i) {
16383 return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length];
16384 }
16385 function colorizeDefaultDataset(dataset, i) {
16386 dataset.borderColor = getBorderColor(i);
16387 dataset.backgroundColor = getBackgroundColor(i);
16388 return ++i;
16389 }
16390 function colorizeDoughnutDataset(dataset, i) {
16391 dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++));
16392 return i;
16393 }
16394 function colorizePolarAreaDataset(dataset, i) {
16395 dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++));
16396 return i;
16397 }
16398 function getColorizer(chart) {
16399 let i = 0;
16400 return (dataset, datasetIndex)=>{
16401 const controller = chart.getDatasetMeta(datasetIndex).controller;
16402 if (controller instanceof DoughnutController) {
16403 i = colorizeDoughnutDataset(dataset, i);
16404 } else if (controller instanceof PolarAreaController) {
16405 i = colorizePolarAreaDataset(dataset, i);
16406 } else if (controller) {
16407 i = colorizeDefaultDataset(dataset, i);
16408 }
16409 };
16410 }
16411 function containsColorsDefinitions(descriptors) {
16412 let k;
16413 for(k in descriptors){
16414 if (descriptors[k].borderColor || descriptors[k].backgroundColor) {
16415 return true;
16416 }
16417 }
16418 return false;
16419 }
16420 function containsColorsDefinition(descriptor) {
16421 return descriptor && (descriptor.borderColor || descriptor.backgroundColor);
16422 }
16423 function containsDefaultColorsDefenitions() {
16424 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.borderColor !== 'rgba(0,0,0,0.1)' || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.backgroundColor !== 'rgba(0,0,0,0.1)';
16425 }
16426 var plugin_colors = {
16427 id: 'colors',
16428 defaults: {
16429 enabled: true,
16430 forceOverride: false
16431 },
16432 beforeLayout (chart, _args, options) {
16433 if (!options.enabled) {
16434 return;
16435 }
16436 const { data: { datasets } , options: chartOptions } = chart.config;
16437 const { elements } = chartOptions;
16438 const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions();
16439 if (!options.forceOverride && containsColorDefenition) {
16440 return;
16441 }
16442 const colorizer = getColorizer(chart);
16443 datasets.forEach(colorizer);
16444 }
16445 };
16446
16447 function lttbDecimation(data, start, count, availableWidth, options) {
16448 const samples = options.samples || availableWidth;
16449 if (samples >= count) {
16450 return data.slice(start, start + count);
16451 }
16452 const decimated = [];
16453 const bucketWidth = (count - 2) / (samples - 2);
16454 let sampledIndex = 0;
16455 const endIndex = start + count - 1;
16456 let a = start;
16457 let i, maxAreaPoint, maxArea, area, nextA;
16458 decimated[sampledIndex++] = data[a];
16459 for(i = 0; i < samples - 2; i++){
16460 let avgX = 0;
16461 let avgY = 0;
16462 let j;
16463 const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;
16464 const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;
16465 const avgRangeLength = avgRangeEnd - avgRangeStart;
16466 for(j = avgRangeStart; j < avgRangeEnd; j++){
16467 avgX += data[j].x;
16468 avgY += data[j].y;
16469 }
16470 avgX /= avgRangeLength;
16471 avgY /= avgRangeLength;
16472 const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;
16473 const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;
16474 const { x: pointAx , y: pointAy } = data[a];
16475 maxArea = area = -1;
16476 for(j = rangeOffs; j < rangeTo; j++){
16477 area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy));
16478 if (area > maxArea) {
16479 maxArea = area;
16480 maxAreaPoint = data[j];
16481 nextA = j;
16482 }
16483 }
16484 decimated[sampledIndex++] = maxAreaPoint;
16485 a = nextA;
16486 }
16487 decimated[sampledIndex++] = data[endIndex];
16488 return decimated;
16489 }
16490 function minMaxDecimation(data, start, count, availableWidth) {
16491 let avgX = 0;
16492 let countX = 0;
16493 let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
16494 const decimated = [];
16495 const endIndex = start + count - 1;
16496 const xMin = data[start].x;
16497 const xMax = data[endIndex].x;
16498 const dx = xMax - xMin;
16499 for(i = start; i < start + count; ++i){
16500 point = data[i];
16501 x = (point.x - xMin) / dx * availableWidth;
16502 y = point.y;
16503 const truncX = x | 0;
16504 if (truncX === prevX) {
16505 if (y < minY) {
16506 minY = y;
16507 minIndex = i;
16508 } else if (y > maxY) {
16509 maxY = y;
16510 maxIndex = i;
16511 }
16512 avgX = (countX * avgX + point.x) / ++countX;
16513 } else {
16514 const lastIndex = i - 1;
16515 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(minIndex) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(maxIndex)) {
16516 const intermediateIndex1 = Math.min(minIndex, maxIndex);
16517 const intermediateIndex2 = Math.max(minIndex, maxIndex);
16518 if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
16519 decimated.push({
16520 ...data[intermediateIndex1],
16521 x: avgX
16522 });
16523 }
16524 if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
16525 decimated.push({
16526 ...data[intermediateIndex2],
16527 x: avgX
16528 });
16529 }
16530 }
16531 if (i > 0 && lastIndex !== startIndex) {
16532 decimated.push(data[lastIndex]);
16533 }
16534 decimated.push(point);
16535 prevX = truncX;
16536 countX = 0;
16537 minY = maxY = y;
16538 minIndex = maxIndex = startIndex = i;
16539 }
16540 }
16541 return decimated;
16542 }
16543 function cleanDecimatedDataset(dataset) {
16544 if (dataset._decimated) {
16545 const data = dataset._data;
16546 delete dataset._decimated;
16547 delete dataset._data;
16548 Object.defineProperty(dataset, 'data', {
16549 configurable: true,
16550 enumerable: true,
16551 writable: true,
16552 value: data
16553 });
16554 }
16555 }
16556 function cleanDecimatedData(chart) {
16557 chart.data.datasets.forEach((dataset)=>{
16558 cleanDecimatedDataset(dataset);
16559 });
16560 }
16561 function getStartAndCountOfVisiblePointsSimplified(meta, points) {
16562 const pointCount = points.length;
16563 let start = 0;
16564 let count;
16565 const { iScale } = meta;
16566 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
16567 if (minDefined) {
16568 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(points, iScale.axis, min).lo, 0, pointCount - 1);
16569 }
16570 if (maxDefined) {
16571 count = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(points, iScale.axis, max).hi + 1, start, pointCount) - start;
16572 } else {
16573 count = pointCount - start;
16574 }
16575 return {
16576 start,
16577 count
16578 };
16579 }
16580 var plugin_decimation = {
16581 id: 'decimation',
16582 defaults: {
16583 algorithm: 'min-max',
16584 enabled: false
16585 },
16586 beforeElementsUpdate: (chart, args, options)=>{
16587 if (!options.enabled) {
16588 cleanDecimatedData(chart);
16589 return;
16590 }
16591 const availableWidth = chart.width;
16592 chart.data.datasets.forEach((dataset, datasetIndex)=>{
16593 const { _data , indexAxis } = dataset;
16594 const meta = chart.getDatasetMeta(datasetIndex);
16595 const data = _data || dataset.data;
16596 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
16597 indexAxis,
16598 chart.options.indexAxis
16599 ]) === 'y') {
16600 return;
16601 }
16602 if (!meta.controller.supportsDecimation) {
16603 return;
16604 }
16605 const xAxis = chart.scales[meta.xAxisID];
16606 if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
16607 return;
16608 }
16609 if (chart.options.parsing) {
16610 return;
16611 }
16612 let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data);
16613 const threshold = options.threshold || 4 * availableWidth;
16614 if (count <= threshold) {
16615 cleanDecimatedDataset(dataset);
16616 return;
16617 }
16618 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(_data)) {
16619 dataset._data = data;
16620 delete dataset.data;
16621 Object.defineProperty(dataset, 'data', {
16622 configurable: true,
16623 enumerable: true,
16624 get: function() {
16625 return this._decimated;
16626 },
16627 set: function(d) {
16628 this._data = d;
16629 }
16630 });
16631 }
16632 let decimated;
16633 switch(options.algorithm){
16634 case 'lttb':
16635 decimated = lttbDecimation(data, start, count, availableWidth, options);
16636 break;
16637 case 'min-max':
16638 decimated = minMaxDecimation(data, start, count, availableWidth);
16639 break;
16640 default:
16641 throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
16642 }
16643 dataset._decimated = decimated;
16644 });
16645 },
16646 destroy (chart) {
16647 cleanDecimatedData(chart);
16648 }
16649 };
16650
16651 function _segments(line, target, property) {
16652 const segments = line.segments;
16653 const points = line.points;
16654 const tpoints = target.points;
16655 const parts = [];
16656 for (const segment of segments){
16657 let { start , end } = segment;
16658 end = _findSegmentEnd(start, end, points);
16659 const bounds = _getBounds(property, points[start], points[end], segment.loop);
16660 if (!target.segments) {
16661 parts.push({
16662 source: segment,
16663 target: bounds,
16664 start: points[start],
16665 end: points[end]
16666 });
16667 continue;
16668 }
16669 const targetSegments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(target, bounds);
16670 for (const tgt of targetSegments){
16671 const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);
16672 const fillSources = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.az)(segment, points, subBounds);
16673 for (const fillSource of fillSources){
16674 parts.push({
16675 source: fillSource,
16676 target: tgt,
16677 start: {
16678 [property]: _getEdge(bounds, subBounds, 'start', Math.max)
16679 },
16680 end: {
16681 [property]: _getEdge(bounds, subBounds, 'end', Math.min)
16682 }
16683 });
16684 }
16685 }
16686 }
16687 return parts;
16688 }
16689 function _getBounds(property, first, last, loop) {
16690 if (loop) {
16691 return;
16692 }
16693 let start = first[property];
16694 let end = last[property];
16695 if (property === 'angle') {
16696 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(start);
16697 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(end);
16698 }
16699 return {
16700 property,
16701 start,
16702 end
16703 };
16704 }
16705 function _pointsFromSegments(boundary, line) {
16706 const { x =null , y =null } = boundary || {};
16707 const linePoints = line.points;
16708 const points = [];
16709 line.segments.forEach(({ start , end })=>{
16710 end = _findSegmentEnd(start, end, linePoints);
16711 const first = linePoints[start];
16712 const last = linePoints[end];
16713 if (y !== null) {
16714 points.push({
16715 x: first.x,
16716 y
16717 });
16718 points.push({
16719 x: last.x,
16720 y
16721 });
16722 } else if (x !== null) {
16723 points.push({
16724 x,
16725 y: first.y
16726 });
16727 points.push({
16728 x,
16729 y: last.y
16730 });
16731 }
16732 });
16733 return points;
16734 }
16735 function _findSegmentEnd(start, end, points) {
16736 for(; end > start; end--){
16737 const point = points[end];
16738 if (!isNaN(point.x) && !isNaN(point.y)) {
16739 break;
16740 }
16741 }
16742 return end;
16743 }
16744 function _getEdge(a, b, prop, fn) {
16745 if (a && b) {
16746 return fn(a[prop], b[prop]);
16747 }
16748 return a ? a[prop] : b ? b[prop] : 0;
16749 }
16750
16751 function _createBoundaryLine(boundary, line) {
16752 let points = [];
16753 let _loop = false;
16754 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(boundary)) {
16755 _loop = true;
16756 points = boundary;
16757 } else {
16758 points = _pointsFromSegments(boundary, line);
16759 }
16760 return points.length ? new LineElement({
16761 points,
16762 options: {
16763 tension: 0
16764 },
16765 _loop,
16766 _fullLoop: _loop
16767 }) : null;
16768 }
16769 function _shouldApplyFill(source) {
16770 return source && source.fill !== false;
16771 }
16772
16773 function _resolveTarget(sources, index, propagate) {
16774 const source = sources[index];
16775 let fill = source.fill;
16776 const visited = [
16777 index
16778 ];
16779 let target;
16780 if (!propagate) {
16781 return fill;
16782 }
16783 while(fill !== false && visited.indexOf(fill) === -1){
16784 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16785 return fill;
16786 }
16787 target = sources[fill];
16788 if (!target) {
16789 return false;
16790 }
16791 if (target.visible) {
16792 return fill;
16793 }
16794 visited.push(fill);
16795 fill = target.fill;
16796 }
16797 return false;
16798 }
16799 function _decodeFill(line, index, count) {
16800 const fill = parseFillOption(line);
16801 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16802 return isNaN(fill.value) ? false : fill;
16803 }
16804 let target = parseFloat(fill);
16805 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(target) && Math.floor(target) === target) {
16806 return decodeTargetIndex(fill[0], index, target, count);
16807 }
16808 return [
16809 'origin',
16810 'start',
16811 'end',
16812 'stack',
16813 'shape'
16814 ].indexOf(fill) >= 0 && fill;
16815 }
16816 function decodeTargetIndex(firstCh, index, target, count) {
16817 if (firstCh === '-' || firstCh === '+') {
16818 target = index + target;
16819 }
16820 if (target === index || target < 0 || target >= count) {
16821 return false;
16822 }
16823 return target;
16824 }
16825 function _getTargetPixel(fill, scale) {
16826 let pixel = null;
16827 if (fill === 'start') {
16828 pixel = scale.bottom;
16829 } else if (fill === 'end') {
16830 pixel = scale.top;
16831 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16832 pixel = scale.getPixelForValue(fill.value);
16833 } else if (scale.getBasePixel) {
16834 pixel = scale.getBasePixel();
16835 }
16836 return pixel;
16837 }
16838 function _getTargetValue(fill, scale, startValue) {
16839 let value;
16840 if (fill === 'start') {
16841 value = startValue;
16842 } else if (fill === 'end') {
16843 value = scale.options.reverse ? scale.min : scale.max;
16844 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16845 value = fill.value;
16846 } else {
16847 value = scale.getBaseValue();
16848 }
16849 return value;
16850 }
16851 function parseFillOption(line) {
16852 const options = line.options;
16853 const fillOption = options.fill;
16854 let fill = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(fillOption && fillOption.target, fillOption);
16855 if (fill === undefined) {
16856 fill = !!options.backgroundColor;
16857 }
16858 if (fill === false || fill === null) {
16859 return false;
16860 }
16861 if (fill === true) {
16862 return 'origin';
16863 }
16864 return fill;
16865 }
16866
16867 function _buildStackLine(source) {
16868 const { scale , index , line } = source;
16869 const points = [];
16870 const segments = line.segments;
16871 const sourcePoints = line.points;
16872 const linesBelow = getLinesBelow(scale, index);
16873 linesBelow.push(_createBoundaryLine({
16874 x: null,
16875 y: scale.bottom
16876 }, line));
16877 for(let i = 0; i < segments.length; i++){
16878 const segment = segments[i];
16879 for(let j = segment.start; j <= segment.end; j++){
16880 addPointsBelow(points, sourcePoints[j], linesBelow);
16881 }
16882 }
16883 return new LineElement({
16884 points,
16885 options: {}
16886 });
16887 }
16888 function getLinesBelow(scale, index) {
16889 const below = [];
16890 const metas = scale.getMatchingVisibleMetas('line');
16891 for(let i = 0; i < metas.length; i++){
16892 const meta = metas[i];
16893 if (meta.index === index) {
16894 break;
16895 }
16896 if (!meta.hidden) {
16897 below.unshift(meta.dataset);
16898 }
16899 }
16900 return below;
16901 }
16902 function addPointsBelow(points, sourcePoint, linesBelow) {
16903 const postponed = [];
16904 for(let j = 0; j < linesBelow.length; j++){
16905 const line = linesBelow[j];
16906 const { first , last , point } = findPoint(line, sourcePoint, 'x');
16907 if (!point || first && last) {
16908 continue;
16909 }
16910 if (first) {
16911 postponed.unshift(point);
16912 } else {
16913 points.push(point);
16914 if (!last) {
16915 break;
16916 }
16917 }
16918 }
16919 points.push(...postponed);
16920 }
16921 function findPoint(line, sourcePoint, property) {
16922 const point = line.interpolate(sourcePoint, property);
16923 if (!point) {
16924 return {};
16925 }
16926 const pointValue = point[property];
16927 const segments = line.segments;
16928 const linePoints = line.points;
16929 let first = false;
16930 let last = false;
16931 for(let i = 0; i < segments.length; i++){
16932 const segment = segments[i];
16933 const firstValue = linePoints[segment.start][property];
16934 const lastValue = linePoints[segment.end][property];
16935 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(pointValue, firstValue, lastValue)) {
16936 first = pointValue === firstValue;
16937 last = pointValue === lastValue;
16938 break;
16939 }
16940 }
16941 return {
16942 first,
16943 last,
16944 point
16945 };
16946 }
16947
16948 class simpleArc {
16949 constructor(opts){
16950 this.x = opts.x;
16951 this.y = opts.y;
16952 this.radius = opts.radius;
16953 }
16954 pathSegment(ctx, bounds, opts) {
16955 const { x , y , radius } = this;
16956 bounds = bounds || {
16957 start: 0,
16958 end: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T
16959 };
16960 ctx.arc(x, y, radius, bounds.end, bounds.start, true);
16961 return !opts.bounds;
16962 }
16963 interpolate(point) {
16964 const { x , y , radius } = this;
16965 const angle = point.angle;
16966 return {
16967 x: x + Math.cos(angle) * radius,
16968 y: y + Math.sin(angle) * radius,
16969 angle
16970 };
16971 }
16972 }
16973
16974 function _getTarget(source) {
16975 const { chart , fill , line } = source;
16976 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16977 return getLineByIndex(chart, fill);
16978 }
16979 if (fill === 'stack') {
16980 return _buildStackLine(source);
16981 }
16982 if (fill === 'shape') {
16983 return true;
16984 }
16985 const boundary = computeBoundary(source);
16986 if (boundary instanceof simpleArc) {
16987 return boundary;
16988 }
16989 return _createBoundaryLine(boundary, line);
16990 }
16991 function getLineByIndex(chart, index) {
16992 const meta = chart.getDatasetMeta(index);
16993 const visible = meta && chart.isDatasetVisible(index);
16994 return visible ? meta.dataset : null;
16995 }
16996 function computeBoundary(source) {
16997 const scale = source.scale || {};
16998 if (scale.getPointPositionForValue) {
16999 return computeCircularBoundary(source);
17000 }
17001 return computeLinearBoundary(source);
17002 }
17003 function computeLinearBoundary(source) {
17004 const { scale ={} , fill } = source;
17005 const pixel = _getTargetPixel(fill, scale);
17006 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(pixel)) {
17007 const horizontal = scale.isHorizontal();
17008 return {
17009 x: horizontal ? pixel : null,
17010 y: horizontal ? null : pixel
17011 };
17012 }
17013 return null;
17014 }
17015 function computeCircularBoundary(source) {
17016 const { scale , fill } = source;
17017 const options = scale.options;
17018 const length = scale.getLabels().length;
17019 const start = options.reverse ? scale.max : scale.min;
17020 const value = _getTargetValue(fill, scale, start);
17021 const target = [];
17022 if (options.grid.circular) {
17023 const center = scale.getPointPositionForValue(0, start);
17024 return new simpleArc({
17025 x: center.x,
17026 y: center.y,
17027 radius: scale.getDistanceFromCenterForValue(value)
17028 });
17029 }
17030 for(let i = 0; i < length; ++i){
17031 target.push(scale.getPointPositionForValue(i, value));
17032 }
17033 return target;
17034 }
17035
17036 function _drawfill(ctx, source, area) {
17037 const target = _getTarget(source);
17038 const { chart , index , line , scale , axis } = source;
17039 const lineOpts = line.options;
17040 const fillOption = lineOpts.fill;
17041 const color = lineOpts.backgroundColor;
17042 const { above =color , below =color } = fillOption || {};
17043 const meta = chart.getDatasetMeta(index);
17044 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(chart, meta);
17045 if (target && line.points.length) {
17046 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
17047 doFill(ctx, {
17048 line,
17049 target,
17050 above,
17051 below,
17052 area,
17053 scale,
17054 axis,
17055 clip
17056 });
17057 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17058 }
17059 }
17060 function doFill(ctx, cfg) {
17061 const { line , target , above , below , area , scale , clip } = cfg;
17062 const property = line._loop ? 'angle' : cfg.axis;
17063 ctx.save();
17064 let fillColor = below;
17065 if (below !== above) {
17066 if (property === 'x') {
17067 clipVertical(ctx, target, area.top);
17068 fill(ctx, {
17069 line,
17070 target,
17071 color: above,
17072 scale,
17073 property,
17074 clip
17075 });
17076 ctx.restore();
17077 ctx.save();
17078 clipVertical(ctx, target, area.bottom);
17079 } else if (property === 'y') {
17080 clipHorizontal(ctx, target, area.left);
17081 fill(ctx, {
17082 line,
17083 target,
17084 color: below,
17085 scale,
17086 property,
17087 clip
17088 });
17089 ctx.restore();
17090 ctx.save();
17091 clipHorizontal(ctx, target, area.right);
17092 fillColor = above;
17093 }
17094 }
17095 fill(ctx, {
17096 line,
17097 target,
17098 color: fillColor,
17099 scale,
17100 property,
17101 clip
17102 });
17103 ctx.restore();
17104 }
17105 function clipVertical(ctx, target, clipY) {
17106 const { segments , points } = target;
17107 let first = true;
17108 let lineLoop = false;
17109 ctx.beginPath();
17110 for (const segment of segments){
17111 const { start , end } = segment;
17112 const firstPoint = points[start];
17113 const lastPoint = points[_findSegmentEnd(start, end, points)];
17114 if (first) {
17115 ctx.moveTo(firstPoint.x, firstPoint.y);
17116 first = false;
17117 } else {
17118 ctx.lineTo(firstPoint.x, clipY);
17119 ctx.lineTo(firstPoint.x, firstPoint.y);
17120 }
17121 lineLoop = !!target.pathSegment(ctx, segment, {
17122 move: lineLoop
17123 });
17124 if (lineLoop) {
17125 ctx.closePath();
17126 } else {
17127 ctx.lineTo(lastPoint.x, clipY);
17128 }
17129 }
17130 ctx.lineTo(target.first().x, clipY);
17131 ctx.closePath();
17132 ctx.clip();
17133 }
17134 function clipHorizontal(ctx, target, clipX) {
17135 const { segments , points } = target;
17136 let first = true;
17137 let lineLoop = false;
17138 ctx.beginPath();
17139 for (const segment of segments){
17140 const { start , end } = segment;
17141 const firstPoint = points[start];
17142 const lastPoint = points[_findSegmentEnd(start, end, points)];
17143 if (first) {
17144 ctx.moveTo(firstPoint.x, firstPoint.y);
17145 first = false;
17146 } else {
17147 ctx.lineTo(clipX, firstPoint.y);
17148 ctx.lineTo(firstPoint.x, firstPoint.y);
17149 }
17150 lineLoop = !!target.pathSegment(ctx, segment, {
17151 move: lineLoop
17152 });
17153 if (lineLoop) {
17154 ctx.closePath();
17155 } else {
17156 ctx.lineTo(clipX, lastPoint.y);
17157 }
17158 }
17159 ctx.lineTo(clipX, target.first().y);
17160 ctx.closePath();
17161 ctx.clip();
17162 }
17163 function fill(ctx, cfg) {
17164 const { line , target , property , color , scale , clip } = cfg;
17165 const segments = _segments(line, target, property);
17166 for (const { source: src , target: tgt , start , end } of segments){
17167 const { style: { backgroundColor =color } = {} } = src;
17168 const notShape = target !== true;
17169 ctx.save();
17170 ctx.fillStyle = backgroundColor;
17171 clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end));
17172 ctx.beginPath();
17173 const lineLoop = !!line.pathSegment(ctx, src);
17174 let loop;
17175 if (notShape) {
17176 if (lineLoop) {
17177 ctx.closePath();
17178 } else {
17179 interpolatedLineTo(ctx, target, end, property);
17180 }
17181 const targetLoop = !!target.pathSegment(ctx, tgt, {
17182 move: lineLoop,
17183 reverse: true
17184 });
17185 loop = lineLoop && targetLoop;
17186 if (!loop) {
17187 interpolatedLineTo(ctx, target, start, property);
17188 }
17189 }
17190 ctx.closePath();
17191 ctx.fill(loop ? 'evenodd' : 'nonzero');
17192 ctx.restore();
17193 }
17194 }
17195 function clipBounds(ctx, scale, clip, bounds) {
17196 const chartArea = scale.chart.chartArea;
17197 const { property , start , end } = bounds || {};
17198 if (property === 'x' || property === 'y') {
17199 let left, top, right, bottom;
17200 if (property === 'x') {
17201 left = start;
17202 top = chartArea.top;
17203 right = end;
17204 bottom = chartArea.bottom;
17205 } else {
17206 left = chartArea.left;
17207 top = start;
17208 right = chartArea.right;
17209 bottom = end;
17210 }
17211 ctx.beginPath();
17212 if (clip) {
17213 left = Math.max(left, clip.left);
17214 right = Math.min(right, clip.right);
17215 top = Math.max(top, clip.top);
17216 bottom = Math.min(bottom, clip.bottom);
17217 }
17218 ctx.rect(left, top, right - left, bottom - top);
17219 ctx.clip();
17220 }
17221 }
17222 function interpolatedLineTo(ctx, target, point, property) {
17223 const interpolatedPoint = target.interpolate(point, property);
17224 if (interpolatedPoint) {
17225 ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
17226 }
17227 }
17228
17229 var index = {
17230 id: 'filler',
17231 afterDatasetsUpdate (chart, _args, options) {
17232 const count = (chart.data.datasets || []).length;
17233 const sources = [];
17234 let meta, i, line, source;
17235 for(i = 0; i < count; ++i){
17236 meta = chart.getDatasetMeta(i);
17237 line = meta.dataset;
17238 source = null;
17239 if (line && line.options && line instanceof LineElement) {
17240 source = {
17241 visible: chart.isDatasetVisible(i),
17242 index: i,
17243 fill: _decodeFill(line, i, count),
17244 chart,
17245 axis: meta.controller.options.indexAxis,
17246 scale: meta.vScale,
17247 line
17248 };
17249 }
17250 meta.$filler = source;
17251 sources.push(source);
17252 }
17253 for(i = 0; i < count; ++i){
17254 source = sources[i];
17255 if (!source || source.fill === false) {
17256 continue;
17257 }
17258 source.fill = _resolveTarget(sources, i, options.propagate);
17259 }
17260 },
17261 beforeDraw (chart, _args, options) {
17262 const draw = options.drawTime === 'beforeDraw';
17263 const metasets = chart.getSortedVisibleDatasetMetas();
17264 const area = chart.chartArea;
17265 for(let i = metasets.length - 1; i >= 0; --i){
17266 const source = metasets[i].$filler;
17267 if (!source) {
17268 continue;
17269 }
17270 source.line.updateControlPoints(area, source.axis);
17271 if (draw && source.fill) {
17272 _drawfill(chart.ctx, source, area);
17273 }
17274 }
17275 },
17276 beforeDatasetsDraw (chart, _args, options) {
17277 if (options.drawTime !== 'beforeDatasetsDraw') {
17278 return;
17279 }
17280 const metasets = chart.getSortedVisibleDatasetMetas();
17281 for(let i = metasets.length - 1; i >= 0; --i){
17282 const source = metasets[i].$filler;
17283 if (_shouldApplyFill(source)) {
17284 _drawfill(chart.ctx, source, chart.chartArea);
17285 }
17286 }
17287 },
17288 beforeDatasetDraw (chart, args, options) {
17289 const source = args.meta.$filler;
17290 if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') {
17291 return;
17292 }
17293 _drawfill(chart.ctx, source, chart.chartArea);
17294 },
17295 defaults: {
17296 propagate: true,
17297 drawTime: 'beforeDatasetDraw'
17298 }
17299 };
17300
17301 const getBoxSize = (labelOpts, fontSize)=>{
17302 let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts;
17303 if (labelOpts.usePointStyle) {
17304 boxHeight = Math.min(boxHeight, fontSize);
17305 boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);
17306 }
17307 return {
17308 boxWidth,
17309 boxHeight,
17310 itemHeight: Math.max(fontSize, boxHeight)
17311 };
17312 };
17313 const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
17314 class Legend extends Element {
17315 constructor(config){
17316 super();
17317 this._added = false;
17318 this.legendHitBoxes = [];
17319 this._hoveredItem = null;
17320 this.doughnutMode = false;
17321 this.chart = config.chart;
17322 this.options = config.options;
17323 this.ctx = config.ctx;
17324 this.legendItems = undefined;
17325 this.columnSizes = undefined;
17326 this.lineWidths = undefined;
17327 this.maxHeight = undefined;
17328 this.maxWidth = undefined;
17329 this.top = undefined;
17330 this.bottom = undefined;
17331 this.left = undefined;
17332 this.right = undefined;
17333 this.height = undefined;
17334 this.width = undefined;
17335 this._margins = undefined;
17336 this.position = undefined;
17337 this.weight = undefined;
17338 this.fullSize = undefined;
17339 }
17340 update(maxWidth, maxHeight, margins) {
17341 this.maxWidth = maxWidth;
17342 this.maxHeight = maxHeight;
17343 this._margins = margins;
17344 this.setDimensions();
17345 this.buildLabels();
17346 this.fit();
17347 }
17348 setDimensions() {
17349 if (this.isHorizontal()) {
17350 this.width = this.maxWidth;
17351 this.left = this._margins.left;
17352 this.right = this.width;
17353 } else {
17354 this.height = this.maxHeight;
17355 this.top = this._margins.top;
17356 this.bottom = this.height;
17357 }
17358 }
17359 buildLabels() {
17360 const labelOpts = this.options.labels || {};
17361 let legendItems = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(labelOpts.generateLabels, [
17362 this.chart
17363 ], this) || [];
17364 if (labelOpts.filter) {
17365 legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data));
17366 }
17367 if (labelOpts.sort) {
17368 legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data));
17369 }
17370 if (this.options.reverse) {
17371 legendItems.reverse();
17372 }
17373 this.legendItems = legendItems;
17374 }
17375 fit() {
17376 const { options , ctx } = this;
17377 if (!options.display) {
17378 this.width = this.height = 0;
17379 return;
17380 }
17381 const labelOpts = options.labels;
17382 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17383 const fontSize = labelFont.size;
17384 const titleHeight = this._computeTitleHeight();
17385 const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize);
17386 let width, height;
17387 ctx.font = labelFont.string;
17388 if (this.isHorizontal()) {
17389 width = this.maxWidth;
17390 height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
17391 } else {
17392 height = this.maxHeight;
17393 width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;
17394 }
17395 this.width = Math.min(width, options.maxWidth || this.maxWidth);
17396 this.height = Math.min(height, options.maxHeight || this.maxHeight);
17397 }
17398 _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
17399 const { ctx , maxWidth , options: { labels: { padding } } } = this;
17400 const hitboxes = this.legendHitBoxes = [];
17401 const lineWidths = this.lineWidths = [
17402 0
17403 ];
17404 const lineHeight = itemHeight + padding;
17405 let totalHeight = titleHeight;
17406 ctx.textAlign = 'left';
17407 ctx.textBaseline = 'middle';
17408 let row = -1;
17409 let top = -lineHeight;
17410 this.legendItems.forEach((legendItem, i)=>{
17411 const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;
17412 if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
17413 totalHeight += lineHeight;
17414 lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
17415 top += lineHeight;
17416 row++;
17417 }
17418 hitboxes[i] = {
17419 left: 0,
17420 top,
17421 row,
17422 width: itemWidth,
17423 height: itemHeight
17424 };
17425 lineWidths[lineWidths.length - 1] += itemWidth + padding;
17426 });
17427 return totalHeight;
17428 }
17429 _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {
17430 const { ctx , maxHeight , options: { labels: { padding } } } = this;
17431 const hitboxes = this.legendHitBoxes = [];
17432 const columnSizes = this.columnSizes = [];
17433 const heightLimit = maxHeight - titleHeight;
17434 let totalWidth = padding;
17435 let currentColWidth = 0;
17436 let currentColHeight = 0;
17437 let left = 0;
17438 let col = 0;
17439 this.legendItems.forEach((legendItem, i)=>{
17440 const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);
17441 if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
17442 totalWidth += currentColWidth + padding;
17443 columnSizes.push({
17444 width: currentColWidth,
17445 height: currentColHeight
17446 });
17447 left += currentColWidth + padding;
17448 col++;
17449 currentColWidth = currentColHeight = 0;
17450 }
17451 hitboxes[i] = {
17452 left,
17453 top: currentColHeight,
17454 col,
17455 width: itemWidth,
17456 height: itemHeight
17457 };
17458 currentColWidth = Math.max(currentColWidth, itemWidth);
17459 currentColHeight += itemHeight + padding;
17460 });
17461 totalWidth += currentColWidth;
17462 columnSizes.push({
17463 width: currentColWidth,
17464 height: currentColHeight
17465 });
17466 return totalWidth;
17467 }
17468 adjustHitBoxes() {
17469 if (!this.options.display) {
17470 return;
17471 }
17472 const titleHeight = this._computeTitleHeight();
17473 const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this;
17474 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(rtl, this.left, this.width);
17475 if (this.isHorizontal()) {
17476 let row = 0;
17477 let left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17478 for (const hitbox of hitboxes){
17479 if (row !== hitbox.row) {
17480 row = hitbox.row;
17481 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17482 }
17483 hitbox.top += this.top + titleHeight + padding;
17484 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
17485 left += hitbox.width + padding;
17486 }
17487 } else {
17488 let col = 0;
17489 let top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17490 for (const hitbox of hitboxes){
17491 if (hitbox.col !== col) {
17492 col = hitbox.col;
17493 top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17494 }
17495 hitbox.top = top;
17496 hitbox.left += this.left + padding;
17497 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
17498 top += hitbox.height + padding;
17499 }
17500 }
17501 }
17502 isHorizontal() {
17503 return this.options.position === 'top' || this.options.position === 'bottom';
17504 }
17505 draw() {
17506 if (this.options.display) {
17507 const ctx = this.ctx;
17508 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, this);
17509 this._draw();
17510 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17511 }
17512 }
17513 _draw() {
17514 const { options: opts , columnSizes , lineWidths , ctx } = this;
17515 const { align , labels: labelOpts } = opts;
17516 const defaultColor = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.color;
17517 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17518 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17519 const { padding } = labelOpts;
17520 const fontSize = labelFont.size;
17521 const halfFontSize = fontSize / 2;
17522 let cursor;
17523 this.drawTitle();
17524 ctx.textAlign = rtlHelper.textAlign('left');
17525 ctx.textBaseline = 'middle';
17526 ctx.lineWidth = 0.5;
17527 ctx.font = labelFont.string;
17528 const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize);
17529 const drawLegendBox = function(x, y, legendItem) {
17530 if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
17531 return;
17532 }
17533 ctx.save();
17534 const lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineWidth, 1);
17535 ctx.fillStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.fillStyle, defaultColor);
17536 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineCap, 'butt');
17537 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDashOffset, 0);
17538 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineJoin, 'miter');
17539 ctx.lineWidth = lineWidth;
17540 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.strokeStyle, defaultColor);
17541 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDash, []));
17542 if (labelOpts.usePointStyle) {
17543 const drawOptions = {
17544 radius: boxHeight * Math.SQRT2 / 2,
17545 pointStyle: legendItem.pointStyle,
17546 rotation: legendItem.rotation,
17547 borderWidth: lineWidth
17548 };
17549 const centerX = rtlHelper.xPlus(x, boxWidth / 2);
17550 const centerY = y + halfFontSize;
17551 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aE)(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);
17552 } else {
17553 const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
17554 const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);
17555 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(legendItem.borderRadius);
17556 ctx.beginPath();
17557 if (Object.values(borderRadius).some((v)=>v !== 0)) {
17558 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
17559 x: xBoxLeft,
17560 y: yBoxTop,
17561 w: boxWidth,
17562 h: boxHeight,
17563 radius: borderRadius
17564 });
17565 } else {
17566 ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
17567 }
17568 ctx.fill();
17569 if (lineWidth !== 0) {
17570 ctx.stroke();
17571 }
17572 }
17573 ctx.restore();
17574 };
17575 const fillText = function(x, y, legendItem) {
17576 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, {
17577 strikethrough: legendItem.hidden,
17578 textAlign: rtlHelper.textAlign(legendItem.textAlign)
17579 });
17580 };
17581 const isHorizontal = this.isHorizontal();
17582 const titleHeight = this._computeTitleHeight();
17583 if (isHorizontal) {
17584 cursor = {
17585 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[0]),
17586 y: this.top + padding + titleHeight,
17587 line: 0
17588 };
17589 } else {
17590 cursor = {
17591 x: this.left + padding,
17592 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
17593 line: 0
17594 };
17595 }
17596 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(this.ctx, opts.textDirection);
17597 const lineHeight = itemHeight + padding;
17598 this.legendItems.forEach((legendItem, i)=>{
17599 ctx.strokeStyle = legendItem.fontColor;
17600 ctx.fillStyle = legendItem.fontColor;
17601 const textWidth = ctx.measureText(legendItem.text).width;
17602 const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
17603 const width = boxWidth + halfFontSize + textWidth;
17604 let x = cursor.x;
17605 let y = cursor.y;
17606 rtlHelper.setWidth(this.width);
17607 if (isHorizontal) {
17608 if (i > 0 && x + width + padding > this.right) {
17609 y = cursor.y += lineHeight;
17610 cursor.line++;
17611 x = cursor.x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[cursor.line]);
17612 }
17613 } else if (i > 0 && y + lineHeight > this.bottom) {
17614 x = cursor.x = x + columnSizes[cursor.line].width + padding;
17615 cursor.line++;
17616 y = cursor.y = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
17617 }
17618 const realX = rtlHelper.x(x);
17619 drawLegendBox(realX, y, legendItem);
17620 x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aC)(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
17621 fillText(rtlHelper.x(x), y, legendItem);
17622 if (isHorizontal) {
17623 cursor.x += width + padding;
17624 } else if (typeof legendItem.text !== 'string') {
17625 const fontLineHeight = labelFont.lineHeight;
17626 cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;
17627 } else {
17628 cursor.y += lineHeight;
17629 }
17630 });
17631 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(this.ctx, opts.textDirection);
17632 }
17633 drawTitle() {
17634 const opts = this.options;
17635 const titleOpts = opts.title;
17636 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17637 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17638 if (!titleOpts.display) {
17639 return;
17640 }
17641 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17642 const ctx = this.ctx;
17643 const position = titleOpts.position;
17644 const halfFontSize = titleFont.size / 2;
17645 const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
17646 let y;
17647 let left = this.left;
17648 let maxWidth = this.width;
17649 if (this.isHorizontal()) {
17650 maxWidth = Math.max(...this.lineWidths);
17651 y = this.top + topPaddingPlusHalfFontSize;
17652 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, left, this.right - maxWidth);
17653 } else {
17654 const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0);
17655 y = topPaddingPlusHalfFontSize + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
17656 }
17657 const x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(position, left, left + maxWidth);
17658 ctx.textAlign = rtlHelper.textAlign((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(position));
17659 ctx.textBaseline = 'middle';
17660 ctx.strokeStyle = titleOpts.color;
17661 ctx.fillStyle = titleOpts.color;
17662 ctx.font = titleFont.string;
17663 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, titleOpts.text, x, y, titleFont);
17664 }
17665 _computeTitleHeight() {
17666 const titleOpts = this.options.title;
17667 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17668 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17669 return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
17670 }
17671 _getLegendItemAt(x, y) {
17672 let i, hitBox, lh;
17673 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, this.left, this.right) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, this.top, this.bottom)) {
17674 lh = this.legendHitBoxes;
17675 for(i = 0; i < lh.length; ++i){
17676 hitBox = lh[i];
17677 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, hitBox.left, hitBox.left + hitBox.width) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, hitBox.top, hitBox.top + hitBox.height)) {
17678 return this.legendItems[i];
17679 }
17680 }
17681 }
17682 return null;
17683 }
17684 handleEvent(e) {
17685 const opts = this.options;
17686 if (!isListened(e.type, opts)) {
17687 return;
17688 }
17689 const hoveredItem = this._getLegendItemAt(e.x, e.y);
17690 if (e.type === 'mousemove' || e.type === 'mouseout') {
17691 const previous = this._hoveredItem;
17692 const sameItem = itemsEqual(previous, hoveredItem);
17693 if (previous && !sameItem) {
17694 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onLeave, [
17695 e,
17696 previous,
17697 this
17698 ], this);
17699 }
17700 this._hoveredItem = hoveredItem;
17701 if (hoveredItem && !sameItem) {
17702 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onHover, [
17703 e,
17704 hoveredItem,
17705 this
17706 ], this);
17707 }
17708 } else if (hoveredItem) {
17709 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onClick, [
17710 e,
17711 hoveredItem,
17712 this
17713 ], this);
17714 }
17715 }
17716 }
17717 function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {
17718 const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);
17719 const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);
17720 return {
17721 itemWidth,
17722 itemHeight
17723 };
17724 }
17725 function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {
17726 let legendItemText = legendItem.text;
17727 if (legendItemText && typeof legendItemText !== 'string') {
17728 legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b);
17729 }
17730 return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;
17731 }
17732 function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {
17733 let itemHeight = _itemHeight;
17734 if (typeof legendItem.text !== 'string') {
17735 itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);
17736 }
17737 return itemHeight;
17738 }
17739 function calculateLegendItemHeight(legendItem, fontLineHeight) {
17740 const labelHeight = legendItem.text ? legendItem.text.length : 0;
17741 return fontLineHeight * labelHeight;
17742 }
17743 function isListened(type, opts) {
17744 if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) {
17745 return true;
17746 }
17747 if (opts.onClick && (type === 'click' || type === 'mouseup')) {
17748 return true;
17749 }
17750 return false;
17751 }
17752 var plugin_legend = {
17753 id: 'legend',
17754 _element: Legend,
17755 start (chart, _args, options) {
17756 const legend = chart.legend = new Legend({
17757 ctx: chart.ctx,
17758 options,
17759 chart
17760 });
17761 layouts.configure(chart, legend, options);
17762 layouts.addBox(chart, legend);
17763 },
17764 stop (chart) {
17765 layouts.removeBox(chart, chart.legend);
17766 delete chart.legend;
17767 },
17768 beforeUpdate (chart, _args, options) {
17769 const legend = chart.legend;
17770 layouts.configure(chart, legend, options);
17771 legend.options = options;
17772 },
17773 afterUpdate (chart) {
17774 const legend = chart.legend;
17775 legend.buildLabels();
17776 legend.adjustHitBoxes();
17777 },
17778 afterEvent (chart, args) {
17779 if (!args.replay) {
17780 chart.legend.handleEvent(args.event);
17781 }
17782 },
17783 defaults: {
17784 display: true,
17785 position: 'top',
17786 align: 'center',
17787 fullSize: true,
17788 reverse: false,
17789 weight: 1000,
17790 onClick (e, legendItem, legend) {
17791 const index = legendItem.datasetIndex;
17792 const ci = legend.chart;
17793 if (ci.isDatasetVisible(index)) {
17794 ci.hide(index);
17795 legendItem.hidden = true;
17796 } else {
17797 ci.show(index);
17798 legendItem.hidden = false;
17799 }
17800 },
17801 onHover: null,
17802 onLeave: null,
17803 labels: {
17804 color: (ctx)=>ctx.chart.options.color,
17805 boxWidth: 40,
17806 padding: 10,
17807 generateLabels (chart) {
17808 const datasets = chart.data.datasets;
17809 const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
17810 return chart._getSortedDatasetMetas().map((meta)=>{
17811 const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
17812 const borderWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(style.borderWidth);
17813 return {
17814 text: datasets[meta.index].label,
17815 fillStyle: style.backgroundColor,
17816 fontColor: color,
17817 hidden: !meta.visible,
17818 lineCap: style.borderCapStyle,
17819 lineDash: style.borderDash,
17820 lineDashOffset: style.borderDashOffset,
17821 lineJoin: style.borderJoinStyle,
17822 lineWidth: (borderWidth.width + borderWidth.height) / 4,
17823 strokeStyle: style.borderColor,
17824 pointStyle: pointStyle || style.pointStyle,
17825 rotation: style.rotation,
17826 textAlign: textAlign || style.textAlign,
17827 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
17828 datasetIndex: meta.index
17829 };
17830 }, this);
17831 }
17832 },
17833 title: {
17834 color: (ctx)=>ctx.chart.options.color,
17835 display: false,
17836 position: 'center',
17837 text: ''
17838 }
17839 },
17840 descriptors: {
17841 _scriptable: (name)=>!name.startsWith('on'),
17842 labels: {
17843 _scriptable: (name)=>![
17844 'generateLabels',
17845 'filter',
17846 'sort'
17847 ].includes(name)
17848 }
17849 }
17850 };
17851
17852 class Title extends Element {
17853 constructor(config){
17854 super();
17855 this.chart = config.chart;
17856 this.options = config.options;
17857 this.ctx = config.ctx;
17858 this._padding = undefined;
17859 this.top = undefined;
17860 this.bottom = undefined;
17861 this.left = undefined;
17862 this.right = undefined;
17863 this.width = undefined;
17864 this.height = undefined;
17865 this.position = undefined;
17866 this.weight = undefined;
17867 this.fullSize = undefined;
17868 }
17869 update(maxWidth, maxHeight) {
17870 const opts = this.options;
17871 this.left = 0;
17872 this.top = 0;
17873 if (!opts.display) {
17874 this.width = this.height = this.right = this.bottom = 0;
17875 return;
17876 }
17877 this.width = this.right = maxWidth;
17878 this.height = this.bottom = maxHeight;
17879 const lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(opts.text) ? opts.text.length : 1;
17880 this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.padding);
17881 const textSize = lineCount * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font).lineHeight + this._padding.height;
17882 if (this.isHorizontal()) {
17883 this.height = textSize;
17884 } else {
17885 this.width = textSize;
17886 }
17887 }
17888 isHorizontal() {
17889 const pos = this.options.position;
17890 return pos === 'top' || pos === 'bottom';
17891 }
17892 _drawArgs(offset) {
17893 const { top , left , bottom , right , options } = this;
17894 const align = options.align;
17895 let rotation = 0;
17896 let maxWidth, titleX, titleY;
17897 if (this.isHorizontal()) {
17898 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
17899 titleY = top + offset;
17900 maxWidth = right - left;
17901 } else {
17902 if (options.position === 'left') {
17903 titleX = left + offset;
17904 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
17905 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * -0.5;
17906 } else {
17907 titleX = right - offset;
17908 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, top, bottom);
17909 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * 0.5;
17910 }
17911 maxWidth = bottom - top;
17912 }
17913 return {
17914 titleX,
17915 titleY,
17916 maxWidth,
17917 rotation
17918 };
17919 }
17920 draw() {
17921 const ctx = this.ctx;
17922 const opts = this.options;
17923 if (!opts.display) {
17924 return;
17925 }
17926 const fontOpts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
17927 const lineHeight = fontOpts.lineHeight;
17928 const offset = lineHeight / 2 + this._padding.top;
17929 const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset);
17930 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, opts.text, 0, 0, fontOpts, {
17931 color: opts.color,
17932 maxWidth,
17933 rotation,
17934 textAlign: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(opts.align),
17935 textBaseline: 'middle',
17936 translation: [
17937 titleX,
17938 titleY
17939 ]
17940 });
17941 }
17942 }
17943 function createTitle(chart, titleOpts) {
17944 const title = new Title({
17945 ctx: chart.ctx,
17946 options: titleOpts,
17947 chart
17948 });
17949 layouts.configure(chart, title, titleOpts);
17950 layouts.addBox(chart, title);
17951 chart.titleBlock = title;
17952 }
17953 var plugin_title = {
17954 id: 'title',
17955 _element: Title,
17956 start (chart, _args, options) {
17957 createTitle(chart, options);
17958 },
17959 stop (chart) {
17960 const titleBlock = chart.titleBlock;
17961 layouts.removeBox(chart, titleBlock);
17962 delete chart.titleBlock;
17963 },
17964 beforeUpdate (chart, _args, options) {
17965 const title = chart.titleBlock;
17966 layouts.configure(chart, title, options);
17967 title.options = options;
17968 },
17969 defaults: {
17970 align: 'center',
17971 display: false,
17972 font: {
17973 weight: 'bold'
17974 },
17975 fullSize: true,
17976 padding: 10,
17977 position: 'top',
17978 text: '',
17979 weight: 2000
17980 },
17981 defaultRoutes: {
17982 color: 'color'
17983 },
17984 descriptors: {
17985 _scriptable: true,
17986 _indexable: false
17987 }
17988 };
17989
17990 const map = new WeakMap();
17991 var plugin_subtitle = {
17992 id: 'subtitle',
17993 start (chart, _args, options) {
17994 const title = new Title({
17995 ctx: chart.ctx,
17996 options,
17997 chart
17998 });
17999 layouts.configure(chart, title, options);
18000 layouts.addBox(chart, title);
18001 map.set(chart, title);
18002 },
18003 stop (chart) {
18004 layouts.removeBox(chart, map.get(chart));
18005 map.delete(chart);
18006 },
18007 beforeUpdate (chart, _args, options) {
18008 const title = map.get(chart);
18009 layouts.configure(chart, title, options);
18010 title.options = options;
18011 },
18012 defaults: {
18013 align: 'center',
18014 display: false,
18015 font: {
18016 weight: 'normal'
18017 },
18018 fullSize: true,
18019 padding: 0,
18020 position: 'top',
18021 text: '',
18022 weight: 1500
18023 },
18024 defaultRoutes: {
18025 color: 'color'
18026 },
18027 descriptors: {
18028 _scriptable: true,
18029 _indexable: false
18030 }
18031 };
18032
18033 const positioners = {
18034 average (items) {
18035 if (!items.length) {
18036 return false;
18037 }
18038 let i, len;
18039 let xSet = new Set();
18040 let y = 0;
18041 let count = 0;
18042 for(i = 0, len = items.length; i < len; ++i){
18043 const el = items[i].element;
18044 if (el && el.hasValue()) {
18045 const pos = el.tooltipPosition();
18046 xSet.add(pos.x);
18047 y += pos.y;
18048 ++count;
18049 }
18050 }
18051 if (count === 0 || xSet.size === 0) {
18052 return false;
18053 }
18054 const xAverage = [
18055 ...xSet
18056 ].reduce((a, b)=>a + b) / xSet.size;
18057 return {
18058 x: xAverage,
18059 y: y / count
18060 };
18061 },
18062 nearest (items, eventPosition) {
18063 if (!items.length) {
18064 return false;
18065 }
18066 let x = eventPosition.x;
18067 let y = eventPosition.y;
18068 let minDistance = Number.POSITIVE_INFINITY;
18069 let i, len, nearestElement;
18070 for(i = 0, len = items.length; i < len; ++i){
18071 const el = items[i].element;
18072 if (el && el.hasValue()) {
18073 const center = el.getCenterPoint();
18074 const d = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aF)(eventPosition, center);
18075 if (d < minDistance) {
18076 minDistance = d;
18077 nearestElement = el;
18078 }
18079 }
18080 }
18081 if (nearestElement) {
18082 const tp = nearestElement.tooltipPosition();
18083 x = tp.x;
18084 y = tp.y;
18085 }
18086 return {
18087 x,
18088 y
18089 };
18090 }
18091 };
18092 function pushOrConcat(base, toPush) {
18093 if (toPush) {
18094 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(toPush)) {
18095 Array.prototype.push.apply(base, toPush);
18096 } else {
18097 base.push(toPush);
18098 }
18099 }
18100 return base;
18101 }
18102 function splitNewlines(str) {
18103 if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
18104 return str.split('\n');
18105 }
18106 return str;
18107 }
18108 function createTooltipItem(chart, item) {
18109 const { element , datasetIndex , index } = item;
18110 const controller = chart.getDatasetMeta(datasetIndex).controller;
18111 const { label , value } = controller.getLabelAndValue(index);
18112 return {
18113 chart,
18114 label,
18115 parsed: controller.getParsed(index),
18116 raw: chart.data.datasets[datasetIndex].data[index],
18117 formattedValue: value,
18118 dataset: controller.getDataset(),
18119 dataIndex: index,
18120 datasetIndex,
18121 element
18122 };
18123 }
18124 function getTooltipSize(tooltip, options) {
18125 const ctx = tooltip.chart.ctx;
18126 const { body , footer , title } = tooltip;
18127 const { boxWidth , boxHeight } = options;
18128 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18129 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18130 const footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18131 const titleLineCount = title.length;
18132 const footerLineCount = footer.length;
18133 const bodyLineItemCount = body.length;
18134 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18135 let height = padding.height;
18136 let width = 0;
18137 let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
18138 combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
18139 if (titleLineCount) {
18140 height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;
18141 }
18142 if (combinedBodyLength) {
18143 const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
18144 height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;
18145 }
18146 if (footerLineCount) {
18147 height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;
18148 }
18149 let widthPadding = 0;
18150 const maxLineWidth = function(line) {
18151 width = Math.max(width, ctx.measureText(line).width + widthPadding);
18152 };
18153 ctx.save();
18154 ctx.font = titleFont.string;
18155 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.title, maxLineWidth);
18156 ctx.font = bodyFont.string;
18157 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
18158 widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;
18159 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(body, (bodyItem)=>{
18160 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, maxLineWidth);
18161 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.lines, maxLineWidth);
18162 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, maxLineWidth);
18163 });
18164 widthPadding = 0;
18165 ctx.font = footerFont.string;
18166 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.footer, maxLineWidth);
18167 ctx.restore();
18168 width += padding.width;
18169 return {
18170 width,
18171 height
18172 };
18173 }
18174 function determineYAlign(chart, size) {
18175 const { y , height } = size;
18176 if (y < height / 2) {
18177 return 'top';
18178 } else if (y > chart.height - height / 2) {
18179 return 'bottom';
18180 }
18181 return 'center';
18182 }
18183 function doesNotFitWithAlign(xAlign, chart, options, size) {
18184 const { x , width } = size;
18185 const caret = options.caretSize + options.caretPadding;
18186 if (xAlign === 'left' && x + width + caret > chart.width) {
18187 return true;
18188 }
18189 if (xAlign === 'right' && x - width - caret < 0) {
18190 return true;
18191 }
18192 }
18193 function determineXAlign(chart, options, size, yAlign) {
18194 const { x , width } = size;
18195 const { width: chartWidth , chartArea: { left , right } } = chart;
18196 let xAlign = 'center';
18197 if (yAlign === 'center') {
18198 xAlign = x <= (left + right) / 2 ? 'left' : 'right';
18199 } else if (x <= width / 2) {
18200 xAlign = 'left';
18201 } else if (x >= chartWidth - width / 2) {
18202 xAlign = 'right';
18203 }
18204 if (doesNotFitWithAlign(xAlign, chart, options, size)) {
18205 xAlign = 'center';
18206 }
18207 return xAlign;
18208 }
18209 function determineAlignment(chart, options, size) {
18210 const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
18211 return {
18212 xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
18213 yAlign
18214 };
18215 }
18216 function alignX(size, xAlign) {
18217 let { x , width } = size;
18218 if (xAlign === 'right') {
18219 x -= width;
18220 } else if (xAlign === 'center') {
18221 x -= width / 2;
18222 }
18223 return x;
18224 }
18225 function alignY(size, yAlign, paddingAndSize) {
18226 let { y , height } = size;
18227 if (yAlign === 'top') {
18228 y += paddingAndSize;
18229 } else if (yAlign === 'bottom') {
18230 y -= height + paddingAndSize;
18231 } else {
18232 y -= height / 2;
18233 }
18234 return y;
18235 }
18236 function getBackgroundPoint(options, size, alignment, chart) {
18237 const { caretSize , caretPadding , cornerRadius } = options;
18238 const { xAlign , yAlign } = alignment;
18239 const paddingAndSize = caretSize + caretPadding;
18240 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18241 let x = alignX(size, xAlign);
18242 const y = alignY(size, yAlign, paddingAndSize);
18243 if (yAlign === 'center') {
18244 if (xAlign === 'left') {
18245 x += paddingAndSize;
18246 } else if (xAlign === 'right') {
18247 x -= paddingAndSize;
18248 }
18249 } else if (xAlign === 'left') {
18250 x -= Math.max(topLeft, bottomLeft) + caretSize;
18251 } else if (xAlign === 'right') {
18252 x += Math.max(topRight, bottomRight) + caretSize;
18253 }
18254 return {
18255 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(x, 0, chart.width - size.width),
18256 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(y, 0, chart.height - size.height)
18257 };
18258 }
18259 function getAlignedX(tooltip, align, options) {
18260 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18261 return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;
18262 }
18263 function getBeforeAfterBodyLines(callback) {
18264 return pushOrConcat([], splitNewlines(callback));
18265 }
18266 function createTooltipContext(parent, tooltip, tooltipItems) {
18267 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
18268 tooltip,
18269 tooltipItems,
18270 type: 'tooltip'
18271 });
18272 }
18273 function overrideCallbacks(callbacks, context) {
18274 const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
18275 return override ? callbacks.override(override) : callbacks;
18276 }
18277 const defaultCallbacks = {
18278 beforeTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18279 title (tooltipItems) {
18280 if (tooltipItems.length > 0) {
18281 const item = tooltipItems[0];
18282 const labels = item.chart.data.labels;
18283 const labelCount = labels ? labels.length : 0;
18284 if (this && this.options && this.options.mode === 'dataset') {
18285 return item.dataset.label || '';
18286 } else if (item.label) {
18287 return item.label;
18288 } else if (labelCount > 0 && item.dataIndex < labelCount) {
18289 return labels[item.dataIndex];
18290 }
18291 }
18292 return '';
18293 },
18294 afterTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18295 beforeBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18296 beforeLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18297 label (tooltipItem) {
18298 if (this && this.options && this.options.mode === 'dataset') {
18299 return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
18300 }
18301 let label = tooltipItem.dataset.label || '';
18302 if (label) {
18303 label += ': ';
18304 }
18305 const value = tooltipItem.formattedValue;
18306 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
18307 label += value;
18308 }
18309 return label;
18310 },
18311 labelColor (tooltipItem) {
18312 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18313 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18314 return {
18315 borderColor: options.borderColor,
18316 backgroundColor: options.backgroundColor,
18317 borderWidth: options.borderWidth,
18318 borderDash: options.borderDash,
18319 borderDashOffset: options.borderDashOffset,
18320 borderRadius: 0
18321 };
18322 },
18323 labelTextColor () {
18324 return this.options.bodyColor;
18325 },
18326 labelPointStyle (tooltipItem) {
18327 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18328 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18329 return {
18330 pointStyle: options.pointStyle,
18331 rotation: options.rotation
18332 };
18333 },
18334 afterLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18335 afterBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18336 beforeFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18337 footer: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18338 afterFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG
18339 };
18340 function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
18341 const result = callbacks[name].call(ctx, arg);
18342 if (typeof result === 'undefined') {
18343 return defaultCallbacks[name].call(ctx, arg);
18344 }
18345 return result;
18346 }
18347 class Tooltip extends Element {
18348 static positioners = positioners;
18349 constructor(config){
18350 super();
18351 this.opacity = 0;
18352 this._active = [];
18353 this._eventPosition = undefined;
18354 this._size = undefined;
18355 this._cachedAnimations = undefined;
18356 this._tooltipItems = [];
18357 this.$animations = undefined;
18358 this.$context = undefined;
18359 this.chart = config.chart;
18360 this.options = config.options;
18361 this.dataPoints = undefined;
18362 this.title = undefined;
18363 this.beforeBody = undefined;
18364 this.body = undefined;
18365 this.afterBody = undefined;
18366 this.footer = undefined;
18367 this.xAlign = undefined;
18368 this.yAlign = undefined;
18369 this.x = undefined;
18370 this.y = undefined;
18371 this.height = undefined;
18372 this.width = undefined;
18373 this.caretX = undefined;
18374 this.caretY = undefined;
18375 this.labelColors = undefined;
18376 this.labelPointStyles = undefined;
18377 this.labelTextColors = undefined;
18378 }
18379 initialize(options) {
18380 this.options = options;
18381 this._cachedAnimations = undefined;
18382 this.$context = undefined;
18383 }
18384 _resolveAnimations() {
18385 const cached = this._cachedAnimations;
18386 if (cached) {
18387 return cached;
18388 }
18389 const chart = this.chart;
18390 const options = this.options.setContext(this.getContext());
18391 const opts = options.enabled && chart.options.animation && options.animations;
18392 const animations = new Animations(this.chart, opts);
18393 if (opts._cacheable) {
18394 this._cachedAnimations = Object.freeze(animations);
18395 }
18396 return animations;
18397 }
18398 getContext() {
18399 return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
18400 }
18401 getTitle(context, options) {
18402 const { callbacks } = options;
18403 const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);
18404 const title = invokeCallbackWithFallback(callbacks, 'title', this, context);
18405 const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);
18406 let lines = [];
18407 lines = pushOrConcat(lines, splitNewlines(beforeTitle));
18408 lines = pushOrConcat(lines, splitNewlines(title));
18409 lines = pushOrConcat(lines, splitNewlines(afterTitle));
18410 return lines;
18411 }
18412 getBeforeBody(tooltipItems, options) {
18413 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems));
18414 }
18415 getBody(tooltipItems, options) {
18416 const { callbacks } = options;
18417 const bodyItems = [];
18418 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18419 const bodyItem = {
18420 before: [],
18421 lines: [],
18422 after: []
18423 };
18424 const scoped = overrideCallbacks(callbacks, context);
18425 pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));
18426 pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));
18427 pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));
18428 bodyItems.push(bodyItem);
18429 });
18430 return bodyItems;
18431 }
18432 getAfterBody(tooltipItems, options) {
18433 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems));
18434 }
18435 getFooter(tooltipItems, options) {
18436 const { callbacks } = options;
18437 const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);
18438 const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);
18439 const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);
18440 let lines = [];
18441 lines = pushOrConcat(lines, splitNewlines(beforeFooter));
18442 lines = pushOrConcat(lines, splitNewlines(footer));
18443 lines = pushOrConcat(lines, splitNewlines(afterFooter));
18444 return lines;
18445 }
18446 _createItems(options) {
18447 const active = this._active;
18448 const data = this.chart.data;
18449 const labelColors = [];
18450 const labelPointStyles = [];
18451 const labelTextColors = [];
18452 let tooltipItems = [];
18453 let i, len;
18454 for(i = 0, len = active.length; i < len; ++i){
18455 tooltipItems.push(createTooltipItem(this.chart, active[i]));
18456 }
18457 if (options.filter) {
18458 tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data));
18459 }
18460 if (options.itemSort) {
18461 tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data));
18462 }
18463 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18464 const scoped = overrideCallbacks(options.callbacks, context);
18465 labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));
18466 labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));
18467 labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));
18468 });
18469 this.labelColors = labelColors;
18470 this.labelPointStyles = labelPointStyles;
18471 this.labelTextColors = labelTextColors;
18472 this.dataPoints = tooltipItems;
18473 return tooltipItems;
18474 }
18475 update(changed, replay) {
18476 const options = this.options.setContext(this.getContext());
18477 const active = this._active;
18478 let properties;
18479 let tooltipItems = [];
18480 if (!active.length) {
18481 if (this.opacity !== 0) {
18482 properties = {
18483 opacity: 0
18484 };
18485 }
18486 } else {
18487 const position = positioners[options.position].call(this, active, this._eventPosition);
18488 tooltipItems = this._createItems(options);
18489 this.title = this.getTitle(tooltipItems, options);
18490 this.beforeBody = this.getBeforeBody(tooltipItems, options);
18491 this.body = this.getBody(tooltipItems, options);
18492 this.afterBody = this.getAfterBody(tooltipItems, options);
18493 this.footer = this.getFooter(tooltipItems, options);
18494 const size = this._size = getTooltipSize(this, options);
18495 const positionAndSize = Object.assign({}, position, size);
18496 const alignment = determineAlignment(this.chart, options, positionAndSize);
18497 const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
18498 this.xAlign = alignment.xAlign;
18499 this.yAlign = alignment.yAlign;
18500 properties = {
18501 opacity: 1,
18502 x: backgroundPoint.x,
18503 y: backgroundPoint.y,
18504 width: size.width,
18505 height: size.height,
18506 caretX: position.x,
18507 caretY: position.y
18508 };
18509 }
18510 this._tooltipItems = tooltipItems;
18511 this.$context = undefined;
18512 if (properties) {
18513 this._resolveAnimations().update(this, properties);
18514 }
18515 if (changed && options.external) {
18516 options.external.call(this, {
18517 chart: this.chart,
18518 tooltip: this,
18519 replay
18520 });
18521 }
18522 }
18523 drawCaret(tooltipPoint, ctx, size, options) {
18524 const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
18525 ctx.lineTo(caretPosition.x1, caretPosition.y1);
18526 ctx.lineTo(caretPosition.x2, caretPosition.y2);
18527 ctx.lineTo(caretPosition.x3, caretPosition.y3);
18528 }
18529 getCaretPosition(tooltipPoint, size, options) {
18530 const { xAlign , yAlign } = this;
18531 const { caretSize , cornerRadius } = options;
18532 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18533 const { x: ptX , y: ptY } = tooltipPoint;
18534 const { width , height } = size;
18535 let x1, x2, x3, y1, y2, y3;
18536 if (yAlign === 'center') {
18537 y2 = ptY + height / 2;
18538 if (xAlign === 'left') {
18539 x1 = ptX;
18540 x2 = x1 - caretSize;
18541 y1 = y2 + caretSize;
18542 y3 = y2 - caretSize;
18543 } else {
18544 x1 = ptX + width;
18545 x2 = x1 + caretSize;
18546 y1 = y2 - caretSize;
18547 y3 = y2 + caretSize;
18548 }
18549 x3 = x1;
18550 } else {
18551 if (xAlign === 'left') {
18552 x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;
18553 } else if (xAlign === 'right') {
18554 x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
18555 } else {
18556 x2 = this.caretX;
18557 }
18558 if (yAlign === 'top') {
18559 y1 = ptY;
18560 y2 = y1 - caretSize;
18561 x1 = x2 - caretSize;
18562 x3 = x2 + caretSize;
18563 } else {
18564 y1 = ptY + height;
18565 y2 = y1 + caretSize;
18566 x1 = x2 + caretSize;
18567 x3 = x2 - caretSize;
18568 }
18569 y3 = y1;
18570 }
18571 return {
18572 x1,
18573 x2,
18574 x3,
18575 y1,
18576 y2,
18577 y3
18578 };
18579 }
18580 drawTitle(pt, ctx, options) {
18581 const title = this.title;
18582 const length = title.length;
18583 let titleFont, titleSpacing, i;
18584 if (length) {
18585 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18586 pt.x = getAlignedX(this, options.titleAlign, options);
18587 ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
18588 ctx.textBaseline = 'middle';
18589 titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18590 titleSpacing = options.titleSpacing;
18591 ctx.fillStyle = options.titleColor;
18592 ctx.font = titleFont.string;
18593 for(i = 0; i < length; ++i){
18594 ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
18595 pt.y += titleFont.lineHeight + titleSpacing;
18596 if (i + 1 === length) {
18597 pt.y += options.titleMarginBottom - titleSpacing;
18598 }
18599 }
18600 }
18601 }
18602 _drawColorBox(ctx, pt, i, rtlHelper, options) {
18603 const labelColor = this.labelColors[i];
18604 const labelPointStyle = this.labelPointStyles[i];
18605 const { boxHeight , boxWidth } = options;
18606 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18607 const colorX = getAlignedX(this, 'left', options);
18608 const rtlColorX = rtlHelper.x(colorX);
18609 const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
18610 const colorY = pt.y + yOffSet;
18611 if (options.usePointStyle) {
18612 const drawOptions = {
18613 radius: Math.min(boxWidth, boxHeight) / 2,
18614 pointStyle: labelPointStyle.pointStyle,
18615 rotation: labelPointStyle.rotation,
18616 borderWidth: 1
18617 };
18618 const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
18619 const centerY = colorY + boxHeight / 2;
18620 ctx.strokeStyle = options.multiKeyBackground;
18621 ctx.fillStyle = options.multiKeyBackground;
18622 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18623 ctx.strokeStyle = labelColor.borderColor;
18624 ctx.fillStyle = labelColor.backgroundColor;
18625 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18626 } else {
18627 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;
18628 ctx.strokeStyle = labelColor.borderColor;
18629 ctx.setLineDash(labelColor.borderDash || []);
18630 ctx.lineDashOffset = labelColor.borderDashOffset || 0;
18631 const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);
18632 const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);
18633 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(labelColor.borderRadius);
18634 if (Object.values(borderRadius).some((v)=>v !== 0)) {
18635 ctx.beginPath();
18636 ctx.fillStyle = options.multiKeyBackground;
18637 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18638 x: outerX,
18639 y: colorY,
18640 w: boxWidth,
18641 h: boxHeight,
18642 radius: borderRadius
18643 });
18644 ctx.fill();
18645 ctx.stroke();
18646 ctx.fillStyle = labelColor.backgroundColor;
18647 ctx.beginPath();
18648 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18649 x: innerX,
18650 y: colorY + 1,
18651 w: boxWidth - 2,
18652 h: boxHeight - 2,
18653 radius: borderRadius
18654 });
18655 ctx.fill();
18656 } else {
18657 ctx.fillStyle = options.multiKeyBackground;
18658 ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
18659 ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
18660 ctx.fillStyle = labelColor.backgroundColor;
18661 ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
18662 }
18663 }
18664 ctx.fillStyle = this.labelTextColors[i];
18665 }
18666 drawBody(pt, ctx, options) {
18667 const { body } = this;
18668 const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options;
18669 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18670 let bodyLineHeight = bodyFont.lineHeight;
18671 let xLinePadding = 0;
18672 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18673 const fillLineOfText = function(line) {
18674 ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
18675 pt.y += bodyLineHeight + bodySpacing;
18676 };
18677 const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
18678 let bodyItem, textColor, lines, i, j, ilen, jlen;
18679 ctx.textAlign = bodyAlign;
18680 ctx.textBaseline = 'middle';
18681 ctx.font = bodyFont.string;
18682 pt.x = getAlignedX(this, bodyAlignForCalculation, options);
18683 ctx.fillStyle = options.bodyColor;
18684 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.beforeBody, fillLineOfText);
18685 xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;
18686 for(i = 0, ilen = body.length; i < ilen; ++i){
18687 bodyItem = body[i];
18688 textColor = this.labelTextColors[i];
18689 ctx.fillStyle = textColor;
18690 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, fillLineOfText);
18691 lines = bodyItem.lines;
18692 if (displayColors && lines.length) {
18693 this._drawColorBox(ctx, pt, i, rtlHelper, options);
18694 bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
18695 }
18696 for(j = 0, jlen = lines.length; j < jlen; ++j){
18697 fillLineOfText(lines[j]);
18698 bodyLineHeight = bodyFont.lineHeight;
18699 }
18700 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, fillLineOfText);
18701 }
18702 xLinePadding = 0;
18703 bodyLineHeight = bodyFont.lineHeight;
18704 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.afterBody, fillLineOfText);
18705 pt.y -= bodySpacing;
18706 }
18707 drawFooter(pt, ctx, options) {
18708 const footer = this.footer;
18709 const length = footer.length;
18710 let footerFont, i;
18711 if (length) {
18712 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18713 pt.x = getAlignedX(this, options.footerAlign, options);
18714 pt.y += options.footerMarginTop;
18715 ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
18716 ctx.textBaseline = 'middle';
18717 footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18718 ctx.fillStyle = options.footerColor;
18719 ctx.font = footerFont.string;
18720 for(i = 0; i < length; ++i){
18721 ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
18722 pt.y += footerFont.lineHeight + options.footerSpacing;
18723 }
18724 }
18725 }
18726 drawBackground(pt, ctx, tooltipSize, options) {
18727 const { xAlign , yAlign } = this;
18728 const { x , y } = pt;
18729 const { width , height } = tooltipSize;
18730 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(options.cornerRadius);
18731 ctx.fillStyle = options.backgroundColor;
18732 ctx.strokeStyle = options.borderColor;
18733 ctx.lineWidth = options.borderWidth;
18734 ctx.beginPath();
18735 ctx.moveTo(x + topLeft, y);
18736 if (yAlign === 'top') {
18737 this.drawCaret(pt, ctx, tooltipSize, options);
18738 }
18739 ctx.lineTo(x + width - topRight, y);
18740 ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
18741 if (yAlign === 'center' && xAlign === 'right') {
18742 this.drawCaret(pt, ctx, tooltipSize, options);
18743 }
18744 ctx.lineTo(x + width, y + height - bottomRight);
18745 ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
18746 if (yAlign === 'bottom') {
18747 this.drawCaret(pt, ctx, tooltipSize, options);
18748 }
18749 ctx.lineTo(x + bottomLeft, y + height);
18750 ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
18751 if (yAlign === 'center' && xAlign === 'left') {
18752 this.drawCaret(pt, ctx, tooltipSize, options);
18753 }
18754 ctx.lineTo(x, y + topLeft);
18755 ctx.quadraticCurveTo(x, y, x + topLeft, y);
18756 ctx.closePath();
18757 ctx.fill();
18758 if (options.borderWidth > 0) {
18759 ctx.stroke();
18760 }
18761 }
18762 _updateAnimationTarget(options) {
18763 const chart = this.chart;
18764 const anims = this.$animations;
18765 const animX = anims && anims.x;
18766 const animY = anims && anims.y;
18767 if (animX || animY) {
18768 const position = positioners[options.position].call(this, this._active, this._eventPosition);
18769 if (!position) {
18770 return;
18771 }
18772 const size = this._size = getTooltipSize(this, options);
18773 const positionAndSize = Object.assign({}, position, this._size);
18774 const alignment = determineAlignment(chart, options, positionAndSize);
18775 const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
18776 if (animX._to !== point.x || animY._to !== point.y) {
18777 this.xAlign = alignment.xAlign;
18778 this.yAlign = alignment.yAlign;
18779 this.width = size.width;
18780 this.height = size.height;
18781 this.caretX = position.x;
18782 this.caretY = position.y;
18783 this._resolveAnimations().update(this, point);
18784 }
18785 }
18786 }
18787 _willRender() {
18788 return !!this.opacity;
18789 }
18790 draw(ctx) {
18791 const options = this.options.setContext(this.getContext());
18792 let opacity = this.opacity;
18793 if (!opacity) {
18794 return;
18795 }
18796 this._updateAnimationTarget(options);
18797 const tooltipSize = {
18798 width: this.width,
18799 height: this.height
18800 };
18801 const pt = {
18802 x: this.x,
18803 y: this.y
18804 };
18805 opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
18806 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18807 const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
18808 if (options.enabled && hasTooltipContent) {
18809 ctx.save();
18810 ctx.globalAlpha = opacity;
18811 this.drawBackground(pt, ctx, tooltipSize, options);
18812 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(ctx, options.textDirection);
18813 pt.y += padding.top;
18814 this.drawTitle(pt, ctx, options);
18815 this.drawBody(pt, ctx, options);
18816 this.drawFooter(pt, ctx, options);
18817 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(ctx, options.textDirection);
18818 ctx.restore();
18819 }
18820 }
18821 getActiveElements() {
18822 return this._active || [];
18823 }
18824 setActiveElements(activeElements, eventPosition) {
18825 const lastActive = this._active;
18826 const active = activeElements.map(({ datasetIndex , index })=>{
18827 const meta = this.chart.getDatasetMeta(datasetIndex);
18828 if (!meta) {
18829 throw new Error('Cannot find a dataset at index ' + datasetIndex);
18830 }
18831 return {
18832 datasetIndex,
18833 element: meta.data[index],
18834 index
18835 };
18836 });
18837 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(lastActive, active);
18838 const positionChanged = this._positionChanged(active, eventPosition);
18839 if (changed || positionChanged) {
18840 this._active = active;
18841 this._eventPosition = eventPosition;
18842 this._ignoreReplayEvents = true;
18843 this.update(true);
18844 }
18845 }
18846 handleEvent(e, replay, inChartArea = true) {
18847 if (replay && this._ignoreReplayEvents) {
18848 return false;
18849 }
18850 this._ignoreReplayEvents = false;
18851 const options = this.options;
18852 const lastActive = this._active || [];
18853 const active = this._getActiveElements(e, lastActive, replay, inChartArea);
18854 const positionChanged = this._positionChanged(active, e);
18855 const changed = replay || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive) || positionChanged;
18856 if (changed) {
18857 this._active = active;
18858 if (options.enabled || options.external) {
18859 this._eventPosition = {
18860 x: e.x,
18861 y: e.y
18862 };
18863 this.update(true, replay);
18864 }
18865 }
18866 return changed;
18867 }
18868 _getActiveElements(e, lastActive, replay, inChartArea) {
18869 const options = this.options;
18870 if (e.type === 'mouseout') {
18871 return [];
18872 }
18873 if (!inChartArea) {
18874 return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined);
18875 }
18876 const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
18877 if (options.reverse) {
18878 active.reverse();
18879 }
18880 return active;
18881 }
18882 _positionChanged(active, e) {
18883 const { caretX , caretY , options } = this;
18884 const position = positioners[options.position].call(this, active, e);
18885 return position !== false && (caretX !== position.x || caretY !== position.y);
18886 }
18887 }
18888 var plugin_tooltip = {
18889 id: 'tooltip',
18890 _element: Tooltip,
18891 positioners,
18892 afterInit (chart, _args, options) {
18893 if (options) {
18894 chart.tooltip = new Tooltip({
18895 chart,
18896 options
18897 });
18898 }
18899 },
18900 beforeUpdate (chart, _args, options) {
18901 if (chart.tooltip) {
18902 chart.tooltip.initialize(options);
18903 }
18904 },
18905 reset (chart, _args, options) {
18906 if (chart.tooltip) {
18907 chart.tooltip.initialize(options);
18908 }
18909 },
18910 afterDraw (chart) {
18911 const tooltip = chart.tooltip;
18912 if (tooltip && tooltip._willRender()) {
18913 const args = {
18914 tooltip
18915 };
18916 if (chart.notifyPlugins('beforeTooltipDraw', {
18917 ...args,
18918 cancelable: true
18919 }) === false) {
18920 return;
18921 }
18922 tooltip.draw(chart.ctx);
18923 chart.notifyPlugins('afterTooltipDraw', args);
18924 }
18925 },
18926 afterEvent (chart, args) {
18927 if (chart.tooltip) {
18928 const useFinalPosition = args.replay;
18929 if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
18930 args.changed = true;
18931 }
18932 }
18933 },
18934 defaults: {
18935 enabled: true,
18936 external: null,
18937 position: 'average',
18938 backgroundColor: 'rgba(0,0,0,0.8)',
18939 titleColor: '#fff',
18940 titleFont: {
18941 weight: 'bold'
18942 },
18943 titleSpacing: 2,
18944 titleMarginBottom: 6,
18945 titleAlign: 'left',
18946 bodyColor: '#fff',
18947 bodySpacing: 2,
18948 bodyFont: {},
18949 bodyAlign: 'left',
18950 footerColor: '#fff',
18951 footerSpacing: 2,
18952 footerMarginTop: 6,
18953 footerFont: {
18954 weight: 'bold'
18955 },
18956 footerAlign: 'left',
18957 padding: 6,
18958 caretPadding: 2,
18959 caretSize: 5,
18960 cornerRadius: 6,
18961 boxHeight: (ctx, opts)=>opts.bodyFont.size,
18962 boxWidth: (ctx, opts)=>opts.bodyFont.size,
18963 multiKeyBackground: '#fff',
18964 displayColors: true,
18965 boxPadding: 0,
18966 borderColor: 'rgba(0,0,0,0)',
18967 borderWidth: 0,
18968 animation: {
18969 duration: 400,
18970 easing: 'easeOutQuart'
18971 },
18972 animations: {
18973 numbers: {
18974 type: 'number',
18975 properties: [
18976 'x',
18977 'y',
18978 'width',
18979 'height',
18980 'caretX',
18981 'caretY'
18982 ]
18983 },
18984 opacity: {
18985 easing: 'linear',
18986 duration: 200
18987 }
18988 },
18989 callbacks: defaultCallbacks
18990 },
18991 defaultRoutes: {
18992 bodyFont: 'font',
18993 footerFont: 'font',
18994 titleFont: 'font'
18995 },
18996 descriptors: {
18997 _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external',
18998 _indexable: false,
18999 callbacks: {
19000 _scriptable: false,
19001 _indexable: false
19002 },
19003 animation: {
19004 _fallback: false
19005 },
19006 animations: {
19007 _fallback: 'animation'
19008 }
19009 },
19010 additionalOptionScopes: [
19011 'interaction'
19012 ]
19013 };
19014
19015 var plugins = /*#__PURE__*/Object.freeze({
19016 __proto__: null,
19017 Colors: plugin_colors,
19018 Decimation: plugin_decimation,
19019 Filler: index,
19020 Legend: plugin_legend,
19021 SubTitle: plugin_subtitle,
19022 Title: plugin_title,
19023 Tooltip: plugin_tooltip
19024 });
19025
19026 const addIfString = (labels, raw, index, addedLabels)=>{
19027 if (typeof raw === 'string') {
19028 index = labels.push(raw) - 1;
19029 addedLabels.unshift({
19030 index,
19031 label: raw
19032 });
19033 } else if (isNaN(raw)) {
19034 index = null;
19035 }
19036 return index;
19037 };
19038 function findOrAddLabel(labels, raw, index, addedLabels) {
19039 const first = labels.indexOf(raw);
19040 if (first === -1) {
19041 return addIfString(labels, raw, index, addedLabels);
19042 }
19043 const last = labels.lastIndexOf(raw);
19044 return first !== last ? index : first;
19045 }
19046 const validIndex = (index, max)=>index === null ? null : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(Math.round(index), 0, max);
19047 function _getLabelForValue(value) {
19048 const labels = this.getLabels();
19049 if (value >= 0 && value < labels.length) {
19050 return labels[value];
19051 }
19052 return value;
19053 }
19054 class CategoryScale extends Scale {
19055 static id = 'category';
19056 static defaults = {
19057 ticks: {
19058 callback: _getLabelForValue
19059 }
19060 };
19061 constructor(cfg){
19062 super(cfg);
19063 this._startValue = undefined;
19064 this._valueRange = 0;
19065 this._addedLabels = [];
19066 }
19067 init(scaleOptions) {
19068 const added = this._addedLabels;
19069 if (added.length) {
19070 const labels = this.getLabels();
19071 for (const { index , label } of added){
19072 if (labels[index] === label) {
19073 labels.splice(index, 1);
19074 }
19075 }
19076 this._addedLabels = [];
19077 }
19078 super.init(scaleOptions);
19079 }
19080 parse(raw, index) {
19081 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19082 return null;
19083 }
19084 const labels = this.getLabels();
19085 index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(index, raw), this._addedLabels);
19086 return validIndex(index, labels.length - 1);
19087 }
19088 determineDataLimits() {
19089 const { minDefined , maxDefined } = this.getUserBounds();
19090 let { min , max } = this.getMinMax(true);
19091 if (this.options.bounds === 'ticks') {
19092 if (!minDefined) {
19093 min = 0;
19094 }
19095 if (!maxDefined) {
19096 max = this.getLabels().length - 1;
19097 }
19098 }
19099 this.min = min;
19100 this.max = max;
19101 }
19102 buildTicks() {
19103 const min = this.min;
19104 const max = this.max;
19105 const offset = this.options.offset;
19106 const ticks = [];
19107 let labels = this.getLabels();
19108 labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);
19109 this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
19110 this._startValue = this.min - (offset ? 0.5 : 0);
19111 for(let value = min; value <= max; value++){
19112 ticks.push({
19113 value
19114 });
19115 }
19116 return ticks;
19117 }
19118 getLabelForValue(value) {
19119 return _getLabelForValue.call(this, value);
19120 }
19121 configure() {
19122 super.configure();
19123 if (!this.isHorizontal()) {
19124 this._reversePixels = !this._reversePixels;
19125 }
19126 }
19127 getPixelForValue(value) {
19128 if (typeof value !== 'number') {
19129 value = this.parse(value);
19130 }
19131 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19132 }
19133 getPixelForTick(index) {
19134 const ticks = this.ticks;
19135 if (index < 0 || index > ticks.length - 1) {
19136 return null;
19137 }
19138 return this.getPixelForValue(ticks[index].value);
19139 }
19140 getValueForPixel(pixel) {
19141 return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
19142 }
19143 getBasePixel() {
19144 return this.bottom;
19145 }
19146 }
19147
19148 function generateTicks$1(generationOptions, dataRange) {
19149 const ticks = [];
19150 const MIN_SPACING = 1e-14;
19151 const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions;
19152 const unit = step || 1;
19153 const maxSpaces = maxTicks - 1;
19154 const { min: rmin , max: rmax } = dataRange;
19155 const minDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(min);
19156 const maxDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(max);
19157 const countDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(count);
19158 const minSpacing = (rmax - rmin) / (maxDigits + 1);
19159 let spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)((rmax - rmin) / maxSpaces / unit) * unit;
19160 let factor, niceMin, niceMax, numSpaces;
19161 if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
19162 return [
19163 {
19164 value: rmin
19165 },
19166 {
19167 value: rmax
19168 }
19169 ];
19170 }
19171 numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
19172 if (numSpaces > maxSpaces) {
19173 spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)(numSpaces * spacing / maxSpaces / unit) * unit;
19174 }
19175 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision)) {
19176 factor = Math.pow(10, precision);
19177 spacing = Math.ceil(spacing * factor) / factor;
19178 }
19179 if (bounds === 'ticks') {
19180 niceMin = Math.floor(rmin / spacing) * spacing;
19181 niceMax = Math.ceil(rmax / spacing) * spacing;
19182 } else {
19183 niceMin = rmin;
19184 niceMax = rmax;
19185 }
19186 if (minDefined && maxDefined && step && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aJ)((max - min) / step, spacing / 1000)) {
19187 numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
19188 spacing = (max - min) / numSpaces;
19189 niceMin = min;
19190 niceMax = max;
19191 } else if (countDefined) {
19192 niceMin = minDefined ? min : niceMin;
19193 niceMax = maxDefined ? max : niceMax;
19194 numSpaces = count - 1;
19195 spacing = (niceMax - niceMin) / numSpaces;
19196 } else {
19197 numSpaces = (niceMax - niceMin) / spacing;
19198 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(numSpaces, Math.round(numSpaces), spacing / 1000)) {
19199 numSpaces = Math.round(numSpaces);
19200 } else {
19201 numSpaces = Math.ceil(numSpaces);
19202 }
19203 }
19204 const decimalPlaces = Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aL)(spacing), (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aL)(niceMin));
19205 factor = Math.pow(10, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision) ? decimalPlaces : precision);
19206 niceMin = Math.round(niceMin * factor) / factor;
19207 niceMax = Math.round(niceMax * factor) / factor;
19208 let j = 0;
19209 if (minDefined) {
19210 if (includeBounds && niceMin !== min) {
19211 ticks.push({
19212 value: min
19213 });
19214 if (niceMin < min) {
19215 j++;
19216 }
19217 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
19218 j++;
19219 }
19220 } else if (niceMin < min) {
19221 j++;
19222 }
19223 }
19224 for(; j < numSpaces; ++j){
19225 const tickValue = Math.round((niceMin + j * spacing) * factor) / factor;
19226 if (maxDefined && tickValue > max) {
19227 break;
19228 }
19229 ticks.push({
19230 value: tickValue
19231 });
19232 }
19233 if (maxDefined && includeBounds && niceMax !== max) {
19234 if (ticks.length && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
19235 ticks[ticks.length - 1].value = max;
19236 } else {
19237 ticks.push({
19238 value: max
19239 });
19240 }
19241 } else if (!maxDefined || niceMax === max) {
19242 ticks.push({
19243 value: niceMax
19244 });
19245 }
19246 return ticks;
19247 }
19248 function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) {
19249 const rad = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(minRotation);
19250 const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;
19251 const length = 0.75 * minSpacing * ('' + value).length;
19252 return Math.min(minSpacing / ratio, length);
19253 }
19254 class LinearScaleBase extends Scale {
19255 constructor(cfg){
19256 super(cfg);
19257 this.start = undefined;
19258 this.end = undefined;
19259 this._startValue = undefined;
19260 this._endValue = undefined;
19261 this._valueRange = 0;
19262 }
19263 parse(raw, index) {
19264 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19265 return null;
19266 }
19267 if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
19268 return null;
19269 }
19270 return +raw;
19271 }
19272 handleTickRangeOptions() {
19273 const { beginAtZero } = this.options;
19274 const { minDefined , maxDefined } = this.getUserBounds();
19275 let { min , max } = this;
19276 const setMin = (v)=>min = minDefined ? min : v;
19277 const setMax = (v)=>max = maxDefined ? max : v;
19278 if (beginAtZero) {
19279 const minSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(min);
19280 const maxSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(max);
19281 if (minSign < 0 && maxSign < 0) {
19282 setMax(0);
19283 } else if (minSign > 0 && maxSign > 0) {
19284 setMin(0);
19285 }
19286 }
19287 if (min === max) {
19288 let offset = max === 0 ? 1 : Math.abs(max * 0.05);
19289 setMax(max + offset);
19290 if (!beginAtZero) {
19291 setMin(min - offset);
19292 }
19293 }
19294 this.min = min;
19295 this.max = max;
19296 }
19297 getTickLimit() {
19298 const tickOpts = this.options.ticks;
19299 let { maxTicksLimit , stepSize } = tickOpts;
19300 let maxTicks;
19301 if (stepSize) {
19302 maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
19303 if (maxTicks > 1000) {
19304 console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
19305 maxTicks = 1000;
19306 }
19307 } else {
19308 maxTicks = this.computeTickLimit();
19309 maxTicksLimit = maxTicksLimit || 11;
19310 }
19311 if (maxTicksLimit) {
19312 maxTicks = Math.min(maxTicksLimit, maxTicks);
19313 }
19314 return maxTicks;
19315 }
19316 computeTickLimit() {
19317 return Number.POSITIVE_INFINITY;
19318 }
19319 buildTicks() {
19320 const opts = this.options;
19321 const tickOpts = opts.ticks;
19322 let maxTicks = this.getTickLimit();
19323 maxTicks = Math.max(2, maxTicks);
19324 const numericGeneratorOptions = {
19325 maxTicks,
19326 bounds: opts.bounds,
19327 min: opts.min,
19328 max: opts.max,
19329 precision: tickOpts.precision,
19330 step: tickOpts.stepSize,
19331 count: tickOpts.count,
19332 maxDigits: this._maxDigits(),
19333 horizontal: this.isHorizontal(),
19334 minRotation: tickOpts.minRotation || 0,
19335 includeBounds: tickOpts.includeBounds !== false
19336 };
19337 const dataRange = this._range || this;
19338 const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
19339 if (opts.bounds === 'ticks') {
19340 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19341 }
19342 if (opts.reverse) {
19343 ticks.reverse();
19344 this.start = this.max;
19345 this.end = this.min;
19346 } else {
19347 this.start = this.min;
19348 this.end = this.max;
19349 }
19350 return ticks;
19351 }
19352 configure() {
19353 const ticks = this.ticks;
19354 let start = this.min;
19355 let end = this.max;
19356 super.configure();
19357 if (this.options.offset && ticks.length) {
19358 const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
19359 start -= offset;
19360 end += offset;
19361 }
19362 this._startValue = start;
19363 this._endValue = end;
19364 this._valueRange = end - start;
19365 }
19366 getLabelForValue(value) {
19367 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19368 }
19369 }
19370
19371 class LinearScale extends LinearScaleBase {
19372 static id = 'linear';
19373 static defaults = {
19374 ticks: {
19375 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19376 }
19377 };
19378 determineDataLimits() {
19379 const { min , max } = this.getMinMax(true);
19380 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? min : 0;
19381 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? max : 1;
19382 this.handleTickRangeOptions();
19383 }
19384 computeTickLimit() {
19385 const horizontal = this.isHorizontal();
19386 const length = horizontal ? this.width : this.height;
19387 const minRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.ticks.minRotation);
19388 const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;
19389 const tickFont = this._resolveTickFontOptions(0);
19390 return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
19391 }
19392 getPixelForValue(value) {
19393 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19394 }
19395 getValueForPixel(pixel) {
19396 return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
19397 }
19398 }
19399
19400 const log10Floor = (v)=>Math.floor((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(v));
19401 const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m);
19402 function isMajor(tickVal) {
19403 const remain = tickVal / Math.pow(10, log10Floor(tickVal));
19404 return remain === 1;
19405 }
19406 function steps(min, max, rangeExp) {
19407 const rangeStep = Math.pow(10, rangeExp);
19408 const start = Math.floor(min / rangeStep);
19409 const end = Math.ceil(max / rangeStep);
19410 return end - start;
19411 }
19412 function startExp(min, max) {
19413 const range = max - min;
19414 let rangeExp = log10Floor(range);
19415 while(steps(min, max, rangeExp) > 10){
19416 rangeExp++;
19417 }
19418 while(steps(min, max, rangeExp) < 10){
19419 rangeExp--;
19420 }
19421 return Math.min(rangeExp, log10Floor(min));
19422 }
19423 function generateTicks(generationOptions, { min , max }) {
19424 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, min);
19425 const ticks = [];
19426 const minExp = log10Floor(min);
19427 let exp = startExp(min, max);
19428 let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
19429 const stepSize = Math.pow(10, exp);
19430 const base = minExp > exp ? Math.pow(10, minExp) : 0;
19431 const start = Math.round((min - base) * precision) / precision;
19432 const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;
19433 let significand = Math.floor((start - offset) / Math.pow(10, exp));
19434 let value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision);
19435 while(value < max){
19436 ticks.push({
19437 value,
19438 major: isMajor(value),
19439 significand
19440 });
19441 if (significand >= 10) {
19442 significand = significand < 15 ? 15 : 20;
19443 } else {
19444 significand++;
19445 }
19446 if (significand >= 20) {
19447 exp++;
19448 significand = 2;
19449 precision = exp >= 0 ? 1 : precision;
19450 }
19451 value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;
19452 }
19453 const lastTick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.max, value);
19454 ticks.push({
19455 value: lastTick,
19456 major: isMajor(lastTick),
19457 significand
19458 });
19459 return ticks;
19460 }
19461 class LogarithmicScale extends Scale {
19462 static id = 'logarithmic';
19463 static defaults = {
19464 ticks: {
19465 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.logarithmic,
19466 major: {
19467 enabled: true
19468 }
19469 }
19470 };
19471 constructor(cfg){
19472 super(cfg);
19473 this.start = undefined;
19474 this.end = undefined;
19475 this._startValue = undefined;
19476 this._valueRange = 0;
19477 }
19478 parse(raw, index) {
19479 const value = LinearScaleBase.prototype.parse.apply(this, [
19480 raw,
19481 index
19482 ]);
19483 if (value === 0) {
19484 this._zero = true;
19485 return undefined;
19486 }
19487 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value) && value > 0 ? value : null;
19488 }
19489 determineDataLimits() {
19490 const { min , max } = this.getMinMax(true);
19491 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? Math.max(0, min) : null;
19492 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? Math.max(0, max) : null;
19493 if (this.options.beginAtZero) {
19494 this._zero = true;
19495 }
19496 if (this._zero && this.min !== this._suggestedMin && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(this._userMin)) {
19497 this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);
19498 }
19499 this.handleTickRangeOptions();
19500 }
19501 handleTickRangeOptions() {
19502 const { minDefined , maxDefined } = this.getUserBounds();
19503 let min = this.min;
19504 let max = this.max;
19505 const setMin = (v)=>min = minDefined ? min : v;
19506 const setMax = (v)=>max = maxDefined ? max : v;
19507 if (min === max) {
19508 if (min <= 0) {
19509 setMin(1);
19510 setMax(10);
19511 } else {
19512 setMin(changeExponent(min, -1));
19513 setMax(changeExponent(max, +1));
19514 }
19515 }
19516 if (min <= 0) {
19517 setMin(changeExponent(max, -1));
19518 }
19519 if (max <= 0) {
19520 setMax(changeExponent(min, +1));
19521 }
19522 this.min = min;
19523 this.max = max;
19524 }
19525 buildTicks() {
19526 const opts = this.options;
19527 const generationOptions = {
19528 min: this._userMin,
19529 max: this._userMax
19530 };
19531 const ticks = generateTicks(generationOptions, this);
19532 if (opts.bounds === 'ticks') {
19533 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19534 }
19535 if (opts.reverse) {
19536 ticks.reverse();
19537 this.start = this.max;
19538 this.end = this.min;
19539 } else {
19540 this.start = this.min;
19541 this.end = this.max;
19542 }
19543 return ticks;
19544 }
19545 getLabelForValue(value) {
19546 return value === undefined ? '0' : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19547 }
19548 configure() {
19549 const start = this.min;
19550 super.configure();
19551 this._startValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start);
19552 this._valueRange = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(this.max) - (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start);
19553 }
19554 getPixelForValue(value) {
19555 if (value === undefined || value === 0) {
19556 value = this.min;
19557 }
19558 if (value === null || isNaN(value)) {
19559 return NaN;
19560 }
19561 return this.getPixelForDecimal(value === this.min ? 0 : ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(value) - this._startValue) / this._valueRange);
19562 }
19563 getValueForPixel(pixel) {
19564 const decimal = this.getDecimalForPixel(pixel);
19565 return Math.pow(10, this._startValue + decimal * this._valueRange);
19566 }
19567 }
19568
19569 function getTickBackdropHeight(opts) {
19570 const tickOpts = opts.ticks;
19571 if (tickOpts.display && opts.display) {
19572 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(tickOpts.backdropPadding);
19573 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(tickOpts.font && tickOpts.font.size, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.font.size) + padding.height;
19574 }
19575 return 0;
19576 }
19577 function measureLabelSize(ctx, font, label) {
19578 label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label : [
19579 label
19580 ];
19581 return {
19582 w: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aO)(ctx, font.string, label),
19583 h: label.length * font.lineHeight
19584 };
19585 }
19586 function determineLimits(angle, pos, size, min, max) {
19587 if (angle === min || angle === max) {
19588 return {
19589 start: pos - size / 2,
19590 end: pos + size / 2
19591 };
19592 } else if (angle < min || angle > max) {
19593 return {
19594 start: pos - size,
19595 end: pos
19596 };
19597 }
19598 return {
19599 start: pos,
19600 end: pos + size
19601 };
19602 }
19603 function fitWithPointLabels(scale) {
19604 const orig = {
19605 l: scale.left + scale._padding.left,
19606 r: scale.right - scale._padding.right,
19607 t: scale.top + scale._padding.top,
19608 b: scale.bottom - scale._padding.bottom
19609 };
19610 const limits = Object.assign({}, orig);
19611 const labelSizes = [];
19612 const padding = [];
19613 const valueCount = scale._pointLabels.length;
19614 const pointLabelOpts = scale.options.pointLabels;
19615 const additionalAngle = pointLabelOpts.centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0;
19616 for(let i = 0; i < valueCount; i++){
19617 const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
19618 padding[i] = opts.padding;
19619 const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
19620 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
19621 const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
19622 labelSizes[i] = textSize;
19623 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(scale.getIndexAngle(i) + additionalAngle);
19624 const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(angleRadians));
19625 const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
19626 const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
19627 updateLimits(limits, orig, angleRadians, hLimits, vLimits);
19628 }
19629 scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);
19630 scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
19631 }
19632 function updateLimits(limits, orig, angle, hLimits, vLimits) {
19633 const sin = Math.abs(Math.sin(angle));
19634 const cos = Math.abs(Math.cos(angle));
19635 let x = 0;
19636 let y = 0;
19637 if (hLimits.start < orig.l) {
19638 x = (orig.l - hLimits.start) / sin;
19639 limits.l = Math.min(limits.l, orig.l - x);
19640 } else if (hLimits.end > orig.r) {
19641 x = (hLimits.end - orig.r) / sin;
19642 limits.r = Math.max(limits.r, orig.r + x);
19643 }
19644 if (vLimits.start < orig.t) {
19645 y = (orig.t - vLimits.start) / cos;
19646 limits.t = Math.min(limits.t, orig.t - y);
19647 } else if (vLimits.end > orig.b) {
19648 y = (vLimits.end - orig.b) / cos;
19649 limits.b = Math.max(limits.b, orig.b + y);
19650 }
19651 }
19652 function createPointLabelItem(scale, index, itemOpts) {
19653 const outerDistance = scale.drawingArea;
19654 const { extra , additionalAngle , padding , size } = itemOpts;
19655 const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);
19656 const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(pointLabelPosition.angle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H)));
19657 const y = yForAngle(pointLabelPosition.y, size.h, angle);
19658 const textAlign = getTextAlignForAngle(angle);
19659 const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
19660 return {
19661 visible: true,
19662 x: pointLabelPosition.x,
19663 y,
19664 textAlign,
19665 left,
19666 top: y,
19667 right: left + size.w,
19668 bottom: y + size.h
19669 };
19670 }
19671 function isNotOverlapped(item, area) {
19672 if (!area) {
19673 return true;
19674 }
19675 const { left , top , right , bottom } = item;
19676 const apexesInArea = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19677 x: left,
19678 y: top
19679 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19680 x: left,
19681 y: bottom
19682 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19683 x: right,
19684 y: top
19685 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19686 x: right,
19687 y: bottom
19688 }, area);
19689 return !apexesInArea;
19690 }
19691 function buildPointLabelItems(scale, labelSizes, padding) {
19692 const items = [];
19693 const valueCount = scale._pointLabels.length;
19694 const opts = scale.options;
19695 const { centerPointLabels , display } = opts.pointLabels;
19696 const itemOpts = {
19697 extra: getTickBackdropHeight(opts) / 2,
19698 additionalAngle: centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0
19699 };
19700 let area;
19701 for(let i = 0; i < valueCount; i++){
19702 itemOpts.padding = padding[i];
19703 itemOpts.size = labelSizes[i];
19704 const item = createPointLabelItem(scale, i, itemOpts);
19705 items.push(item);
19706 if (display === 'auto') {
19707 item.visible = isNotOverlapped(item, area);
19708 if (item.visible) {
19709 area = item;
19710 }
19711 }
19712 }
19713 return items;
19714 }
19715 function getTextAlignForAngle(angle) {
19716 if (angle === 0 || angle === 180) {
19717 return 'center';
19718 } else if (angle < 180) {
19719 return 'left';
19720 }
19721 return 'right';
19722 }
19723 function leftForTextAlign(x, w, align) {
19724 if (align === 'right') {
19725 x -= w;
19726 } else if (align === 'center') {
19727 x -= w / 2;
19728 }
19729 return x;
19730 }
19731 function yForAngle(y, h, angle) {
19732 if (angle === 90 || angle === 270) {
19733 y -= h / 2;
19734 } else if (angle > 270 || angle < 90) {
19735 y -= h;
19736 }
19737 return y;
19738 }
19739 function drawPointLabelBox(ctx, opts, item) {
19740 const { left , top , right , bottom } = item;
19741 const { backdropColor } = opts;
19742 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(backdropColor)) {
19743 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(opts.borderRadius);
19744 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.backdropPadding);
19745 ctx.fillStyle = backdropColor;
19746 const backdropLeft = left - padding.left;
19747 const backdropTop = top - padding.top;
19748 const backdropWidth = right - left + padding.width;
19749 const backdropHeight = bottom - top + padding.height;
19750 if (Object.values(borderRadius).some((v)=>v !== 0)) {
19751 ctx.beginPath();
19752 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
19753 x: backdropLeft,
19754 y: backdropTop,
19755 w: backdropWidth,
19756 h: backdropHeight,
19757 radius: borderRadius
19758 });
19759 ctx.fill();
19760 } else {
19761 ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);
19762 }
19763 }
19764 }
19765 function drawPointLabels(scale, labelCount) {
19766 const { ctx , options: { pointLabels } } = scale;
19767 for(let i = labelCount - 1; i >= 0; i--){
19768 const item = scale._pointLabelItems[i];
19769 if (!item.visible) {
19770 continue;
19771 }
19772 const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));
19773 drawPointLabelBox(ctx, optsAtIndex, item);
19774 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
19775 const { x , y , textAlign } = item;
19776 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, {
19777 color: optsAtIndex.color,
19778 textAlign: textAlign,
19779 textBaseline: 'middle'
19780 });
19781 }
19782 }
19783 function pathRadiusLine(scale, radius, circular, labelCount) {
19784 const { ctx } = scale;
19785 if (circular) {
19786 ctx.arc(scale.xCenter, scale.yCenter, radius, 0, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
19787 } else {
19788 let pointPosition = scale.getPointPosition(0, radius);
19789 ctx.moveTo(pointPosition.x, pointPosition.y);
19790 for(let i = 1; i < labelCount; i++){
19791 pointPosition = scale.getPointPosition(i, radius);
19792 ctx.lineTo(pointPosition.x, pointPosition.y);
19793 }
19794 }
19795 }
19796 function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {
19797 const ctx = scale.ctx;
19798 const circular = gridLineOpts.circular;
19799 const { color , lineWidth } = gridLineOpts;
19800 if (!circular && !labelCount || !color || !lineWidth || radius < 0) {
19801 return;
19802 }
19803 ctx.save();
19804 ctx.strokeStyle = color;
19805 ctx.lineWidth = lineWidth;
19806 ctx.setLineDash(borderOpts.dash || []);
19807 ctx.lineDashOffset = borderOpts.dashOffset;
19808 ctx.beginPath();
19809 pathRadiusLine(scale, radius, circular, labelCount);
19810 ctx.closePath();
19811 ctx.stroke();
19812 ctx.restore();
19813 }
19814 function createPointLabelContext(parent, index, label) {
19815 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
19816 label,
19817 index,
19818 type: 'pointLabel'
19819 });
19820 }
19821 class RadialLinearScale extends LinearScaleBase {
19822 static id = 'radialLinear';
19823 static defaults = {
19824 display: true,
19825 animate: true,
19826 position: 'chartArea',
19827 angleLines: {
19828 display: true,
19829 lineWidth: 1,
19830 borderDash: [],
19831 borderDashOffset: 0.0
19832 },
19833 grid: {
19834 circular: false
19835 },
19836 startAngle: 0,
19837 ticks: {
19838 showLabelBackdrop: true,
19839 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19840 },
19841 pointLabels: {
19842 backdropColor: undefined,
19843 backdropPadding: 2,
19844 display: true,
19845 font: {
19846 size: 10
19847 },
19848 callback (label) {
19849 return label;
19850 },
19851 padding: 5,
19852 centerPointLabels: false
19853 }
19854 };
19855 static defaultRoutes = {
19856 'angleLines.color': 'borderColor',
19857 'pointLabels.color': 'color',
19858 'ticks.color': 'color'
19859 };
19860 static descriptors = {
19861 angleLines: {
19862 _fallback: 'grid'
19863 }
19864 };
19865 constructor(cfg){
19866 super(cfg);
19867 this.xCenter = undefined;
19868 this.yCenter = undefined;
19869 this.drawingArea = undefined;
19870 this._pointLabels = [];
19871 this._pointLabelItems = [];
19872 }
19873 setDimensions() {
19874 const padding = this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(getTickBackdropHeight(this.options) / 2);
19875 const w = this.width = this.maxWidth - padding.width;
19876 const h = this.height = this.maxHeight - padding.height;
19877 this.xCenter = Math.floor(this.left + w / 2 + padding.left);
19878 this.yCenter = Math.floor(this.top + h / 2 + padding.top);
19879 this.drawingArea = Math.floor(Math.min(w, h) / 2);
19880 }
19881 determineDataLimits() {
19882 const { min , max } = this.getMinMax(false);
19883 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : 0;
19884 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : 0;
19885 this.handleTickRangeOptions();
19886 }
19887 computeTickLimit() {
19888 return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
19889 }
19890 generateTickLabels(ticks) {
19891 LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
19892 this._pointLabels = this.getLabels().map((value, index)=>{
19893 const label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.pointLabels.callback, [
19894 value,
19895 index
19896 ], this);
19897 return label || label === 0 ? label : '';
19898 }).filter((v, i)=>this.chart.getDataVisibility(i));
19899 }
19900 fit() {
19901 const opts = this.options;
19902 if (opts.display && opts.pointLabels.display) {
19903 fitWithPointLabels(this);
19904 } else {
19905 this.setCenterPoint(0, 0, 0, 0);
19906 }
19907 }
19908 setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
19909 this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
19910 this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
19911 this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
19912 }
19913 getIndexAngle(index) {
19914 const angleMultiplier = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T / (this._pointLabels.length || 1);
19915 const startAngle = this.options.startAngle || 0;
19916 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(index * angleMultiplier + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(startAngle));
19917 }
19918 getDistanceFromCenterForValue(value) {
19919 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
19920 return NaN;
19921 }
19922 const scalingFactor = this.drawingArea / (this.max - this.min);
19923 if (this.options.reverse) {
19924 return (this.max - value) * scalingFactor;
19925 }
19926 return (value - this.min) * scalingFactor;
19927 }
19928 getValueForDistanceFromCenter(distance) {
19929 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(distance)) {
19930 return NaN;
19931 }
19932 const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
19933 return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
19934 }
19935 getPointLabelContext(index) {
19936 const pointLabels = this._pointLabels || [];
19937 if (index >= 0 && index < pointLabels.length) {
19938 const pointLabel = pointLabels[index];
19939 return createPointLabelContext(this.getContext(), index, pointLabel);
19940 }
19941 }
19942 getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
19943 const angle = this.getIndexAngle(index) - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H + additionalAngle;
19944 return {
19945 x: Math.cos(angle) * distanceFromCenter + this.xCenter,
19946 y: Math.sin(angle) * distanceFromCenter + this.yCenter,
19947 angle
19948 };
19949 }
19950 getPointPositionForValue(index, value) {
19951 return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
19952 }
19953 getBasePosition(index) {
19954 return this.getPointPositionForValue(index || 0, this.getBaseValue());
19955 }
19956 getPointLabelPosition(index) {
19957 const { left , top , right , bottom } = this._pointLabelItems[index];
19958 return {
19959 left,
19960 top,
19961 right,
19962 bottom
19963 };
19964 }
19965 drawBackground() {
19966 const { backgroundColor , grid: { circular } } = this.options;
19967 if (backgroundColor) {
19968 const ctx = this.ctx;
19969 ctx.save();
19970 ctx.beginPath();
19971 pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
19972 ctx.closePath();
19973 ctx.fillStyle = backgroundColor;
19974 ctx.fill();
19975 ctx.restore();
19976 }
19977 }
19978 drawGrid() {
19979 const ctx = this.ctx;
19980 const opts = this.options;
19981 const { angleLines , grid , border } = opts;
19982 const labelCount = this._pointLabels.length;
19983 let i, offset, position;
19984 if (opts.pointLabels.display) {
19985 drawPointLabels(this, labelCount);
19986 }
19987 if (grid.display) {
19988 this.ticks.forEach((tick, index)=>{
19989 if (index !== 0 || index === 0 && this.min < 0) {
19990 offset = this.getDistanceFromCenterForValue(tick.value);
19991 const context = this.getContext(index);
19992 const optsAtIndex = grid.setContext(context);
19993 const optsAtIndexBorder = border.setContext(context);
19994 drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);
19995 }
19996 });
19997 }
19998 if (angleLines.display) {
19999 ctx.save();
20000 for(i = labelCount - 1; i >= 0; i--){
20001 const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
20002 const { color , lineWidth } = optsAtIndex;
20003 if (!lineWidth || !color) {
20004 continue;
20005 }
20006 ctx.lineWidth = lineWidth;
20007 ctx.strokeStyle = color;
20008 ctx.setLineDash(optsAtIndex.borderDash);
20009 ctx.lineDashOffset = optsAtIndex.borderDashOffset;
20010 offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);
20011 position = this.getPointPosition(i, offset);
20012 ctx.beginPath();
20013 ctx.moveTo(this.xCenter, this.yCenter);
20014 ctx.lineTo(position.x, position.y);
20015 ctx.stroke();
20016 }
20017 ctx.restore();
20018 }
20019 }
20020 drawBorder() {}
20021 drawLabels() {
20022 const ctx = this.ctx;
20023 const opts = this.options;
20024 const tickOpts = opts.ticks;
20025 if (!tickOpts.display) {
20026 return;
20027 }
20028 const startAngle = this.getIndexAngle(0);
20029 let offset, width;
20030 ctx.save();
20031 ctx.translate(this.xCenter, this.yCenter);
20032 ctx.rotate(startAngle);
20033 ctx.textAlign = 'center';
20034 ctx.textBaseline = 'middle';
20035 this.ticks.forEach((tick, index)=>{
20036 if (index === 0 && this.min >= 0 && !opts.reverse) {
20037 return;
20038 }
20039 const optsAtIndex = tickOpts.setContext(this.getContext(index));
20040 const tickFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
20041 offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
20042 if (optsAtIndex.showLabelBackdrop) {
20043 ctx.font = tickFont.string;
20044 width = ctx.measureText(tick.label).width;
20045 ctx.fillStyle = optsAtIndex.backdropColor;
20046 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
20047 ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);
20048 }
20049 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, tick.label, 0, -offset, tickFont, {
20050 color: optsAtIndex.color,
20051 strokeColor: optsAtIndex.textStrokeColor,
20052 strokeWidth: optsAtIndex.textStrokeWidth
20053 });
20054 });
20055 ctx.restore();
20056 }
20057 drawTitle() {}
20058 }
20059
20060 const INTERVALS = {
20061 millisecond: {
20062 common: true,
20063 size: 1,
20064 steps: 1000
20065 },
20066 second: {
20067 common: true,
20068 size: 1000,
20069 steps: 60
20070 },
20071 minute: {
20072 common: true,
20073 size: 60000,
20074 steps: 60
20075 },
20076 hour: {
20077 common: true,
20078 size: 3600000,
20079 steps: 24
20080 },
20081 day: {
20082 common: true,
20083 size: 86400000,
20084 steps: 30
20085 },
20086 week: {
20087 common: false,
20088 size: 604800000,
20089 steps: 4
20090 },
20091 month: {
20092 common: true,
20093 size: 2.628e9,
20094 steps: 12
20095 },
20096 quarter: {
20097 common: false,
20098 size: 7.884e9,
20099 steps: 4
20100 },
20101 year: {
20102 common: true,
20103 size: 3.154e10
20104 }
20105 };
20106 const UNITS = /* #__PURE__ */ Object.keys(INTERVALS);
20107 function sorter(a, b) {
20108 return a - b;
20109 }
20110 function parse(scale, input) {
20111 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(input)) {
20112 return null;
20113 }
20114 const adapter = scale._adapter;
20115 const { parser , round , isoWeekday } = scale._parseOpts;
20116 let value = input;
20117 if (typeof parser === 'function') {
20118 value = parser(value);
20119 }
20120 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
20121 value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value);
20122 }
20123 if (value === null) {
20124 return null;
20125 }
20126 if (round) {
20127 value = round === 'week' && ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round);
20128 }
20129 return +value;
20130 }
20131 function determineUnitForAutoTicks(minUnit, min, max, capacity) {
20132 const ilen = UNITS.length;
20133 for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){
20134 const interval = INTERVALS[UNITS[i]];
20135 const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
20136 if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
20137 return UNITS[i];
20138 }
20139 }
20140 return UNITS[ilen - 1];
20141 }
20142 function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
20143 for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){
20144 const unit = UNITS[i];
20145 if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
20146 return unit;
20147 }
20148 }
20149 return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
20150 }
20151 function determineMajorUnit(unit) {
20152 for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){
20153 if (INTERVALS[UNITS[i]].common) {
20154 return UNITS[i];
20155 }
20156 }
20157 }
20158 function addTick(ticks, time, timestamps) {
20159 if (!timestamps) {
20160 ticks[time] = true;
20161 } else if (timestamps.length) {
20162 const { lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aQ)(timestamps, time);
20163 const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
20164 ticks[timestamp] = true;
20165 }
20166 }
20167 function setMajorTicks(scale, ticks, map, majorUnit) {
20168 const adapter = scale._adapter;
20169 const first = +adapter.startOf(ticks[0].value, majorUnit);
20170 const last = ticks[ticks.length - 1].value;
20171 let major, index;
20172 for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){
20173 index = map[major];
20174 if (index >= 0) {
20175 ticks[index].major = true;
20176 }
20177 }
20178 return ticks;
20179 }
20180 function ticksFromTimestamps(scale, values, majorUnit) {
20181 const ticks = [];
20182 const map = {};
20183 const ilen = values.length;
20184 let i, value;
20185 for(i = 0; i < ilen; ++i){
20186 value = values[i];
20187 map[value] = i;
20188 ticks.push({
20189 value,
20190 major: false
20191 });
20192 }
20193 return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
20194 }
20195 class TimeScale extends Scale {
20196 static id = 'time';
20197 static defaults = {
20198 bounds: 'data',
20199 adapters: {},
20200 time: {
20201 parser: false,
20202 unit: false,
20203 round: false,
20204 isoWeekday: false,
20205 minUnit: 'millisecond',
20206 displayFormats: {}
20207 },
20208 ticks: {
20209 source: 'auto',
20210 callback: false,
20211 major: {
20212 enabled: false
20213 }
20214 }
20215 };
20216 constructor(props){
20217 super(props);
20218 this._cache = {
20219 data: [],
20220 labels: [],
20221 all: []
20222 };
20223 this._unit = 'day';
20224 this._majorUnit = undefined;
20225 this._offsets = {};
20226 this._normalized = false;
20227 this._parseOpts = undefined;
20228 }
20229 init(scaleOpts, opts = {}) {
20230 const time = scaleOpts.time || (scaleOpts.time = {});
20231 const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
20232 adapter.init(opts);
20233 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(time.displayFormats, adapter.formats());
20234 this._parseOpts = {
20235 parser: time.parser,
20236 round: time.round,
20237 isoWeekday: time.isoWeekday
20238 };
20239 super.init(scaleOpts);
20240 this._normalized = opts.normalized;
20241 }
20242 parse(raw, index) {
20243 if (raw === undefined) {
20244 return null;
20245 }
20246 return parse(this, raw);
20247 }
20248 beforeLayout() {
20249 super.beforeLayout();
20250 this._cache = {
20251 data: [],
20252 labels: [],
20253 all: []
20254 };
20255 }
20256 determineDataLimits() {
20257 const options = this.options;
20258 const adapter = this._adapter;
20259 const unit = options.time.unit || 'day';
20260 let { min , max , minDefined , maxDefined } = this.getUserBounds();
20261 function _applyBounds(bounds) {
20262 if (!minDefined && !isNaN(bounds.min)) {
20263 min = Math.min(min, bounds.min);
20264 }
20265 if (!maxDefined && !isNaN(bounds.max)) {
20266 max = Math.max(max, bounds.max);
20267 }
20268 }
20269 if (!minDefined || !maxDefined) {
20270 _applyBounds(this._getLabelBounds());
20271 if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
20272 _applyBounds(this.getMinMax(false));
20273 }
20274 }
20275 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
20276 max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
20277 this.min = Math.min(min, max - 1);
20278 this.max = Math.max(min + 1, max);
20279 }
20280 _getLabelBounds() {
20281 const arr = this.getLabelTimestamps();
20282 let min = Number.POSITIVE_INFINITY;
20283 let max = Number.NEGATIVE_INFINITY;
20284 if (arr.length) {
20285 min = arr[0];
20286 max = arr[arr.length - 1];
20287 }
20288 return {
20289 min,
20290 max
20291 };
20292 }
20293 buildTicks() {
20294 const options = this.options;
20295 const timeOpts = options.time;
20296 const tickOpts = options.ticks;
20297 const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();
20298 if (options.bounds === 'ticks' && timestamps.length) {
20299 this.min = this._userMin || timestamps[0];
20300 this.max = this._userMax || timestamps[timestamps.length - 1];
20301 }
20302 const min = this.min;
20303 const max = this.max;
20304 const ticks = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aP)(timestamps, min, max);
20305 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));
20306 this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit);
20307 this.initOffsets(timestamps);
20308 if (options.reverse) {
20309 ticks.reverse();
20310 }
20311 return ticksFromTimestamps(this, ticks, this._majorUnit);
20312 }
20313 afterAutoSkip() {
20314 if (this.options.offsetAfterAutoskip) {
20315 this.initOffsets(this.ticks.map((tick)=>+tick.value));
20316 }
20317 }
20318 initOffsets(timestamps = []) {
20319 let start = 0;
20320 let end = 0;
20321 let first, last;
20322 if (this.options.offset && timestamps.length) {
20323 first = this.getDecimalForValue(timestamps[0]);
20324 if (timestamps.length === 1) {
20325 start = 1 - first;
20326 } else {
20327 start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
20328 }
20329 last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
20330 if (timestamps.length === 1) {
20331 end = last;
20332 } else {
20333 end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
20334 }
20335 }
20336 const limit = timestamps.length < 3 ? 0.5 : 0.25;
20337 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(start, 0, limit);
20338 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(end, 0, limit);
20339 this._offsets = {
20340 start,
20341 end,
20342 factor: 1 / (start + 1 + end)
20343 };
20344 }
20345 _generate() {
20346 const adapter = this._adapter;
20347 const min = this.min;
20348 const max = this.max;
20349 const options = this.options;
20350 const timeOpts = options.time;
20351 const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
20352 const stepSize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.stepSize, 1);
20353 const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
20354 const hasWeekday = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(weekday) || weekday === true;
20355 const ticks = {};
20356 let first = min;
20357 let time, count;
20358 if (hasWeekday) {
20359 first = +adapter.startOf(first, 'isoWeek', weekday);
20360 }
20361 first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
20362 if (adapter.diff(max, min, minor) > 100000 * stepSize) {
20363 throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
20364 }
20365 const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();
20366 for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){
20367 addTick(ticks, time, timestamps);
20368 }
20369 if (time === max || options.bounds === 'ticks' || count === 1) {
20370 addTick(ticks, time, timestamps);
20371 }
20372 return Object.keys(ticks).sort(sorter).map((x)=>+x);
20373 }
20374 getLabelForValue(value) {
20375 const adapter = this._adapter;
20376 const timeOpts = this.options.time;
20377 if (timeOpts.tooltipFormat) {
20378 return adapter.format(value, timeOpts.tooltipFormat);
20379 }
20380 return adapter.format(value, timeOpts.displayFormats.datetime);
20381 }
20382 format(value, format) {
20383 const options = this.options;
20384 const formats = options.time.displayFormats;
20385 const unit = this._unit;
20386 const fmt = format || formats[unit];
20387 return this._adapter.format(value, fmt);
20388 }
20389 _tickFormatFunction(time, index, ticks, format) {
20390 const options = this.options;
20391 const formatter = options.ticks.callback;
20392 if (formatter) {
20393 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(formatter, [
20394 time,
20395 index,
20396 ticks
20397 ], this);
20398 }
20399 const formats = options.time.displayFormats;
20400 const unit = this._unit;
20401 const majorUnit = this._majorUnit;
20402 const minorFormat = unit && formats[unit];
20403 const majorFormat = majorUnit && formats[majorUnit];
20404 const tick = ticks[index];
20405 const major = majorUnit && majorFormat && tick && tick.major;
20406 return this._adapter.format(time, format || (major ? majorFormat : minorFormat));
20407 }
20408 generateTickLabels(ticks) {
20409 let i, ilen, tick;
20410 for(i = 0, ilen = ticks.length; i < ilen; ++i){
20411 tick = ticks[i];
20412 tick.label = this._tickFormatFunction(tick.value, i, ticks);
20413 }
20414 }
20415 getDecimalForValue(value) {
20416 return value === null ? NaN : (value - this.min) / (this.max - this.min);
20417 }
20418 getPixelForValue(value) {
20419 const offsets = this._offsets;
20420 const pos = this.getDecimalForValue(value);
20421 return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
20422 }
20423 getValueForPixel(pixel) {
20424 const offsets = this._offsets;
20425 const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20426 return this.min + pos * (this.max - this.min);
20427 }
20428 _getLabelSize(label) {
20429 const ticksOpts = this.options.ticks;
20430 const tickLabelWidth = this.ctx.measureText(label).width;
20431 const angle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
20432 const cosRotation = Math.cos(angle);
20433 const sinRotation = Math.sin(angle);
20434 const tickFontSize = this._resolveTickFontOptions(0).size;
20435 return {
20436 w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,
20437 h: tickLabelWidth * sinRotation + tickFontSize * cosRotation
20438 };
20439 }
20440 _getLabelCapacity(exampleTime) {
20441 const timeOpts = this.options.time;
20442 const displayFormats = timeOpts.displayFormats;
20443 const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
20444 const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [
20445 exampleTime
20446 ], this._majorUnit), format);
20447 const size = this._getLabelSize(exampleLabel);
20448 const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
20449 return capacity > 0 ? capacity : 1;
20450 }
20451 getDataTimestamps() {
20452 let timestamps = this._cache.data || [];
20453 let i, ilen;
20454 if (timestamps.length) {
20455 return timestamps;
20456 }
20457 const metas = this.getMatchingVisibleMetas();
20458 if (this._normalized && metas.length) {
20459 return this._cache.data = metas[0].controller.getAllParsedValues(this);
20460 }
20461 for(i = 0, ilen = metas.length; i < ilen; ++i){
20462 timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));
20463 }
20464 return this._cache.data = this.normalize(timestamps);
20465 }
20466 getLabelTimestamps() {
20467 const timestamps = this._cache.labels || [];
20468 let i, ilen;
20469 if (timestamps.length) {
20470 return timestamps;
20471 }
20472 const labels = this.getLabels();
20473 for(i = 0, ilen = labels.length; i < ilen; ++i){
20474 timestamps.push(parse(this, labels[i]));
20475 }
20476 return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);
20477 }
20478 normalize(values) {
20479 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort(sorter));
20480 }
20481 }
20482
20483 function interpolate(table, val, reverse) {
20484 let lo = 0;
20485 let hi = table.length - 1;
20486 let prevSource, nextSource, prevTarget, nextTarget;
20487 if (reverse) {
20488 if (val >= table[lo].pos && val <= table[hi].pos) {
20489 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'pos', val));
20490 }
20491 ({ pos: prevSource , time: prevTarget } = table[lo]);
20492 ({ pos: nextSource , time: nextTarget } = table[hi]);
20493 } else {
20494 if (val >= table[lo].time && val <= table[hi].time) {
20495 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'time', val));
20496 }
20497 ({ time: prevSource , pos: prevTarget } = table[lo]);
20498 ({ time: nextSource , pos: nextTarget } = table[hi]);
20499 }
20500 const span = nextSource - prevSource;
20501 return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
20502 }
20503 class TimeSeriesScale extends TimeScale {
20504 static id = 'timeseries';
20505 static defaults = TimeScale.defaults;
20506 constructor(props){
20507 super(props);
20508 this._table = [];
20509 this._minPos = undefined;
20510 this._tableRange = undefined;
20511 }
20512 initOffsets() {
20513 const timestamps = this._getTimestampsForTable();
20514 const table = this._table = this.buildLookupTable(timestamps);
20515 this._minPos = interpolate(table, this.min);
20516 this._tableRange = interpolate(table, this.max) - this._minPos;
20517 super.initOffsets(timestamps);
20518 }
20519 buildLookupTable(timestamps) {
20520 const { min , max } = this;
20521 const items = [];
20522 const table = [];
20523 let i, ilen, prev, curr, next;
20524 for(i = 0, ilen = timestamps.length; i < ilen; ++i){
20525 curr = timestamps[i];
20526 if (curr >= min && curr <= max) {
20527 items.push(curr);
20528 }
20529 }
20530 if (items.length < 2) {
20531 return [
20532 {
20533 time: min,
20534 pos: 0
20535 },
20536 {
20537 time: max,
20538 pos: 1
20539 }
20540 ];
20541 }
20542 for(i = 0, ilen = items.length; i < ilen; ++i){
20543 next = items[i + 1];
20544 prev = items[i - 1];
20545 curr = items[i];
20546 if (Math.round((next + prev) / 2) !== curr) {
20547 table.push({
20548 time: curr,
20549 pos: i / (ilen - 1)
20550 });
20551 }
20552 }
20553 return table;
20554 }
20555 _generate() {
20556 const min = this.min;
20557 const max = this.max;
20558 let timestamps = super.getDataTimestamps();
20559 if (!timestamps.includes(min) || !timestamps.length) {
20560 timestamps.splice(0, 0, min);
20561 }
20562 if (!timestamps.includes(max) || timestamps.length === 1) {
20563 timestamps.push(max);
20564 }
20565 return timestamps.sort((a, b)=>a - b);
20566 }
20567 _getTimestampsForTable() {
20568 let timestamps = this._cache.all || [];
20569 if (timestamps.length) {
20570 return timestamps;
20571 }
20572 const data = this.getDataTimestamps();
20573 const label = this.getLabelTimestamps();
20574 if (data.length && label.length) {
20575 timestamps = this.normalize(data.concat(label));
20576 } else {
20577 timestamps = data.length ? data : label;
20578 }
20579 timestamps = this._cache.all = timestamps;
20580 return timestamps;
20581 }
20582 getDecimalForValue(value) {
20583 return (interpolate(this._table, value) - this._minPos) / this._tableRange;
20584 }
20585 getValueForPixel(pixel) {
20586 const offsets = this._offsets;
20587 const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20588 return interpolate(this._table, decimal * this._tableRange + this._minPos, true);
20589 }
20590 }
20591
20592 var scales = /*#__PURE__*/Object.freeze({
20593 __proto__: null,
20594 CategoryScale: CategoryScale,
20595 LinearScale: LinearScale,
20596 LogarithmicScale: LogarithmicScale,
20597 RadialLinearScale: RadialLinearScale,
20598 TimeScale: TimeScale,
20599 TimeSeriesScale: TimeSeriesScale
20600 });
20601
20602 const registerables = [
20603 controllers,
20604 elements,
20605 plugins,
20606 scales
20607 ];
20608
20609
20610 //# sourceMappingURL=chart.js.map
20611
20612
20613 /***/ },
20614
20615 /***/ "./node_modules/chart.js/dist/chunks/helpers.dataset.js"
20616 /*!**************************************************************!*\
20617 !*** ./node_modules/chart.js/dist/chunks/helpers.dataset.js ***!
20618 \**************************************************************/
20619 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
20620
20621 "use strict";
20622 __webpack_require__.r(__webpack_exports__);
20623 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
20624 /* harmony export */ $: () => (/* binding */ unclipArea),
20625 /* harmony export */ A: () => (/* binding */ _rlookupByKey),
20626 /* harmony export */ B: () => (/* binding */ _lookupByKey),
20627 /* harmony export */ C: () => (/* binding */ _isPointInArea),
20628 /* harmony export */ D: () => (/* binding */ getAngleFromPoint),
20629 /* harmony export */ E: () => (/* binding */ toPadding),
20630 /* harmony export */ F: () => (/* binding */ each),
20631 /* harmony export */ G: () => (/* binding */ getMaximumSize),
20632 /* harmony export */ H: () => (/* binding */ HALF_PI),
20633 /* harmony export */ I: () => (/* binding */ _getParentNode),
20634 /* harmony export */ J: () => (/* binding */ readUsedSize),
20635 /* harmony export */ K: () => (/* binding */ supportsEventListenerOptions),
20636 /* harmony export */ L: () => (/* binding */ throttled),
20637 /* harmony export */ M: () => (/* binding */ _isDomSupported),
20638 /* harmony export */ N: () => (/* binding */ _factorize),
20639 /* harmony export */ O: () => (/* binding */ finiteOrDefault),
20640 /* harmony export */ P: () => (/* binding */ PI),
20641 /* harmony export */ Q: () => (/* binding */ callback),
20642 /* harmony export */ R: () => (/* binding */ _addGrace),
20643 /* harmony export */ S: () => (/* binding */ _limitValue),
20644 /* harmony export */ T: () => (/* binding */ TAU),
20645 /* harmony export */ U: () => (/* binding */ toDegrees),
20646 /* harmony export */ V: () => (/* binding */ _measureText),
20647 /* harmony export */ W: () => (/* binding */ _int16Range),
20648 /* harmony export */ X: () => (/* binding */ _alignPixel),
20649 /* harmony export */ Y: () => (/* binding */ clipArea),
20650 /* harmony export */ Z: () => (/* binding */ renderText),
20651 /* harmony export */ _: () => (/* binding */ _arrayUnique),
20652 /* harmony export */ a: () => (/* binding */ resolve),
20653 /* harmony export */ a$: () => (/* binding */ getStyle),
20654 /* harmony export */ a0: () => (/* binding */ toFont),
20655 /* harmony export */ a1: () => (/* binding */ _toLeftRightCenter),
20656 /* harmony export */ a2: () => (/* binding */ _alignStartEnd),
20657 /* harmony export */ a3: () => (/* binding */ overrides),
20658 /* harmony export */ a4: () => (/* binding */ merge),
20659 /* harmony export */ a5: () => (/* binding */ _capitalize),
20660 /* harmony export */ a6: () => (/* binding */ descriptors),
20661 /* harmony export */ a7: () => (/* binding */ isFunction),
20662 /* harmony export */ a8: () => (/* binding */ _attachContext),
20663 /* harmony export */ a9: () => (/* binding */ _createResolver),
20664 /* harmony export */ aA: () => (/* binding */ getRtlAdapter),
20665 /* harmony export */ aB: () => (/* binding */ overrideTextDirection),
20666 /* harmony export */ aC: () => (/* binding */ _textX),
20667 /* harmony export */ aD: () => (/* binding */ restoreTextDirection),
20668 /* harmony export */ aE: () => (/* binding */ drawPointLegend),
20669 /* harmony export */ aF: () => (/* binding */ distanceBetweenPoints),
20670 /* harmony export */ aG: () => (/* binding */ noop),
20671 /* harmony export */ aH: () => (/* binding */ _setMinAndMaxByKey),
20672 /* harmony export */ aI: () => (/* binding */ niceNum),
20673 /* harmony export */ aJ: () => (/* binding */ almostWhole),
20674 /* harmony export */ aK: () => (/* binding */ almostEquals),
20675 /* harmony export */ aL: () => (/* binding */ _decimalPlaces),
20676 /* harmony export */ aM: () => (/* binding */ Ticks),
20677 /* harmony export */ aN: () => (/* binding */ log10),
20678 /* harmony export */ aO: () => (/* binding */ _longestText),
20679 /* harmony export */ aP: () => (/* binding */ _filterBetween),
20680 /* harmony export */ aQ: () => (/* binding */ _lookup),
20681 /* harmony export */ aR: () => (/* binding */ isPatternOrGradient),
20682 /* harmony export */ aS: () => (/* binding */ getHoverColor),
20683 /* harmony export */ aT: () => (/* binding */ clone),
20684 /* harmony export */ aU: () => (/* binding */ _merger),
20685 /* harmony export */ aV: () => (/* binding */ _mergerIf),
20686 /* harmony export */ aW: () => (/* binding */ _deprecated),
20687 /* harmony export */ aX: () => (/* binding */ _splitKey),
20688 /* harmony export */ aY: () => (/* binding */ toFontString),
20689 /* harmony export */ aZ: () => (/* binding */ splineCurve),
20690 /* harmony export */ a_: () => (/* binding */ splineCurveMonotone),
20691 /* harmony export */ aa: () => (/* binding */ _descriptors),
20692 /* harmony export */ ab: () => (/* binding */ mergeIf),
20693 /* harmony export */ ac: () => (/* binding */ uid),
20694 /* harmony export */ ad: () => (/* binding */ debounce),
20695 /* harmony export */ ae: () => (/* binding */ retinaScale),
20696 /* harmony export */ af: () => (/* binding */ clearCanvas),
20697 /* harmony export */ ag: () => (/* binding */ setsEqual),
20698 /* harmony export */ ah: () => (/* binding */ getDatasetClipArea),
20699 /* harmony export */ ai: () => (/* binding */ _elementsEqual),
20700 /* harmony export */ aj: () => (/* binding */ _isClickEvent),
20701 /* harmony export */ ak: () => (/* binding */ _isBetween),
20702 /* harmony export */ al: () => (/* binding */ _normalizeAngle),
20703 /* harmony export */ am: () => (/* binding */ _readValueToProps),
20704 /* harmony export */ an: () => (/* binding */ _updateBezierControlPoints),
20705 /* harmony export */ ao: () => (/* binding */ _computeSegments),
20706 /* harmony export */ ap: () => (/* binding */ _boundSegments),
20707 /* harmony export */ aq: () => (/* binding */ _steppedInterpolation),
20708 /* harmony export */ ar: () => (/* binding */ _bezierInterpolation),
20709 /* harmony export */ as: () => (/* binding */ _pointInLine),
20710 /* harmony export */ at: () => (/* binding */ _steppedLineTo),
20711 /* harmony export */ au: () => (/* binding */ _bezierCurveTo),
20712 /* harmony export */ av: () => (/* binding */ drawPoint),
20713 /* harmony export */ aw: () => (/* binding */ addRoundedRectPath),
20714 /* harmony export */ ax: () => (/* binding */ toTRBL),
20715 /* harmony export */ ay: () => (/* binding */ toTRBLCorners),
20716 /* harmony export */ az: () => (/* binding */ _boundSegment),
20717 /* harmony export */ b: () => (/* binding */ isArray),
20718 /* harmony export */ b0: () => (/* binding */ fontString),
20719 /* harmony export */ b1: () => (/* binding */ toLineHeight),
20720 /* harmony export */ b2: () => (/* binding */ PITAU),
20721 /* harmony export */ b3: () => (/* binding */ INFINITY),
20722 /* harmony export */ b4: () => (/* binding */ RAD_PER_DEG),
20723 /* harmony export */ b5: () => (/* binding */ QUARTER_PI),
20724 /* harmony export */ b6: () => (/* binding */ TWO_THIRDS_PI),
20725 /* harmony export */ b7: () => (/* binding */ _angleDiff),
20726 /* harmony export */ c: () => (/* binding */ color),
20727 /* harmony export */ d: () => (/* binding */ defaults),
20728 /* harmony export */ e: () => (/* binding */ effects),
20729 /* harmony export */ f: () => (/* binding */ resolveObjectKey),
20730 /* harmony export */ g: () => (/* binding */ isNumberFinite),
20731 /* harmony export */ h: () => (/* binding */ defined),
20732 /* harmony export */ i: () => (/* binding */ isObject),
20733 /* harmony export */ j: () => (/* binding */ createContext),
20734 /* harmony export */ k: () => (/* binding */ isNullOrUndef),
20735 /* harmony export */ l: () => (/* binding */ listenArrayEvents),
20736 /* harmony export */ m: () => (/* binding */ toPercentage),
20737 /* harmony export */ n: () => (/* binding */ toDimension),
20738 /* harmony export */ o: () => (/* binding */ formatNumber),
20739 /* harmony export */ p: () => (/* binding */ _angleBetween),
20740 /* harmony export */ q: () => (/* binding */ _getStartAndCountOfVisiblePoints),
20741 /* harmony export */ r: () => (/* binding */ requestAnimFrame),
20742 /* harmony export */ s: () => (/* binding */ sign),
20743 /* harmony export */ t: () => (/* binding */ toRadians),
20744 /* harmony export */ u: () => (/* binding */ unlistenArrayEvents),
20745 /* harmony export */ v: () => (/* binding */ valueOrDefault),
20746 /* harmony export */ w: () => (/* binding */ _scaleRangesChanged),
20747 /* harmony export */ x: () => (/* binding */ isNumber),
20748 /* harmony export */ y: () => (/* binding */ _parseObjectDataRadialScale),
20749 /* harmony export */ z: () => (/* binding */ getRelativePosition)
20750 /* harmony export */ });
20751 /* harmony import */ var _kurkle_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kurkle/color */ "./node_modules/@kurkle/color/dist/color.esm.js");
20752 /*!
20753 * Chart.js v4.5.1
20754 * https://www.chartjs.org
20755 * (c) 2025 Chart.js Contributors
20756 * Released under the MIT License
20757 */
20758
20759
20760 /**
20761 * @namespace Chart.helpers
20762 */ /**
20763 * An empty function that can be used, for example, for optional callback.
20764 */ function noop() {
20765 /* noop */ }
20766 /**
20767 * Returns a unique id, sequentially generated from a global variable.
20768 */ const uid = (()=>{
20769 let id = 0;
20770 return ()=>id++;
20771 })();
20772 /**
20773 * Returns true if `value` is neither null nor undefined, else returns false.
20774 * @param value - The value to test.
20775 * @since 2.7.0
20776 */ function isNullOrUndef(value) {
20777 return value === null || value === undefined;
20778 }
20779 /**
20780 * Returns true if `value` is an array (including typed arrays), else returns false.
20781 * @param value - The value to test.
20782 * @function
20783 */ function isArray(value) {
20784 if (Array.isArray && Array.isArray(value)) {
20785 return true;
20786 }
20787 const type = Object.prototype.toString.call(value);
20788 if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') {
20789 return true;
20790 }
20791 return false;
20792 }
20793 /**
20794 * Returns true if `value` is an object (excluding null), else returns false.
20795 * @param value - The value to test.
20796 * @since 2.7.0
20797 */ function isObject(value) {
20798 return value !== null && Object.prototype.toString.call(value) === '[object Object]';
20799 }
20800 /**
20801 * Returns true if `value` is a finite number, else returns false
20802 * @param value - The value to test.
20803 */ function isNumberFinite(value) {
20804 return (typeof value === 'number' || value instanceof Number) && isFinite(+value);
20805 }
20806 /**
20807 * Returns `value` if finite, else returns `defaultValue`.
20808 * @param value - The value to return if defined.
20809 * @param defaultValue - The value to return if `value` is not finite.
20810 */ function finiteOrDefault(value, defaultValue) {
20811 return isNumberFinite(value) ? value : defaultValue;
20812 }
20813 /**
20814 * Returns `value` if defined, else returns `defaultValue`.
20815 * @param value - The value to return if defined.
20816 * @param defaultValue - The value to return if `value` is undefined.
20817 */ function valueOrDefault(value, defaultValue) {
20818 return typeof value === 'undefined' ? defaultValue : value;
20819 }
20820 const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;
20821 const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;
20822 /**
20823 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
20824 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
20825 * @param fn - The function to call.
20826 * @param args - The arguments with which `fn` should be called.
20827 * @param [thisArg] - The value of `this` provided for the call to `fn`.
20828 */ function callback(fn, args, thisArg) {
20829 if (fn && typeof fn.call === 'function') {
20830 return fn.apply(thisArg, args);
20831 }
20832 }
20833 function each(loopable, fn, thisArg, reverse) {
20834 let i, len, keys;
20835 if (isArray(loopable)) {
20836 len = loopable.length;
20837 if (reverse) {
20838 for(i = len - 1; i >= 0; i--){
20839 fn.call(thisArg, loopable[i], i);
20840 }
20841 } else {
20842 for(i = 0; i < len; i++){
20843 fn.call(thisArg, loopable[i], i);
20844 }
20845 }
20846 } else if (isObject(loopable)) {
20847 keys = Object.keys(loopable);
20848 len = keys.length;
20849 for(i = 0; i < len; i++){
20850 fn.call(thisArg, loopable[keys[i]], keys[i]);
20851 }
20852 }
20853 }
20854 /**
20855 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
20856 * @param a0 - The array to compare
20857 * @param a1 - The array to compare
20858 * @private
20859 */ function _elementsEqual(a0, a1) {
20860 let i, ilen, v0, v1;
20861 if (!a0 || !a1 || a0.length !== a1.length) {
20862 return false;
20863 }
20864 for(i = 0, ilen = a0.length; i < ilen; ++i){
20865 v0 = a0[i];
20866 v1 = a1[i];
20867 if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
20868 return false;
20869 }
20870 }
20871 return true;
20872 }
20873 /**
20874 * Returns a deep copy of `source` without keeping references on objects and arrays.
20875 * @param source - The value to clone.
20876 */ function clone(source) {
20877 if (isArray(source)) {
20878 return source.map(clone);
20879 }
20880 if (isObject(source)) {
20881 const target = Object.create(null);
20882 const keys = Object.keys(source);
20883 const klen = keys.length;
20884 let k = 0;
20885 for(; k < klen; ++k){
20886 target[keys[k]] = clone(source[keys[k]]);
20887 }
20888 return target;
20889 }
20890 return source;
20891 }
20892 function isValidKey(key) {
20893 return [
20894 '__proto__',
20895 'prototype',
20896 'constructor'
20897 ].indexOf(key) === -1;
20898 }
20899 /**
20900 * The default merger when Chart.helpers.merge is called without merger option.
20901 * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
20902 * @private
20903 */ function _merger(key, target, source, options) {
20904 if (!isValidKey(key)) {
20905 return;
20906 }
20907 const tval = target[key];
20908 const sval = source[key];
20909 if (isObject(tval) && isObject(sval)) {
20910 // eslint-disable-next-line @typescript-eslint/no-use-before-define
20911 merge(tval, sval, options);
20912 } else {
20913 target[key] = clone(sval);
20914 }
20915 }
20916 function merge(target, source, options) {
20917 const sources = isArray(source) ? source : [
20918 source
20919 ];
20920 const ilen = sources.length;
20921 if (!isObject(target)) {
20922 return target;
20923 }
20924 options = options || {};
20925 const merger = options.merger || _merger;
20926 let current;
20927 for(let i = 0; i < ilen; ++i){
20928 current = sources[i];
20929 if (!isObject(current)) {
20930 continue;
20931 }
20932 const keys = Object.keys(current);
20933 for(let k = 0, klen = keys.length; k < klen; ++k){
20934 merger(keys[k], target, current, options);
20935 }
20936 }
20937 return target;
20938 }
20939 function mergeIf(target, source) {
20940 // eslint-disable-next-line @typescript-eslint/no-use-before-define
20941 return merge(target, source, {
20942 merger: _mergerIf
20943 });
20944 }
20945 /**
20946 * Merges source[key] in target[key] only if target[key] is undefined.
20947 * @private
20948 */ function _mergerIf(key, target, source) {
20949 if (!isValidKey(key)) {
20950 return;
20951 }
20952 const tval = target[key];
20953 const sval = source[key];
20954 if (isObject(tval) && isObject(sval)) {
20955 mergeIf(tval, sval);
20956 } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
20957 target[key] = clone(sval);
20958 }
20959 }
20960 /**
20961 * @private
20962 */ function _deprecated(scope, value, previous, current) {
20963 if (value !== undefined) {
20964 console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead');
20965 }
20966 }
20967 // resolveObjectKey resolver cache
20968 const keyResolvers = {
20969 // Chart.helpers.core resolveObjectKey should resolve empty key to root object
20970 '': (v)=>v,
20971 // default resolvers
20972 x: (o)=>o.x,
20973 y: (o)=>o.y
20974 };
20975 /**
20976 * @private
20977 */ function _splitKey(key) {
20978 const parts = key.split('.');
20979 const keys = [];
20980 let tmp = '';
20981 for (const part of parts){
20982 tmp += part;
20983 if (tmp.endsWith('\\')) {
20984 tmp = tmp.slice(0, -1) + '.';
20985 } else {
20986 keys.push(tmp);
20987 tmp = '';
20988 }
20989 }
20990 return keys;
20991 }
20992 function _getKeyResolver(key) {
20993 const keys = _splitKey(key);
20994 return (obj)=>{
20995 for (const k of keys){
20996 if (k === '') {
20997 break;
20998 }
20999 obj = obj && obj[k];
21000 }
21001 return obj;
21002 };
21003 }
21004 function resolveObjectKey(obj, key) {
21005 const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
21006 return resolver(obj);
21007 }
21008 /**
21009 * @private
21010 */ function _capitalize(str) {
21011 return str.charAt(0).toUpperCase() + str.slice(1);
21012 }
21013 const defined = (value)=>typeof value !== 'undefined';
21014 const isFunction = (value)=>typeof value === 'function';
21015 // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
21016 const setsEqual = (a, b)=>{
21017 if (a.size !== b.size) {
21018 return false;
21019 }
21020 for (const item of a){
21021 if (!b.has(item)) {
21022 return false;
21023 }
21024 }
21025 return true;
21026 };
21027 /**
21028 * @param e - The event
21029 * @private
21030 */ function _isClickEvent(e) {
21031 return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
21032 }
21033
21034 /**
21035 * @alias Chart.helpers.math
21036 * @namespace
21037 */ const PI = Math.PI;
21038 const TAU = 2 * PI;
21039 const PITAU = TAU + PI;
21040 const INFINITY = Number.POSITIVE_INFINITY;
21041 const RAD_PER_DEG = PI / 180;
21042 const HALF_PI = PI / 2;
21043 const QUARTER_PI = PI / 4;
21044 const TWO_THIRDS_PI = PI * 2 / 3;
21045 const log10 = Math.log10;
21046 const sign = Math.sign;
21047 function almostEquals(x, y, epsilon) {
21048 return Math.abs(x - y) < epsilon;
21049 }
21050 /**
21051 * Implementation of the nice number algorithm used in determining where axis labels will go
21052 */ function niceNum(range) {
21053 const roundedRange = Math.round(range);
21054 range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
21055 const niceRange = Math.pow(10, Math.floor(log10(range)));
21056 const fraction = range / niceRange;
21057 const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
21058 return niceFraction * niceRange;
21059 }
21060 /**
21061 * Returns an array of factors sorted from 1 to sqrt(value)
21062 * @private
21063 */ function _factorize(value) {
21064 const result = [];
21065 const sqrt = Math.sqrt(value);
21066 let i;
21067 for(i = 1; i < sqrt; i++){
21068 if (value % i === 0) {
21069 result.push(i);
21070 result.push(value / i);
21071 }
21072 }
21073 if (sqrt === (sqrt | 0)) {
21074 result.push(sqrt);
21075 }
21076 result.sort((a, b)=>a - b).pop();
21077 return result;
21078 }
21079 /**
21080 * Verifies that attempting to coerce n to string or number won't throw a TypeError.
21081 */ function isNonPrimitive(n) {
21082 return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n);
21083 }
21084 function isNumber(n) {
21085 return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n);
21086 }
21087 function almostWhole(x, epsilon) {
21088 const rounded = Math.round(x);
21089 return rounded - epsilon <= x && rounded + epsilon >= x;
21090 }
21091 /**
21092 * @private
21093 */ function _setMinAndMaxByKey(array, target, property) {
21094 let i, ilen, value;
21095 for(i = 0, ilen = array.length; i < ilen; i++){
21096 value = array[i][property];
21097 if (!isNaN(value)) {
21098 target.min = Math.min(target.min, value);
21099 target.max = Math.max(target.max, value);
21100 }
21101 }
21102 }
21103 function toRadians(degrees) {
21104 return degrees * (PI / 180);
21105 }
21106 function toDegrees(radians) {
21107 return radians * (180 / PI);
21108 }
21109 /**
21110 * Returns the number of decimal places
21111 * i.e. the number of digits after the decimal point, of the value of this Number.
21112 * @param x - A number.
21113 * @returns The number of decimal places.
21114 * @private
21115 */ function _decimalPlaces(x) {
21116 if (!isNumberFinite(x)) {
21117 return;
21118 }
21119 let e = 1;
21120 let p = 0;
21121 while(Math.round(x * e) / e !== x){
21122 e *= 10;
21123 p++;
21124 }
21125 return p;
21126 }
21127 // Gets the angle from vertical upright to the point about a centre.
21128 function getAngleFromPoint(centrePoint, anglePoint) {
21129 const distanceFromXCenter = anglePoint.x - centrePoint.x;
21130 const distanceFromYCenter = anglePoint.y - centrePoint.y;
21131 const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
21132 let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
21133 if (angle < -0.5 * PI) {
21134 angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
21135 }
21136 return {
21137 angle,
21138 distance: radialDistanceFromCenter
21139 };
21140 }
21141 function distanceBetweenPoints(pt1, pt2) {
21142 return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
21143 }
21144 /**
21145 * Shortest distance between angles, in either direction.
21146 * @private
21147 */ function _angleDiff(a, b) {
21148 return (a - b + PITAU) % TAU - PI;
21149 }
21150 /**
21151 * Normalize angle to be between 0 and 2*PI
21152 * @private
21153 */ function _normalizeAngle(a) {
21154 return (a % TAU + TAU) % TAU;
21155 }
21156 /**
21157 * @private
21158 */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
21159 const a = _normalizeAngle(angle);
21160 const s = _normalizeAngle(start);
21161 const e = _normalizeAngle(end);
21162 const angleToStart = _normalizeAngle(s - a);
21163 const angleToEnd = _normalizeAngle(e - a);
21164 const startToAngle = _normalizeAngle(a - s);
21165 const endToAngle = _normalizeAngle(a - e);
21166 return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;
21167 }
21168 /**
21169 * Limit `value` between `min` and `max`
21170 * @param value
21171 * @param min
21172 * @param max
21173 * @private
21174 */ function _limitValue(value, min, max) {
21175 return Math.max(min, Math.min(max, value));
21176 }
21177 /**
21178 * @param {number} value
21179 * @private
21180 */ function _int16Range(value) {
21181 return _limitValue(value, -32768, 32767);
21182 }
21183 /**
21184 * @param value
21185 * @param start
21186 * @param end
21187 * @param [epsilon]
21188 * @private
21189 */ function _isBetween(value, start, end, epsilon = 1e-6) {
21190 return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
21191 }
21192
21193 function _lookup(table, value, cmp) {
21194 cmp = cmp || ((index)=>table[index] < value);
21195 let hi = table.length - 1;
21196 let lo = 0;
21197 let mid;
21198 while(hi - lo > 1){
21199 mid = lo + hi >> 1;
21200 if (cmp(mid)) {
21201 lo = mid;
21202 } else {
21203 hi = mid;
21204 }
21205 }
21206 return {
21207 lo,
21208 hi
21209 };
21210 }
21211 /**
21212 * Binary search
21213 * @param table - the table search. must be sorted!
21214 * @param key - property name for the value in each entry
21215 * @param value - value to find
21216 * @param last - lookup last index
21217 * @private
21218 */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{
21219 const ti = table[index][key];
21220 return ti < value || ti === value && table[index + 1][key] === value;
21221 } : (index)=>table[index][key] < value);
21222 /**
21223 * Reverse binary search
21224 * @param table - the table search. must be sorted!
21225 * @param key - property name for the value in each entry
21226 * @param value - value to find
21227 * @private
21228 */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);
21229 /**
21230 * Return subset of `values` between `min` and `max` inclusive.
21231 * Values are assumed to be in sorted order.
21232 * @param values - sorted array of values
21233 * @param min - min value
21234 * @param max - max value
21235 */ function _filterBetween(values, min, max) {
21236 let start = 0;
21237 let end = values.length;
21238 while(start < end && values[start] < min){
21239 start++;
21240 }
21241 while(end > start && values[end - 1] > max){
21242 end--;
21243 }
21244 return start > 0 || end < values.length ? values.slice(start, end) : values;
21245 }
21246 const arrayEvents = [
21247 'push',
21248 'pop',
21249 'shift',
21250 'splice',
21251 'unshift'
21252 ];
21253 function listenArrayEvents(array, listener) {
21254 if (array._chartjs) {
21255 array._chartjs.listeners.push(listener);
21256 return;
21257 }
21258 Object.defineProperty(array, '_chartjs', {
21259 configurable: true,
21260 enumerable: false,
21261 value: {
21262 listeners: [
21263 listener
21264 ]
21265 }
21266 });
21267 arrayEvents.forEach((key)=>{
21268 const method = '_onData' + _capitalize(key);
21269 const base = array[key];
21270 Object.defineProperty(array, key, {
21271 configurable: true,
21272 enumerable: false,
21273 value (...args) {
21274 const res = base.apply(this, args);
21275 array._chartjs.listeners.forEach((object)=>{
21276 if (typeof object[method] === 'function') {
21277 object[method](...args);
21278 }
21279 });
21280 return res;
21281 }
21282 });
21283 });
21284 }
21285 function unlistenArrayEvents(array, listener) {
21286 const stub = array._chartjs;
21287 if (!stub) {
21288 return;
21289 }
21290 const listeners = stub.listeners;
21291 const index = listeners.indexOf(listener);
21292 if (index !== -1) {
21293 listeners.splice(index, 1);
21294 }
21295 if (listeners.length > 0) {
21296 return;
21297 }
21298 arrayEvents.forEach((key)=>{
21299 delete array[key];
21300 });
21301 delete array._chartjs;
21302 }
21303 /**
21304 * @param items
21305 */ function _arrayUnique(items) {
21306 const set = new Set(items);
21307 if (set.size === items.length) {
21308 return items;
21309 }
21310 return Array.from(set);
21311 }
21312
21313 function fontString(pixelSize, fontStyle, fontFamily) {
21314 return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
21315 }
21316 /**
21317 * Request animation polyfill
21318 */ const requestAnimFrame = function() {
21319 if (typeof window === 'undefined') {
21320 return function(callback) {
21321 return callback();
21322 };
21323 }
21324 return window.requestAnimationFrame;
21325 }();
21326 /**
21327 * Throttles calling `fn` once per animation frame
21328 * Latest arguments are used on the actual call
21329 */ function throttled(fn, thisArg) {
21330 let argsToUse = [];
21331 let ticking = false;
21332 return function(...args) {
21333 // Save the args for use later
21334 argsToUse = args;
21335 if (!ticking) {
21336 ticking = true;
21337 requestAnimFrame.call(window, ()=>{
21338 ticking = false;
21339 fn.apply(thisArg, argsToUse);
21340 });
21341 }
21342 };
21343 }
21344 /**
21345 * Debounces calling `fn` for `delay` ms
21346 */ function debounce(fn, delay) {
21347 let timeout;
21348 return function(...args) {
21349 if (delay) {
21350 clearTimeout(timeout);
21351 timeout = setTimeout(fn, delay, args);
21352 } else {
21353 fn.apply(this, args);
21354 }
21355 return delay;
21356 };
21357 }
21358 /**
21359 * Converts 'start' to 'left', 'end' to 'right' and others to 'center'
21360 * @private
21361 */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
21362 /**
21363 * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`
21364 * @private
21365 */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
21366 /**
21367 * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`
21368 * @private
21369 */ const _textX = (align, left, right, rtl)=>{
21370 const check = rtl ? 'left' : 'right';
21371 return align === check ? right : align === 'center' ? (left + right) / 2 : left;
21372 };
21373 /**
21374 * Return start and count of visible points.
21375 * @private
21376 */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
21377 const pointCount = points.length;
21378 let start = 0;
21379 let count = pointCount;
21380 if (meta._sorted) {
21381 const { iScale , vScale , _parsed } = meta;
21382 const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null;
21383 const axis = iScale.axis;
21384 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
21385 if (minDefined) {
21386 start = Math.min(// @ts-expect-error Need to type _parsed
21387 _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey
21388 animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo);
21389 if (spanGaps) {
21390 const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21391 start -= Math.max(0, distanceToDefinedLo);
21392 }
21393 start = _limitValue(start, 0, pointCount - 1);
21394 }
21395 if (maxDefined) {
21396 let end = Math.max(// @ts-expect-error Need to type _parsed
21397 _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey
21398 animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1);
21399 if (spanGaps) {
21400 const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21401 end += Math.max(0, distanceToDefinedHi);
21402 }
21403 count = _limitValue(end, start, pointCount) - start;
21404 } else {
21405 count = pointCount - start;
21406 }
21407 }
21408 return {
21409 start,
21410 count
21411 };
21412 }
21413 /**
21414 * Checks if the scale ranges have changed.
21415 * @param {object} meta - dataset meta.
21416 * @returns {boolean}
21417 * @private
21418 */ function _scaleRangesChanged(meta) {
21419 const { xScale , yScale , _scaleRanges } = meta;
21420 const newRanges = {
21421 xmin: xScale.min,
21422 xmax: xScale.max,
21423 ymin: yScale.min,
21424 ymax: yScale.max
21425 };
21426 if (!_scaleRanges) {
21427 meta._scaleRanges = newRanges;
21428 return true;
21429 }
21430 const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max;
21431 Object.assign(_scaleRanges, newRanges);
21432 return changed;
21433 }
21434
21435 const atEdge = (t)=>t === 0 || t === 1;
21436 const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
21437 const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
21438 /**
21439 * Easing functions adapted from Robert Penner's easing equations.
21440 * @namespace Chart.helpers.easing.effects
21441 * @see http://www.robertpenner.com/easing/
21442 */ const effects = {
21443 linear: (t)=>t,
21444 easeInQuad: (t)=>t * t,
21445 easeOutQuad: (t)=>-t * (t - 2),
21446 easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),
21447 easeInCubic: (t)=>t * t * t,
21448 easeOutCubic: (t)=>(t -= 1) * t * t + 1,
21449 easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),
21450 easeInQuart: (t)=>t * t * t * t,
21451 easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),
21452 easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),
21453 easeInQuint: (t)=>t * t * t * t * t,
21454 easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,
21455 easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),
21456 easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,
21457 easeOutSine: (t)=>Math.sin(t * HALF_PI),
21458 easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),
21459 easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
21460 easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,
21461 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),
21462 easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),
21463 easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),
21464 easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
21465 easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
21466 easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
21467 easeInOutElastic (t) {
21468 const s = 0.1125;
21469 const p = 0.45;
21470 return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
21471 },
21472 easeInBack (t) {
21473 const s = 1.70158;
21474 return t * t * ((s + 1) * t - s);
21475 },
21476 easeOutBack (t) {
21477 const s = 1.70158;
21478 return (t -= 1) * t * ((s + 1) * t + s) + 1;
21479 },
21480 easeInOutBack (t) {
21481 let s = 1.70158;
21482 if ((t /= 0.5) < 1) {
21483 return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
21484 }
21485 return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
21486 },
21487 easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),
21488 easeOutBounce (t) {
21489 const m = 7.5625;
21490 const d = 2.75;
21491 if (t < 1 / d) {
21492 return m * t * t;
21493 }
21494 if (t < 2 / d) {
21495 return m * (t -= 1.5 / d) * t + 0.75;
21496 }
21497 if (t < 2.5 / d) {
21498 return m * (t -= 2.25 / d) * t + 0.9375;
21499 }
21500 return m * (t -= 2.625 / d) * t + 0.984375;
21501 },
21502 easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5
21503 };
21504
21505 function isPatternOrGradient(value) {
21506 if (value && typeof value === 'object') {
21507 const type = value.toString();
21508 return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
21509 }
21510 return false;
21511 }
21512 function color(value) {
21513 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value);
21514 }
21515 function getHoverColor(value) {
21516 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value).saturate(0.5).darken(0.1).hexString();
21517 }
21518
21519 const numbers = [
21520 'x',
21521 'y',
21522 'borderWidth',
21523 'radius',
21524 'tension'
21525 ];
21526 const colors = [
21527 'color',
21528 'borderColor',
21529 'backgroundColor'
21530 ];
21531 function applyAnimationsDefaults(defaults) {
21532 defaults.set('animation', {
21533 delay: undefined,
21534 duration: 1000,
21535 easing: 'easeOutQuart',
21536 fn: undefined,
21537 from: undefined,
21538 loop: undefined,
21539 to: undefined,
21540 type: undefined
21541 });
21542 defaults.describe('animation', {
21543 _fallback: false,
21544 _indexable: false,
21545 _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'
21546 });
21547 defaults.set('animations', {
21548 colors: {
21549 type: 'color',
21550 properties: colors
21551 },
21552 numbers: {
21553 type: 'number',
21554 properties: numbers
21555 }
21556 });
21557 defaults.describe('animations', {
21558 _fallback: 'animation'
21559 });
21560 defaults.set('transitions', {
21561 active: {
21562 animation: {
21563 duration: 400
21564 }
21565 },
21566 resize: {
21567 animation: {
21568 duration: 0
21569 }
21570 },
21571 show: {
21572 animations: {
21573 colors: {
21574 from: 'transparent'
21575 },
21576 visible: {
21577 type: 'boolean',
21578 duration: 0
21579 }
21580 }
21581 },
21582 hide: {
21583 animations: {
21584 colors: {
21585 to: 'transparent'
21586 },
21587 visible: {
21588 type: 'boolean',
21589 easing: 'linear',
21590 fn: (v)=>v | 0
21591 }
21592 }
21593 }
21594 });
21595 }
21596
21597 function applyLayoutsDefaults(defaults) {
21598 defaults.set('layout', {
21599 autoPadding: true,
21600 padding: {
21601 top: 0,
21602 right: 0,
21603 bottom: 0,
21604 left: 0
21605 }
21606 });
21607 }
21608
21609 const intlCache = new Map();
21610 function getNumberFormat(locale, options) {
21611 options = options || {};
21612 const cacheKey = locale + JSON.stringify(options);
21613 let formatter = intlCache.get(cacheKey);
21614 if (!formatter) {
21615 formatter = new Intl.NumberFormat(locale, options);
21616 intlCache.set(cacheKey, formatter);
21617 }
21618 return formatter;
21619 }
21620 function formatNumber(num, locale, options) {
21621 return getNumberFormat(locale, options).format(num);
21622 }
21623
21624 const formatters = {
21625 values (value) {
21626 return isArray(value) ? value : '' + value;
21627 },
21628 numeric (tickValue, index, ticks) {
21629 if (tickValue === 0) {
21630 return '0';
21631 }
21632 const locale = this.chart.options.locale;
21633 let notation;
21634 let delta = tickValue;
21635 if (ticks.length > 1) {
21636 const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
21637 if (maxTick < 1e-4 || maxTick > 1e+15) {
21638 notation = 'scientific';
21639 }
21640 delta = calculateDelta(tickValue, ticks);
21641 }
21642 const logDelta = log10(Math.abs(delta));
21643 const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
21644 const options = {
21645 notation,
21646 minimumFractionDigits: numDecimal,
21647 maximumFractionDigits: numDecimal
21648 };
21649 Object.assign(options, this.options.ticks.format);
21650 return formatNumber(tickValue, locale, options);
21651 },
21652 logarithmic (tickValue, index, ticks) {
21653 if (tickValue === 0) {
21654 return '0';
21655 }
21656 const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
21657 if ([
21658 1,
21659 2,
21660 3,
21661 5,
21662 10,
21663 15
21664 ].includes(remain) || index > 0.8 * ticks.length) {
21665 return formatters.numeric.call(this, tickValue, index, ticks);
21666 }
21667 return '';
21668 }
21669 };
21670 function calculateDelta(tickValue, ticks) {
21671 let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
21672 if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
21673 delta = tickValue - Math.floor(tickValue);
21674 }
21675 return delta;
21676 }
21677 var Ticks = {
21678 formatters
21679 };
21680
21681 function applyScaleDefaults(defaults) {
21682 defaults.set('scale', {
21683 display: true,
21684 offset: false,
21685 reverse: false,
21686 beginAtZero: false,
21687 bounds: 'ticks',
21688 clip: true,
21689 grace: 0,
21690 grid: {
21691 display: true,
21692 lineWidth: 1,
21693 drawOnChartArea: true,
21694 drawTicks: true,
21695 tickLength: 8,
21696 tickWidth: (_ctx, options)=>options.lineWidth,
21697 tickColor: (_ctx, options)=>options.color,
21698 offset: false
21699 },
21700 border: {
21701 display: true,
21702 dash: [],
21703 dashOffset: 0.0,
21704 width: 1
21705 },
21706 title: {
21707 display: false,
21708 text: '',
21709 padding: {
21710 top: 4,
21711 bottom: 4
21712 }
21713 },
21714 ticks: {
21715 minRotation: 0,
21716 maxRotation: 50,
21717 mirror: false,
21718 textStrokeWidth: 0,
21719 textStrokeColor: '',
21720 padding: 3,
21721 display: true,
21722 autoSkip: true,
21723 autoSkipPadding: 3,
21724 labelOffset: 0,
21725 callback: Ticks.formatters.values,
21726 minor: {},
21727 major: {},
21728 align: 'center',
21729 crossAlign: 'near',
21730 showLabelBackdrop: false,
21731 backdropColor: 'rgba(255, 255, 255, 0.75)',
21732 backdropPadding: 2
21733 }
21734 });
21735 defaults.route('scale.ticks', 'color', '', 'color');
21736 defaults.route('scale.grid', 'color', '', 'borderColor');
21737 defaults.route('scale.border', 'color', '', 'borderColor');
21738 defaults.route('scale.title', 'color', '', 'color');
21739 defaults.describe('scale', {
21740 _fallback: false,
21741 _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
21742 _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'
21743 });
21744 defaults.describe('scales', {
21745 _fallback: 'scale'
21746 });
21747 defaults.describe('scale.ticks', {
21748 _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',
21749 _indexable: (name)=>name !== 'backdropPadding'
21750 });
21751 }
21752
21753 const overrides = Object.create(null);
21754 const descriptors = Object.create(null);
21755 function getScope$1(node, key) {
21756 if (!key) {
21757 return node;
21758 }
21759 const keys = key.split('.');
21760 for(let i = 0, n = keys.length; i < n; ++i){
21761 const k = keys[i];
21762 node = node[k] || (node[k] = Object.create(null));
21763 }
21764 return node;
21765 }
21766 function set(root, scope, values) {
21767 if (typeof scope === 'string') {
21768 return merge(getScope$1(root, scope), values);
21769 }
21770 return merge(getScope$1(root, ''), scope);
21771 }
21772 class Defaults {
21773 constructor(_descriptors, _appliers){
21774 this.animation = undefined;
21775 this.backgroundColor = 'rgba(0,0,0,0.1)';
21776 this.borderColor = 'rgba(0,0,0,0.1)';
21777 this.color = '#666';
21778 this.datasets = {};
21779 this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio();
21780 this.elements = {};
21781 this.events = [
21782 'mousemove',
21783 'mouseout',
21784 'click',
21785 'touchstart',
21786 'touchmove'
21787 ];
21788 this.font = {
21789 family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
21790 size: 12,
21791 style: 'normal',
21792 lineHeight: 1.2,
21793 weight: null
21794 };
21795 this.hover = {};
21796 this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor);
21797 this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor);
21798 this.hoverColor = (ctx, options)=>getHoverColor(options.color);
21799 this.indexAxis = 'x';
21800 this.interaction = {
21801 mode: 'nearest',
21802 intersect: true,
21803 includeInvisible: false
21804 };
21805 this.maintainAspectRatio = true;
21806 this.onHover = null;
21807 this.onClick = null;
21808 this.parsing = true;
21809 this.plugins = {};
21810 this.responsive = true;
21811 this.scale = undefined;
21812 this.scales = {};
21813 this.showLine = true;
21814 this.drawActiveElementsOnTop = true;
21815 this.describe(_descriptors);
21816 this.apply(_appliers);
21817 }
21818 set(scope, values) {
21819 return set(this, scope, values);
21820 }
21821 get(scope) {
21822 return getScope$1(this, scope);
21823 }
21824 describe(scope, values) {
21825 return set(descriptors, scope, values);
21826 }
21827 override(scope, values) {
21828 return set(overrides, scope, values);
21829 }
21830 route(scope, name, targetScope, targetName) {
21831 const scopeObject = getScope$1(this, scope);
21832 const targetScopeObject = getScope$1(this, targetScope);
21833 const privateName = '_' + name;
21834 Object.defineProperties(scopeObject, {
21835 [privateName]: {
21836 value: scopeObject[name],
21837 writable: true
21838 },
21839 [name]: {
21840 enumerable: true,
21841 get () {
21842 const local = this[privateName];
21843 const target = targetScopeObject[targetName];
21844 if (isObject(local)) {
21845 return Object.assign({}, target, local);
21846 }
21847 return valueOrDefault(local, target);
21848 },
21849 set (value) {
21850 this[privateName] = value;
21851 }
21852 }
21853 });
21854 }
21855 apply(appliers) {
21856 appliers.forEach((apply)=>apply(this));
21857 }
21858 }
21859 var defaults = /* #__PURE__ */ new Defaults({
21860 _scriptable: (name)=>!name.startsWith('on'),
21861 _indexable: (name)=>name !== 'events',
21862 hover: {
21863 _fallback: 'interaction'
21864 },
21865 interaction: {
21866 _scriptable: false,
21867 _indexable: false
21868 }
21869 }, [
21870 applyAnimationsDefaults,
21871 applyLayoutsDefaults,
21872 applyScaleDefaults
21873 ]);
21874
21875 /**
21876 * Converts the given font object into a CSS font string.
21877 * @param font - A font object.
21878 * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
21879 * @private
21880 */ function toFontString(font) {
21881 if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
21882 return null;
21883 }
21884 return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family;
21885 }
21886 /**
21887 * @private
21888 */ function _measureText(ctx, data, gc, longest, string) {
21889 let textWidth = data[string];
21890 if (!textWidth) {
21891 textWidth = data[string] = ctx.measureText(string).width;
21892 gc.push(string);
21893 }
21894 if (textWidth > longest) {
21895 longest = textWidth;
21896 }
21897 return longest;
21898 }
21899 /**
21900 * @private
21901 */ // eslint-disable-next-line complexity
21902 function _longestText(ctx, font, arrayOfThings, cache) {
21903 cache = cache || {};
21904 let data = cache.data = cache.data || {};
21905 let gc = cache.garbageCollect = cache.garbageCollect || [];
21906 if (cache.font !== font) {
21907 data = cache.data = {};
21908 gc = cache.garbageCollect = [];
21909 cache.font = font;
21910 }
21911 ctx.save();
21912 ctx.font = font;
21913 let longest = 0;
21914 const ilen = arrayOfThings.length;
21915 let i, j, jlen, thing, nestedThing;
21916 for(i = 0; i < ilen; i++){
21917 thing = arrayOfThings[i];
21918 // Undefined strings and arrays should not be measured
21919 if (thing !== undefined && thing !== null && !isArray(thing)) {
21920 longest = _measureText(ctx, data, gc, longest, thing);
21921 } else if (isArray(thing)) {
21922 // if it is an array lets measure each element
21923 // to do maybe simplify this function a bit so we can do this more recursively?
21924 for(j = 0, jlen = thing.length; j < jlen; j++){
21925 nestedThing = thing[j];
21926 // Undefined strings and arrays should not be measured
21927 if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
21928 longest = _measureText(ctx, data, gc, longest, nestedThing);
21929 }
21930 }
21931 }
21932 }
21933 ctx.restore();
21934 const gcLen = gc.length / 2;
21935 if (gcLen > arrayOfThings.length) {
21936 for(i = 0; i < gcLen; i++){
21937 delete data[gc[i]];
21938 }
21939 gc.splice(0, gcLen);
21940 }
21941 return longest;
21942 }
21943 /**
21944 * Returns the aligned pixel value to avoid anti-aliasing blur
21945 * @param chart - The chart instance.
21946 * @param pixel - A pixel value.
21947 * @param width - The width of the element.
21948 * @returns The aligned pixel value.
21949 * @private
21950 */ function _alignPixel(chart, pixel, width) {
21951 const devicePixelRatio = chart.currentDevicePixelRatio;
21952 const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
21953 return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
21954 }
21955 /**
21956 * Clears the entire canvas.
21957 */ function clearCanvas(canvas, ctx) {
21958 if (!ctx && !canvas) {
21959 return;
21960 }
21961 ctx = ctx || canvas.getContext('2d');
21962 ctx.save();
21963 // canvas.width and canvas.height do not consider the canvas transform,
21964 // while clearRect does
21965 ctx.resetTransform();
21966 ctx.clearRect(0, 0, canvas.width, canvas.height);
21967 ctx.restore();
21968 }
21969 function drawPoint(ctx, options, x, y) {
21970 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21971 drawPointLegend(ctx, options, x, y, null);
21972 }
21973 // eslint-disable-next-line complexity
21974 function drawPointLegend(ctx, options, x, y, w) {
21975 let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;
21976 const style = options.pointStyle;
21977 const rotation = options.rotation;
21978 const radius = options.radius;
21979 let rad = (rotation || 0) * RAD_PER_DEG;
21980 if (style && typeof style === 'object') {
21981 type = style.toString();
21982 if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
21983 ctx.save();
21984 ctx.translate(x, y);
21985 ctx.rotate(rad);
21986 ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
21987 ctx.restore();
21988 return;
21989 }
21990 }
21991 if (isNaN(radius) || radius <= 0) {
21992 return;
21993 }
21994 ctx.beginPath();
21995 switch(style){
21996 // Default includes circle
21997 default:
21998 if (w) {
21999 ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);
22000 } else {
22001 ctx.arc(x, y, radius, 0, TAU);
22002 }
22003 ctx.closePath();
22004 break;
22005 case 'triangle':
22006 width = w ? w / 2 : radius;
22007 ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22008 rad += TWO_THIRDS_PI;
22009 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22010 rad += TWO_THIRDS_PI;
22011 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22012 ctx.closePath();
22013 break;
22014 case 'rectRounded':
22015 // NOTE: the rounded rect implementation changed to use `arc` instead of
22016 // `quadraticCurveTo` since it generates better results when rect is
22017 // almost a circle. 0.516 (instead of 0.5) produces results with visually
22018 // closer proportion to the previous impl and it is inscribed in the
22019 // circle with `radius`. For more details, see the following PRs:
22020 // https://github.com/chartjs/Chart.js/issues/5597
22021 // https://github.com/chartjs/Chart.js/issues/5858
22022 cornerRadius = radius * 0.516;
22023 size = radius - cornerRadius;
22024 xOffset = Math.cos(rad + QUARTER_PI) * size;
22025 xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22026 yOffset = Math.sin(rad + QUARTER_PI) * size;
22027 yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22028 ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
22029 ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);
22030 ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);
22031 ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
22032 ctx.closePath();
22033 break;
22034 case 'rect':
22035 if (!rotation) {
22036 size = Math.SQRT1_2 * radius;
22037 width = w ? w / 2 : size;
22038 ctx.rect(x - width, y - size, 2 * width, 2 * size);
22039 break;
22040 }
22041 rad += QUARTER_PI;
22042 /* falls through */ case 'rectRot':
22043 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22044 xOffset = Math.cos(rad) * radius;
22045 yOffset = Math.sin(rad) * radius;
22046 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22047 ctx.moveTo(x - xOffsetW, y - yOffset);
22048 ctx.lineTo(x + yOffsetW, y - xOffset);
22049 ctx.lineTo(x + xOffsetW, y + yOffset);
22050 ctx.lineTo(x - yOffsetW, y + xOffset);
22051 ctx.closePath();
22052 break;
22053 case 'crossRot':
22054 rad += QUARTER_PI;
22055 /* falls through */ case 'cross':
22056 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22057 xOffset = Math.cos(rad) * radius;
22058 yOffset = Math.sin(rad) * radius;
22059 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22060 ctx.moveTo(x - xOffsetW, y - yOffset);
22061 ctx.lineTo(x + xOffsetW, y + yOffset);
22062 ctx.moveTo(x + yOffsetW, y - xOffset);
22063 ctx.lineTo(x - yOffsetW, y + xOffset);
22064 break;
22065 case 'star':
22066 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22067 xOffset = Math.cos(rad) * radius;
22068 yOffset = Math.sin(rad) * radius;
22069 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22070 ctx.moveTo(x - xOffsetW, y - yOffset);
22071 ctx.lineTo(x + xOffsetW, y + yOffset);
22072 ctx.moveTo(x + yOffsetW, y - xOffset);
22073 ctx.lineTo(x - yOffsetW, y + xOffset);
22074 rad += QUARTER_PI;
22075 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22076 xOffset = Math.cos(rad) * radius;
22077 yOffset = Math.sin(rad) * radius;
22078 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22079 ctx.moveTo(x - xOffsetW, y - yOffset);
22080 ctx.lineTo(x + xOffsetW, y + yOffset);
22081 ctx.moveTo(x + yOffsetW, y - xOffset);
22082 ctx.lineTo(x - yOffsetW, y + xOffset);
22083 break;
22084 case 'line':
22085 xOffset = w ? w / 2 : Math.cos(rad) * radius;
22086 yOffset = Math.sin(rad) * radius;
22087 ctx.moveTo(x - xOffset, y - yOffset);
22088 ctx.lineTo(x + xOffset, y + yOffset);
22089 break;
22090 case 'dash':
22091 ctx.moveTo(x, y);
22092 ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);
22093 break;
22094 case false:
22095 ctx.closePath();
22096 break;
22097 }
22098 ctx.fill();
22099 if (options.borderWidth > 0) {
22100 ctx.stroke();
22101 }
22102 }
22103 /**
22104 * Returns true if the point is inside the rectangle
22105 * @param point - The point to test
22106 * @param area - The rectangle
22107 * @param margin - allowed margin
22108 * @private
22109 */ function _isPointInArea(point, area, margin) {
22110 margin = margin || 0.5; // margin - default is to match rounded decimals
22111 return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;
22112 }
22113 function clipArea(ctx, area) {
22114 ctx.save();
22115 ctx.beginPath();
22116 ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
22117 ctx.clip();
22118 }
22119 function unclipArea(ctx) {
22120 ctx.restore();
22121 }
22122 /**
22123 * @private
22124 */ function _steppedLineTo(ctx, previous, target, flip, mode) {
22125 if (!previous) {
22126 return ctx.lineTo(target.x, target.y);
22127 }
22128 if (mode === 'middle') {
22129 const midpoint = (previous.x + target.x) / 2.0;
22130 ctx.lineTo(midpoint, previous.y);
22131 ctx.lineTo(midpoint, target.y);
22132 } else if (mode === 'after' !== !!flip) {
22133 ctx.lineTo(previous.x, target.y);
22134 } else {
22135 ctx.lineTo(target.x, previous.y);
22136 }
22137 ctx.lineTo(target.x, target.y);
22138 }
22139 /**
22140 * @private
22141 */ function _bezierCurveTo(ctx, previous, target, flip) {
22142 if (!previous) {
22143 return ctx.lineTo(target.x, target.y);
22144 }
22145 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);
22146 }
22147 function setRenderOpts(ctx, opts) {
22148 if (opts.translation) {
22149 ctx.translate(opts.translation[0], opts.translation[1]);
22150 }
22151 if (!isNullOrUndef(opts.rotation)) {
22152 ctx.rotate(opts.rotation);
22153 }
22154 if (opts.color) {
22155 ctx.fillStyle = opts.color;
22156 }
22157 if (opts.textAlign) {
22158 ctx.textAlign = opts.textAlign;
22159 }
22160 if (opts.textBaseline) {
22161 ctx.textBaseline = opts.textBaseline;
22162 }
22163 }
22164 function decorateText(ctx, x, y, line, opts) {
22165 if (opts.strikethrough || opts.underline) {
22166 /**
22167 * Now that IE11 support has been dropped, we can use more
22168 * of the TextMetrics object. The actual bounding boxes
22169 * are unflagged in Chrome, Firefox, Edge, and Safari so they
22170 * can be safely used.
22171 * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
22172 */ const metrics = ctx.measureText(line);
22173 const left = x - metrics.actualBoundingBoxLeft;
22174 const right = x + metrics.actualBoundingBoxRight;
22175 const top = y - metrics.actualBoundingBoxAscent;
22176 const bottom = y + metrics.actualBoundingBoxDescent;
22177 const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
22178 ctx.strokeStyle = ctx.fillStyle;
22179 ctx.beginPath();
22180 ctx.lineWidth = opts.decorationWidth || 2;
22181 ctx.moveTo(left, yDecoration);
22182 ctx.lineTo(right, yDecoration);
22183 ctx.stroke();
22184 }
22185 }
22186 function drawBackdrop(ctx, opts) {
22187 const oldColor = ctx.fillStyle;
22188 ctx.fillStyle = opts.color;
22189 ctx.fillRect(opts.left, opts.top, opts.width, opts.height);
22190 ctx.fillStyle = oldColor;
22191 }
22192 /**
22193 * Render text onto the canvas
22194 */ function renderText(ctx, text, x, y, font, opts = {}) {
22195 const lines = isArray(text) ? text : [
22196 text
22197 ];
22198 const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
22199 let i, line;
22200 ctx.save();
22201 ctx.font = font.string;
22202 setRenderOpts(ctx, opts);
22203 for(i = 0; i < lines.length; ++i){
22204 line = lines[i];
22205 if (opts.backdrop) {
22206 drawBackdrop(ctx, opts.backdrop);
22207 }
22208 if (stroke) {
22209 if (opts.strokeColor) {
22210 ctx.strokeStyle = opts.strokeColor;
22211 }
22212 if (!isNullOrUndef(opts.strokeWidth)) {
22213 ctx.lineWidth = opts.strokeWidth;
22214 }
22215 ctx.strokeText(line, x, y, opts.maxWidth);
22216 }
22217 ctx.fillText(line, x, y, opts.maxWidth);
22218 decorateText(ctx, x, y, line, opts);
22219 y += Number(font.lineHeight);
22220 }
22221 ctx.restore();
22222 }
22223 /**
22224 * Add a path of a rectangle with rounded corners to the current sub-path
22225 * @param ctx - Context
22226 * @param rect - Bounding rect
22227 */ function addRoundedRectPath(ctx, rect) {
22228 const { x , y , w , h , radius } = rect;
22229 // top left arc
22230 ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
22231 // line from top left to bottom left
22232 ctx.lineTo(x, y + h - radius.bottomLeft);
22233 // bottom left arc
22234 ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
22235 // line from bottom left to bottom right
22236 ctx.lineTo(x + w - radius.bottomRight, y + h);
22237 // bottom right arc
22238 ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
22239 // line from bottom right to top right
22240 ctx.lineTo(x + w, y + radius.topRight);
22241 // top right arc
22242 ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
22243 // line from top right to top left
22244 ctx.lineTo(x + radius.topLeft, y);
22245 }
22246
22247 const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
22248 const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
22249 /**
22250 * @alias Chart.helpers.options
22251 * @namespace
22252 */ /**
22253 * Converts the given line height `value` in pixels for a specific font `size`.
22254 * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
22255 * @param size - The font size (in pixels) used to resolve relative `value`.
22256 * @returns The effective line height in pixels (size * 1.2 if value is invalid).
22257 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
22258 * @since 2.7.0
22259 */ function toLineHeight(value, size) {
22260 const matches = ('' + value).match(LINE_HEIGHT);
22261 if (!matches || matches[1] === 'normal') {
22262 return size * 1.2;
22263 }
22264 value = +matches[2];
22265 switch(matches[3]){
22266 case 'px':
22267 return value;
22268 case '%':
22269 value /= 100;
22270 break;
22271 }
22272 return size * value;
22273 }
22274 const numberOrZero = (v)=>+v || 0;
22275 function _readValueToProps(value, props) {
22276 const ret = {};
22277 const objProps = isObject(props);
22278 const keys = objProps ? Object.keys(props) : props;
22279 const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value;
22280 for (const prop of keys){
22281 ret[prop] = numberOrZero(read(prop));
22282 }
22283 return ret;
22284 }
22285 /**
22286 * Converts the given value into a TRBL object.
22287 * @param value - If a number, set the value to all TRBL component,
22288 * else, if an object, use defined properties and sets undefined ones to 0.
22289 * x / y are shorthands for same value for left/right and top/bottom.
22290 * @returns The padding values (top, right, bottom, left)
22291 * @since 3.0.0
22292 */ function toTRBL(value) {
22293 return _readValueToProps(value, {
22294 top: 'y',
22295 right: 'x',
22296 bottom: 'y',
22297 left: 'x'
22298 });
22299 }
22300 /**
22301 * Converts the given value into a TRBL corners object (similar with css border-radius).
22302 * @param value - If a number, set the value to all TRBL corner components,
22303 * else, if an object, use defined properties and sets undefined ones to 0.
22304 * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)
22305 * @since 3.0.0
22306 */ function toTRBLCorners(value) {
22307 return _readValueToProps(value, [
22308 'topLeft',
22309 'topRight',
22310 'bottomLeft',
22311 'bottomRight'
22312 ]);
22313 }
22314 /**
22315 * Converts the given value into a padding object with pre-computed width/height.
22316 * @param value - If a number, set the value to all TRBL component,
22317 * else, if an object, use defined properties and sets undefined ones to 0.
22318 * x / y are shorthands for same value for left/right and top/bottom.
22319 * @returns The padding values (top, right, bottom, left, width, height)
22320 * @since 2.7.0
22321 */ function toPadding(value) {
22322 const obj = toTRBL(value);
22323 obj.width = obj.left + obj.right;
22324 obj.height = obj.top + obj.bottom;
22325 return obj;
22326 }
22327 /**
22328 * Parses font options and returns the font object.
22329 * @param options - A object that contains font options to be parsed.
22330 * @param fallback - A object that contains fallback font options.
22331 * @return The font object.
22332 * @private
22333 */ function toFont(options, fallback) {
22334 options = options || {};
22335 fallback = fallback || defaults.font;
22336 let size = valueOrDefault(options.size, fallback.size);
22337 if (typeof size === 'string') {
22338 size = parseInt(size, 10);
22339 }
22340 let style = valueOrDefault(options.style, fallback.style);
22341 if (style && !('' + style).match(FONT_STYLE)) {
22342 console.warn('Invalid font style specified: "' + style + '"');
22343 style = undefined;
22344 }
22345 const font = {
22346 family: valueOrDefault(options.family, fallback.family),
22347 lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
22348 size,
22349 style,
22350 weight: valueOrDefault(options.weight, fallback.weight),
22351 string: ''
22352 };
22353 font.string = toFontString(font);
22354 return font;
22355 }
22356 /**
22357 * Evaluates the given `inputs` sequentially and returns the first defined value.
22358 * @param inputs - An array of values, falling back to the last value.
22359 * @param context - If defined and the current value is a function, the value
22360 * is called with `context` as first argument and the result becomes the new input.
22361 * @param index - If defined and the current value is an array, the value
22362 * at `index` become the new input.
22363 * @param info - object to return information about resolution in
22364 * @param info.cacheable - Will be set to `false` if option is not cacheable.
22365 * @since 2.7.0
22366 */ function resolve(inputs, context, index, info) {
22367 let cacheable = true;
22368 let i, ilen, value;
22369 for(i = 0, ilen = inputs.length; i < ilen; ++i){
22370 value = inputs[i];
22371 if (value === undefined) {
22372 continue;
22373 }
22374 if (context !== undefined && typeof value === 'function') {
22375 value = value(context);
22376 cacheable = false;
22377 }
22378 if (index !== undefined && isArray(value)) {
22379 value = value[index % value.length];
22380 cacheable = false;
22381 }
22382 if (value !== undefined) {
22383 if (info && !cacheable) {
22384 info.cacheable = false;
22385 }
22386 return value;
22387 }
22388 }
22389 }
22390 /**
22391 * @param minmax
22392 * @param grace
22393 * @param beginAtZero
22394 * @private
22395 */ function _addGrace(minmax, grace, beginAtZero) {
22396 const { min , max } = minmax;
22397 const change = toDimension(grace, (max - min) / 2);
22398 const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;
22399 return {
22400 min: keepZero(min, -Math.abs(change)),
22401 max: keepZero(max, change)
22402 };
22403 }
22404 function createContext(parentContext, context) {
22405 return Object.assign(Object.create(parentContext), context);
22406 }
22407
22408 /**
22409 * Creates a Proxy for resolving raw values for options.
22410 * @param scopes - The option scopes to look for values, in resolution order
22411 * @param prefixes - The prefixes for values, in resolution order.
22412 * @param rootScopes - The root option scopes
22413 * @param fallback - Parent scopes fallback
22414 * @param getTarget - callback for getting the target for changed values
22415 * @returns Proxy
22416 * @private
22417 */ function _createResolver(scopes, prefixes = [
22418 ''
22419 ], rootScopes, fallback, getTarget = ()=>scopes[0]) {
22420 const finalRootScopes = rootScopes || scopes;
22421 if (typeof fallback === 'undefined') {
22422 fallback = _resolve('_fallback', scopes);
22423 }
22424 const cache = {
22425 [Symbol.toStringTag]: 'Object',
22426 _cacheable: true,
22427 _scopes: scopes,
22428 _rootScopes: finalRootScopes,
22429 _fallback: fallback,
22430 _getTarget: getTarget,
22431 override: (scope)=>_createResolver([
22432 scope,
22433 ...scopes
22434 ], prefixes, finalRootScopes, fallback)
22435 };
22436 return new Proxy(cache, {
22437 /**
22438 * A trap for the delete operator.
22439 */ deleteProperty (target, prop) {
22440 delete target[prop]; // remove from cache
22441 delete target._keys; // remove cached keys
22442 delete scopes[0][prop]; // remove from top level scope
22443 return true;
22444 },
22445 /**
22446 * A trap for getting property values.
22447 */ get (target, prop) {
22448 return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));
22449 },
22450 /**
22451 * A trap for Object.getOwnPropertyDescriptor.
22452 * Also used by Object.hasOwnProperty.
22453 */ getOwnPropertyDescriptor (target, prop) {
22454 return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
22455 },
22456 /**
22457 * A trap for Object.getPrototypeOf.
22458 */ getPrototypeOf () {
22459 return Reflect.getPrototypeOf(scopes[0]);
22460 },
22461 /**
22462 * A trap for the in operator.
22463 */ has (target, prop) {
22464 return getKeysFromAllScopes(target).includes(prop);
22465 },
22466 /**
22467 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22468 */ ownKeys (target) {
22469 return getKeysFromAllScopes(target);
22470 },
22471 /**
22472 * A trap for setting property values.
22473 */ set (target, prop, value) {
22474 const storage = target._storage || (target._storage = getTarget());
22475 target[prop] = storage[prop] = value; // set to top level scope + cache
22476 delete target._keys; // remove cached keys
22477 return true;
22478 }
22479 });
22480 }
22481 /**
22482 * Returns an Proxy for resolving option values with context.
22483 * @param proxy - The Proxy returned by `_createResolver`
22484 * @param context - Context object for scriptable/indexable options
22485 * @param subProxy - The proxy provided for scriptable options
22486 * @param descriptorDefaults - Defaults for descriptors
22487 * @private
22488 */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {
22489 const cache = {
22490 _cacheable: false,
22491 _proxy: proxy,
22492 _context: context,
22493 _subProxy: subProxy,
22494 _stack: new Set(),
22495 _descriptors: _descriptors(proxy, descriptorDefaults),
22496 setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),
22497 override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
22498 };
22499 return new Proxy(cache, {
22500 /**
22501 * A trap for the delete operator.
22502 */ deleteProperty (target, prop) {
22503 delete target[prop]; // remove from cache
22504 delete proxy[prop]; // remove from proxy
22505 return true;
22506 },
22507 /**
22508 * A trap for getting property values.
22509 */ get (target, prop, receiver) {
22510 return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));
22511 },
22512 /**
22513 * A trap for Object.getOwnPropertyDescriptor.
22514 * Also used by Object.hasOwnProperty.
22515 */ getOwnPropertyDescriptor (target, prop) {
22516 return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
22517 enumerable: true,
22518 configurable: true
22519 } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);
22520 },
22521 /**
22522 * A trap for Object.getPrototypeOf.
22523 */ getPrototypeOf () {
22524 return Reflect.getPrototypeOf(proxy);
22525 },
22526 /**
22527 * A trap for the in operator.
22528 */ has (target, prop) {
22529 return Reflect.has(proxy, prop);
22530 },
22531 /**
22532 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22533 */ ownKeys () {
22534 return Reflect.ownKeys(proxy);
22535 },
22536 /**
22537 * A trap for setting property values.
22538 */ set (target, prop, value) {
22539 proxy[prop] = value; // set to proxy
22540 delete target[prop]; // remove from cache
22541 return true;
22542 }
22543 });
22544 }
22545 /**
22546 * @private
22547 */ function _descriptors(proxy, defaults = {
22548 scriptable: true,
22549 indexable: true
22550 }) {
22551 const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;
22552 return {
22553 allKeys: _allKeys,
22554 scriptable: _scriptable,
22555 indexable: _indexable,
22556 isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,
22557 isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable
22558 };
22559 }
22560 const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;
22561 const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);
22562 function _cached(target, prop, resolve) {
22563 if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {
22564 return target[prop];
22565 }
22566 const value = resolve();
22567 // cache the resolved value
22568 target[prop] = value;
22569 return value;
22570 }
22571 function _resolveWithContext(target, prop, receiver) {
22572 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22573 let value = _proxy[prop]; // resolve from proxy
22574 // resolve with context
22575 if (isFunction(value) && descriptors.isScriptable(prop)) {
22576 value = _resolveScriptable(prop, value, target, receiver);
22577 }
22578 if (isArray(value) && value.length) {
22579 value = _resolveArray(prop, value, target, descriptors.isIndexable);
22580 }
22581 if (needsSubResolver(prop, value)) {
22582 // if the resolved value is an object, create a sub resolver for it
22583 value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
22584 }
22585 return value;
22586 }
22587 function _resolveScriptable(prop, getValue, target, receiver) {
22588 const { _proxy , _context , _subProxy , _stack } = target;
22589 if (_stack.has(prop)) {
22590 throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
22591 }
22592 _stack.add(prop);
22593 let value = getValue(_context, _subProxy || receiver);
22594 _stack.delete(prop);
22595 if (needsSubResolver(prop, value)) {
22596 // When scriptable option returns an object, create a resolver on that.
22597 value = createSubResolver(_proxy._scopes, _proxy, prop, value);
22598 }
22599 return value;
22600 }
22601 function _resolveArray(prop, value, target, isIndexable) {
22602 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22603 if (typeof _context.index !== 'undefined' && isIndexable(prop)) {
22604 return value[_context.index % value.length];
22605 } else if (isObject(value[0])) {
22606 // Array of objects, return array or resolvers
22607 const arr = value;
22608 const scopes = _proxy._scopes.filter((s)=>s !== arr);
22609 value = [];
22610 for (const item of arr){
22611 const resolver = createSubResolver(scopes, _proxy, prop, item);
22612 value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
22613 }
22614 }
22615 return value;
22616 }
22617 function resolveFallback(fallback, prop, value) {
22618 return isFunction(fallback) ? fallback(prop, value) : fallback;
22619 }
22620 const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
22621 function addScopes(set, parentScopes, key, parentFallback, value) {
22622 for (const parent of parentScopes){
22623 const scope = getScope(key, parent);
22624 if (scope) {
22625 set.add(scope);
22626 const fallback = resolveFallback(scope._fallback, key, value);
22627 if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {
22628 // When we reach the descriptor that defines a new _fallback, return that.
22629 // The fallback will resume to that new scope.
22630 return fallback;
22631 }
22632 } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {
22633 // Fallback to `false` results to `false`, when falling back to different key.
22634 // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`
22635 return null;
22636 }
22637 }
22638 return false;
22639 }
22640 function createSubResolver(parentScopes, resolver, prop, value) {
22641 const rootScopes = resolver._rootScopes;
22642 const fallback = resolveFallback(resolver._fallback, prop, value);
22643 const allScopes = [
22644 ...parentScopes,
22645 ...rootScopes
22646 ];
22647 const set = new Set();
22648 set.add(value);
22649 let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
22650 if (key === null) {
22651 return false;
22652 }
22653 if (typeof fallback !== 'undefined' && fallback !== prop) {
22654 key = addScopesFromKey(set, allScopes, fallback, key, value);
22655 if (key === null) {
22656 return false;
22657 }
22658 }
22659 return _createResolver(Array.from(set), [
22660 ''
22661 ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));
22662 }
22663 function addScopesFromKey(set, allScopes, key, fallback, item) {
22664 while(key){
22665 key = addScopes(set, allScopes, key, fallback, item);
22666 }
22667 return key;
22668 }
22669 function subGetTarget(resolver, prop, value) {
22670 const parent = resolver._getTarget();
22671 if (!(prop in parent)) {
22672 parent[prop] = {};
22673 }
22674 const target = parent[prop];
22675 if (isArray(target) && isObject(value)) {
22676 // For array of objects, the object is used to store updated values
22677 return value;
22678 }
22679 return target || {};
22680 }
22681 function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
22682 let value;
22683 for (const prefix of prefixes){
22684 value = _resolve(readKey(prefix, prop), scopes);
22685 if (typeof value !== 'undefined') {
22686 return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
22687 }
22688 }
22689 }
22690 function _resolve(key, scopes) {
22691 for (const scope of scopes){
22692 if (!scope) {
22693 continue;
22694 }
22695 const value = scope[key];
22696 if (typeof value !== 'undefined') {
22697 return value;
22698 }
22699 }
22700 }
22701 function getKeysFromAllScopes(target) {
22702 let keys = target._keys;
22703 if (!keys) {
22704 keys = target._keys = resolveKeysFromAllScopes(target._scopes);
22705 }
22706 return keys;
22707 }
22708 function resolveKeysFromAllScopes(scopes) {
22709 const set = new Set();
22710 for (const scope of scopes){
22711 for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){
22712 set.add(key);
22713 }
22714 }
22715 return Array.from(set);
22716 }
22717 function _parseObjectDataRadialScale(meta, data, start, count) {
22718 const { iScale } = meta;
22719 const { key ='r' } = this._parsing;
22720 const parsed = new Array(count);
22721 let i, ilen, index, item;
22722 for(i = 0, ilen = count; i < ilen; ++i){
22723 index = i + start;
22724 item = data[index];
22725 parsed[i] = {
22726 r: iScale.parse(resolveObjectKey(item, key), index)
22727 };
22728 }
22729 return parsed;
22730 }
22731
22732 const EPSILON = Number.EPSILON || 1e-14;
22733 const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];
22734 const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';
22735 function splineCurve(firstPoint, middlePoint, afterPoint, t) {
22736 // Props to Rob Spencer at scaled innovation for his post on splining between points
22737 // http://scaledinnovation.com/analytics/splines/aboutSplines.html
22738 // This function must also respect "skipped" points
22739 const previous = firstPoint.skip ? middlePoint : firstPoint;
22740 const current = middlePoint;
22741 const next = afterPoint.skip ? middlePoint : afterPoint;
22742 const d01 = distanceBetweenPoints(current, previous);
22743 const d12 = distanceBetweenPoints(next, current);
22744 let s01 = d01 / (d01 + d12);
22745 let s12 = d12 / (d01 + d12);
22746 // If all points are the same, s01 & s02 will be inf
22747 s01 = isNaN(s01) ? 0 : s01;
22748 s12 = isNaN(s12) ? 0 : s12;
22749 const fa = t * s01; // scaling factor for triangle Ta
22750 const fb = t * s12;
22751 return {
22752 previous: {
22753 x: current.x - fa * (next.x - previous.x),
22754 y: current.y - fa * (next.y - previous.y)
22755 },
22756 next: {
22757 x: current.x + fb * (next.x - previous.x),
22758 y: current.y + fb * (next.y - previous.y)
22759 }
22760 };
22761 }
22762 /**
22763 * Adjust tangents to ensure monotonic properties
22764 */ function monotoneAdjust(points, deltaK, mK) {
22765 const pointsLen = points.length;
22766 let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
22767 let pointAfter = getPoint(points, 0);
22768 for(let i = 0; i < pointsLen - 1; ++i){
22769 pointCurrent = pointAfter;
22770 pointAfter = getPoint(points, i + 1);
22771 if (!pointCurrent || !pointAfter) {
22772 continue;
22773 }
22774 if (almostEquals(deltaK[i], 0, EPSILON)) {
22775 mK[i] = mK[i + 1] = 0;
22776 continue;
22777 }
22778 alphaK = mK[i] / deltaK[i];
22779 betaK = mK[i + 1] / deltaK[i];
22780 squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
22781 if (squaredMagnitude <= 9) {
22782 continue;
22783 }
22784 tauK = 3 / Math.sqrt(squaredMagnitude);
22785 mK[i] = alphaK * tauK * deltaK[i];
22786 mK[i + 1] = betaK * tauK * deltaK[i];
22787 }
22788 }
22789 function monotoneCompute(points, mK, indexAxis = 'x') {
22790 const valueAxis = getValueAxis(indexAxis);
22791 const pointsLen = points.length;
22792 let delta, pointBefore, pointCurrent;
22793 let pointAfter = getPoint(points, 0);
22794 for(let i = 0; i < pointsLen; ++i){
22795 pointBefore = pointCurrent;
22796 pointCurrent = pointAfter;
22797 pointAfter = getPoint(points, i + 1);
22798 if (!pointCurrent) {
22799 continue;
22800 }
22801 const iPixel = pointCurrent[indexAxis];
22802 const vPixel = pointCurrent[valueAxis];
22803 if (pointBefore) {
22804 delta = (iPixel - pointBefore[indexAxis]) / 3;
22805 pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
22806 pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
22807 }
22808 if (pointAfter) {
22809 delta = (pointAfter[indexAxis] - iPixel) / 3;
22810 pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
22811 pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
22812 }
22813 }
22814 }
22815 /**
22816 * This function calculates Bézier control points in a similar way than |splineCurve|,
22817 * but preserves monotonicity of the provided data and ensures no local extremums are added
22818 * between the dataset discrete points due to the interpolation.
22819 * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
22820 */ function splineCurveMonotone(points, indexAxis = 'x') {
22821 const valueAxis = getValueAxis(indexAxis);
22822 const pointsLen = points.length;
22823 const deltaK = Array(pointsLen).fill(0);
22824 const mK = Array(pointsLen);
22825 // Calculate slopes (deltaK) and initialize tangents (mK)
22826 let i, pointBefore, pointCurrent;
22827 let pointAfter = getPoint(points, 0);
22828 for(i = 0; i < pointsLen; ++i){
22829 pointBefore = pointCurrent;
22830 pointCurrent = pointAfter;
22831 pointAfter = getPoint(points, i + 1);
22832 if (!pointCurrent) {
22833 continue;
22834 }
22835 if (pointAfter) {
22836 const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
22837 // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
22838 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
22839 }
22840 mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;
22841 }
22842 monotoneAdjust(points, deltaK, mK);
22843 monotoneCompute(points, mK, indexAxis);
22844 }
22845 function capControlPoint(pt, min, max) {
22846 return Math.max(Math.min(pt, max), min);
22847 }
22848 function capBezierPoints(points, area) {
22849 let i, ilen, point, inArea, inAreaPrev;
22850 let inAreaNext = _isPointInArea(points[0], area);
22851 for(i = 0, ilen = points.length; i < ilen; ++i){
22852 inAreaPrev = inArea;
22853 inArea = inAreaNext;
22854 inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
22855 if (!inArea) {
22856 continue;
22857 }
22858 point = points[i];
22859 if (inAreaPrev) {
22860 point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
22861 point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
22862 }
22863 if (inAreaNext) {
22864 point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
22865 point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
22866 }
22867 }
22868 }
22869 /**
22870 * @private
22871 */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
22872 let i, ilen, point, controlPoints;
22873 // Only consider points that are drawn in case the spanGaps option is used
22874 if (options.spanGaps) {
22875 points = points.filter((pt)=>!pt.skip);
22876 }
22877 if (options.cubicInterpolationMode === 'monotone') {
22878 splineCurveMonotone(points, indexAxis);
22879 } else {
22880 let prev = loop ? points[points.length - 1] : points[0];
22881 for(i = 0, ilen = points.length; i < ilen; ++i){
22882 point = points[i];
22883 controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);
22884 point.cp1x = controlPoints.previous.x;
22885 point.cp1y = controlPoints.previous.y;
22886 point.cp2x = controlPoints.next.x;
22887 point.cp2y = controlPoints.next.y;
22888 prev = point;
22889 }
22890 }
22891 if (options.capBezierPoints) {
22892 capBezierPoints(points, area);
22893 }
22894 }
22895
22896 /**
22897 * @private
22898 */ function _isDomSupported() {
22899 return typeof window !== 'undefined' && typeof document !== 'undefined';
22900 }
22901 /**
22902 * @private
22903 */ function _getParentNode(domNode) {
22904 let parent = domNode.parentNode;
22905 if (parent && parent.toString() === '[object ShadowRoot]') {
22906 parent = parent.host;
22907 }
22908 return parent;
22909 }
22910 /**
22911 * convert max-width/max-height values that may be percentages into a number
22912 * @private
22913 */ function parseMaxStyle(styleValue, node, parentProperty) {
22914 let valueInPixels;
22915 if (typeof styleValue === 'string') {
22916 valueInPixels = parseInt(styleValue, 10);
22917 if (styleValue.indexOf('%') !== -1) {
22918 // percentage * size in dimension
22919 valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
22920 }
22921 } else {
22922 valueInPixels = styleValue;
22923 }
22924 return valueInPixels;
22925 }
22926 const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);
22927 function getStyle(el, property) {
22928 return getComputedStyle(el).getPropertyValue(property);
22929 }
22930 const positions = [
22931 'top',
22932 'right',
22933 'bottom',
22934 'left'
22935 ];
22936 function getPositionedStyle(styles, style, suffix) {
22937 const result = {};
22938 suffix = suffix ? '-' + suffix : '';
22939 for(let i = 0; i < 4; i++){
22940 const pos = positions[i];
22941 result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
22942 }
22943 result.width = result.left + result.right;
22944 result.height = result.top + result.bottom;
22945 return result;
22946 }
22947 const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);
22948 /**
22949 * @param e
22950 * @param canvas
22951 * @returns Canvas position
22952 */ function getCanvasPosition(e, canvas) {
22953 const touches = e.touches;
22954 const source = touches && touches.length ? touches[0] : e;
22955 const { offsetX , offsetY } = source;
22956 let box = false;
22957 let x, y;
22958 if (useOffsetPos(offsetX, offsetY, e.target)) {
22959 x = offsetX;
22960 y = offsetY;
22961 } else {
22962 const rect = canvas.getBoundingClientRect();
22963 x = source.clientX - rect.left;
22964 y = source.clientY - rect.top;
22965 box = true;
22966 }
22967 return {
22968 x,
22969 y,
22970 box
22971 };
22972 }
22973 /**
22974 * Gets an event's x, y coordinates, relative to the chart area
22975 * @param event
22976 * @param chart
22977 * @returns x and y coordinates of the event
22978 */ function getRelativePosition(event, chart) {
22979 if ('native' in event) {
22980 return event;
22981 }
22982 const { canvas , currentDevicePixelRatio } = chart;
22983 const style = getComputedStyle(canvas);
22984 const borderBox = style.boxSizing === 'border-box';
22985 const paddings = getPositionedStyle(style, 'padding');
22986 const borders = getPositionedStyle(style, 'border', 'width');
22987 const { x , y , box } = getCanvasPosition(event, canvas);
22988 const xOffset = paddings.left + (box && borders.left);
22989 const yOffset = paddings.top + (box && borders.top);
22990 let { width , height } = chart;
22991 if (borderBox) {
22992 width -= paddings.width + borders.width;
22993 height -= paddings.height + borders.height;
22994 }
22995 return {
22996 x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
22997 y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
22998 };
22999 }
23000 function getContainerSize(canvas, width, height) {
23001 let maxWidth, maxHeight;
23002 if (width === undefined || height === undefined) {
23003 const container = canvas && _getParentNode(canvas);
23004 if (!container) {
23005 width = canvas.clientWidth;
23006 height = canvas.clientHeight;
23007 } else {
23008 const rect = container.getBoundingClientRect(); // this is the border box of the container
23009 const containerStyle = getComputedStyle(container);
23010 const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
23011 const containerPadding = getPositionedStyle(containerStyle, 'padding');
23012 width = rect.width - containerPadding.width - containerBorder.width;
23013 height = rect.height - containerPadding.height - containerBorder.height;
23014 maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
23015 maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
23016 }
23017 }
23018 return {
23019 width,
23020 height,
23021 maxWidth: maxWidth || INFINITY,
23022 maxHeight: maxHeight || INFINITY
23023 };
23024 }
23025 const round1 = (v)=>Math.round(v * 10) / 10;
23026 // eslint-disable-next-line complexity
23027 function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
23028 const style = getComputedStyle(canvas);
23029 const margins = getPositionedStyle(style, 'margin');
23030 const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
23031 const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
23032 const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
23033 let { width , height } = containerSize;
23034 if (style.boxSizing === 'content-box') {
23035 const borders = getPositionedStyle(style, 'border', 'width');
23036 const paddings = getPositionedStyle(style, 'padding');
23037 width -= paddings.width + borders.width;
23038 height -= paddings.height + borders.height;
23039 }
23040 width = Math.max(0, width - margins.width);
23041 height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
23042 width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
23043 height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
23044 if (width && !height) {
23045 // https://github.com/chartjs/Chart.js/issues/4659
23046 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)
23047 height = round1(width / 2);
23048 }
23049 const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;
23050 if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
23051 height = containerSize.height;
23052 width = round1(Math.floor(height * aspectRatio));
23053 }
23054 return {
23055 width,
23056 height
23057 };
23058 }
23059 /**
23060 * @param chart
23061 * @param forceRatio
23062 * @param forceStyle
23063 * @returns True if the canvas context size or transformation has changed.
23064 */ function retinaScale(chart, forceRatio, forceStyle) {
23065 const pixelRatio = forceRatio || 1;
23066 const deviceHeight = round1(chart.height * pixelRatio);
23067 const deviceWidth = round1(chart.width * pixelRatio);
23068 chart.height = round1(chart.height);
23069 chart.width = round1(chart.width);
23070 const canvas = chart.canvas;
23071 // If no style has been set on the canvas, the render size is used as display size,
23072 // making the chart visually bigger, so let's enforce it to the "correct" values.
23073 // See https://github.com/chartjs/Chart.js/issues/3575
23074 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
23075 canvas.style.height = `${chart.height}px`;
23076 canvas.style.width = `${chart.width}px`;
23077 }
23078 if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
23079 chart.currentDevicePixelRatio = pixelRatio;
23080 canvas.height = deviceHeight;
23081 canvas.width = deviceWidth;
23082 chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
23083 return true;
23084 }
23085 return false;
23086 }
23087 /**
23088 * Detects support for options object argument in addEventListener.
23089 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
23090 * @private
23091 */ const supportsEventListenerOptions = function() {
23092 let passiveSupported = false;
23093 try {
23094 const options = {
23095 get passive () {
23096 passiveSupported = true;
23097 return false;
23098 }
23099 };
23100 if (_isDomSupported()) {
23101 window.addEventListener('test', null, options);
23102 window.removeEventListener('test', null, options);
23103 }
23104 } catch (e) {
23105 // continue regardless of error
23106 }
23107 return passiveSupported;
23108 }();
23109 /**
23110 * The "used" size is the final value of a dimension property after all calculations have
23111 * been performed. This method uses the computed style of `element` but returns undefined
23112 * if the computed style is not expressed in pixels. That can happen in some cases where
23113 * `element` has a size relative to its parent and this last one is not yet displayed,
23114 * for example because of `display: none` on a parent node.
23115 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
23116 * @returns Size in pixels or undefined if unknown.
23117 */ function readUsedSize(element, property) {
23118 const value = getStyle(element, property);
23119 const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
23120 return matches ? +matches[1] : undefined;
23121 }
23122
23123 /**
23124 * @private
23125 */ function _pointInLine(p1, p2, t, mode) {
23126 return {
23127 x: p1.x + t * (p2.x - p1.x),
23128 y: p1.y + t * (p2.y - p1.y)
23129 };
23130 }
23131 /**
23132 * @private
23133 */ function _steppedInterpolation(p1, p2, t, mode) {
23134 return {
23135 x: p1.x + t * (p2.x - p1.x),
23136 y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y
23137 };
23138 }
23139 /**
23140 * @private
23141 */ function _bezierInterpolation(p1, p2, t, mode) {
23142 const cp1 = {
23143 x: p1.cp2x,
23144 y: p1.cp2y
23145 };
23146 const cp2 = {
23147 x: p2.cp1x,
23148 y: p2.cp1y
23149 };
23150 const a = _pointInLine(p1, cp1, t);
23151 const b = _pointInLine(cp1, cp2, t);
23152 const c = _pointInLine(cp2, p2, t);
23153 const d = _pointInLine(a, b, t);
23154 const e = _pointInLine(b, c, t);
23155 return _pointInLine(d, e, t);
23156 }
23157
23158 const getRightToLeftAdapter = function(rectX, width) {
23159 return {
23160 x (x) {
23161 return rectX + rectX + width - x;
23162 },
23163 setWidth (w) {
23164 width = w;
23165 },
23166 textAlign (align) {
23167 if (align === 'center') {
23168 return align;
23169 }
23170 return align === 'right' ? 'left' : 'right';
23171 },
23172 xPlus (x, value) {
23173 return x - value;
23174 },
23175 leftForLtr (x, itemWidth) {
23176 return x - itemWidth;
23177 }
23178 };
23179 };
23180 const getLeftToRightAdapter = function() {
23181 return {
23182 x (x) {
23183 return x;
23184 },
23185 setWidth (w) {},
23186 textAlign (align) {
23187 return align;
23188 },
23189 xPlus (x, value) {
23190 return x + value;
23191 },
23192 leftForLtr (x, _itemWidth) {
23193 return x;
23194 }
23195 };
23196 };
23197 function getRtlAdapter(rtl, rectX, width) {
23198 return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
23199 }
23200 function overrideTextDirection(ctx, direction) {
23201 let style, original;
23202 if (direction === 'ltr' || direction === 'rtl') {
23203 style = ctx.canvas.style;
23204 original = [
23205 style.getPropertyValue('direction'),
23206 style.getPropertyPriority('direction')
23207 ];
23208 style.setProperty('direction', direction, 'important');
23209 ctx.prevTextDirection = original;
23210 }
23211 }
23212 function restoreTextDirection(ctx, original) {
23213 if (original !== undefined) {
23214 delete ctx.prevTextDirection;
23215 ctx.canvas.style.setProperty('direction', original[0], original[1]);
23216 }
23217 }
23218
23219 function propertyFn(property) {
23220 if (property === 'angle') {
23221 return {
23222 between: _angleBetween,
23223 compare: _angleDiff,
23224 normalize: _normalizeAngle
23225 };
23226 }
23227 return {
23228 between: _isBetween,
23229 compare: (a, b)=>a - b,
23230 normalize: (x)=>x
23231 };
23232 }
23233 function normalizeSegment({ start , end , count , loop , style }) {
23234 return {
23235 start: start % count,
23236 end: end % count,
23237 loop: loop && (end - start + 1) % count === 0,
23238 style
23239 };
23240 }
23241 function getSegment(segment, points, bounds) {
23242 const { property , start: startBound , end: endBound } = bounds;
23243 const { between , normalize } = propertyFn(property);
23244 const count = points.length;
23245 let { start , end , loop } = segment;
23246 let i, ilen;
23247 if (loop) {
23248 start += count;
23249 end += count;
23250 for(i = 0, ilen = count; i < ilen; ++i){
23251 if (!between(normalize(points[start % count][property]), startBound, endBound)) {
23252 break;
23253 }
23254 start--;
23255 end--;
23256 }
23257 start %= count;
23258 end %= count;
23259 }
23260 if (end < start) {
23261 end += count;
23262 }
23263 return {
23264 start,
23265 end,
23266 loop,
23267 style: segment.style
23268 };
23269 }
23270 function _boundSegment(segment, points, bounds) {
23271 if (!bounds) {
23272 return [
23273 segment
23274 ];
23275 }
23276 const { property , start: startBound , end: endBound } = bounds;
23277 const count = points.length;
23278 const { compare , between , normalize } = propertyFn(property);
23279 const { start , end , loop , style } = getSegment(segment, points, bounds);
23280 const result = [];
23281 let inside = false;
23282 let subStart = null;
23283 let value, point, prevValue;
23284 const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
23285 const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);
23286 const shouldStart = ()=>inside || startIsBefore();
23287 const shouldStop = ()=>!inside || endIsBefore();
23288 for(let i = start, prev = start; i <= end; ++i){
23289 point = points[i % count];
23290 if (point.skip) {
23291 continue;
23292 }
23293 value = normalize(point[property]);
23294 if (value === prevValue) {
23295 continue;
23296 }
23297 inside = between(value, startBound, endBound);
23298 if (subStart === null && shouldStart()) {
23299 subStart = compare(value, startBound) === 0 ? i : prev;
23300 }
23301 if (subStart !== null && shouldStop()) {
23302 result.push(normalizeSegment({
23303 start: subStart,
23304 end: i,
23305 loop,
23306 count,
23307 style
23308 }));
23309 subStart = null;
23310 }
23311 prev = i;
23312 prevValue = value;
23313 }
23314 if (subStart !== null) {
23315 result.push(normalizeSegment({
23316 start: subStart,
23317 end,
23318 loop,
23319 count,
23320 style
23321 }));
23322 }
23323 return result;
23324 }
23325 function _boundSegments(line, bounds) {
23326 const result = [];
23327 const segments = line.segments;
23328 for(let i = 0; i < segments.length; i++){
23329 const sub = _boundSegment(segments[i], line.points, bounds);
23330 if (sub.length) {
23331 result.push(...sub);
23332 }
23333 }
23334 return result;
23335 }
23336 function findStartAndEnd(points, count, loop, spanGaps) {
23337 let start = 0;
23338 let end = count - 1;
23339 if (loop && !spanGaps) {
23340 while(start < count && !points[start].skip){
23341 start++;
23342 }
23343 }
23344 while(start < count && points[start].skip){
23345 start++;
23346 }
23347 start %= count;
23348 if (loop) {
23349 end += start;
23350 }
23351 while(end > start && points[end % count].skip){
23352 end--;
23353 }
23354 end %= count;
23355 return {
23356 start,
23357 end
23358 };
23359 }
23360 function solidSegments(points, start, max, loop) {
23361 const count = points.length;
23362 const result = [];
23363 let last = start;
23364 let prev = points[start];
23365 let end;
23366 for(end = start + 1; end <= max; ++end){
23367 const cur = points[end % count];
23368 if (cur.skip || cur.stop) {
23369 if (!prev.skip) {
23370 loop = false;
23371 result.push({
23372 start: start % count,
23373 end: (end - 1) % count,
23374 loop
23375 });
23376 start = last = cur.stop ? end : null;
23377 }
23378 } else {
23379 last = end;
23380 if (prev.skip) {
23381 start = end;
23382 }
23383 }
23384 prev = cur;
23385 }
23386 if (last !== null) {
23387 result.push({
23388 start: start % count,
23389 end: last % count,
23390 loop
23391 });
23392 }
23393 return result;
23394 }
23395 function _computeSegments(line, segmentOptions) {
23396 const points = line.points;
23397 const spanGaps = line.options.spanGaps;
23398 const count = points.length;
23399 if (!count) {
23400 return [];
23401 }
23402 const loop = !!line._loop;
23403 const { start , end } = findStartAndEnd(points, count, loop, spanGaps);
23404 if (spanGaps === true) {
23405 return splitByStyles(line, [
23406 {
23407 start,
23408 end,
23409 loop
23410 }
23411 ], points, segmentOptions);
23412 }
23413 const max = end < start ? end + count : end;
23414 const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
23415 return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
23416 }
23417 function splitByStyles(line, segments, points, segmentOptions) {
23418 if (!segmentOptions || !segmentOptions.setContext || !points) {
23419 return segments;
23420 }
23421 return doSplitByStyles(line, segments, points, segmentOptions);
23422 }
23423 function doSplitByStyles(line, segments, points, segmentOptions) {
23424 const chartContext = line._chart.getContext();
23425 const baseStyle = readStyle(line.options);
23426 const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;
23427 const count = points.length;
23428 const result = [];
23429 let prevStyle = baseStyle;
23430 let start = segments[0].start;
23431 let i = start;
23432 function addStyle(s, e, l, st) {
23433 const dir = spanGaps ? -1 : 1;
23434 if (s === e) {
23435 return;
23436 }
23437 s += count;
23438 while(points[s % count].skip){
23439 s -= dir;
23440 }
23441 while(points[e % count].skip){
23442 e += dir;
23443 }
23444 if (s % count !== e % count) {
23445 result.push({
23446 start: s % count,
23447 end: e % count,
23448 loop: l,
23449 style: st
23450 });
23451 prevStyle = st;
23452 start = e % count;
23453 }
23454 }
23455 for (const segment of segments){
23456 start = spanGaps ? start : segment.start;
23457 let prev = points[start % count];
23458 let style;
23459 for(i = start + 1; i <= segment.end; i++){
23460 const pt = points[i % count];
23461 style = readStyle(segmentOptions.setContext(createContext(chartContext, {
23462 type: 'segment',
23463 p0: prev,
23464 p1: pt,
23465 p0DataIndex: (i - 1) % count,
23466 p1DataIndex: i % count,
23467 datasetIndex
23468 })));
23469 if (styleChanged(style, prevStyle)) {
23470 addStyle(start, i - 1, segment.loop, prevStyle);
23471 }
23472 prev = pt;
23473 prevStyle = style;
23474 }
23475 if (start < i - 1) {
23476 addStyle(start, i - 1, segment.loop, prevStyle);
23477 }
23478 }
23479 return result;
23480 }
23481 function readStyle(options) {
23482 return {
23483 backgroundColor: options.backgroundColor,
23484 borderCapStyle: options.borderCapStyle,
23485 borderDash: options.borderDash,
23486 borderDashOffset: options.borderDashOffset,
23487 borderJoinStyle: options.borderJoinStyle,
23488 borderWidth: options.borderWidth,
23489 borderColor: options.borderColor
23490 };
23491 }
23492 function styleChanged(style, prevStyle) {
23493 if (!prevStyle) {
23494 return false;
23495 }
23496 const cache = [];
23497 const replacer = function(key, value) {
23498 if (!isPatternOrGradient(value)) {
23499 return value;
23500 }
23501 if (!cache.includes(value)) {
23502 cache.push(value);
23503 }
23504 return cache.indexOf(value);
23505 };
23506 return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);
23507 }
23508
23509 function getSizeForArea(scale, chartArea, field) {
23510 return scale.options.clip ? scale[field] : chartArea[field];
23511 }
23512 function getDatasetArea(meta, chartArea) {
23513 const { xScale , yScale } = meta;
23514 if (xScale && yScale) {
23515 return {
23516 left: getSizeForArea(xScale, chartArea, 'left'),
23517 right: getSizeForArea(xScale, chartArea, 'right'),
23518 top: getSizeForArea(yScale, chartArea, 'top'),
23519 bottom: getSizeForArea(yScale, chartArea, 'bottom')
23520 };
23521 }
23522 return chartArea;
23523 }
23524 function getDatasetClipArea(chart, meta) {
23525 const clip = meta._clip;
23526 if (clip.disabled) {
23527 return false;
23528 }
23529 const area = getDatasetArea(meta, chart.chartArea);
23530 return {
23531 left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left),
23532 right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right),
23533 top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top),
23534 bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom)
23535 };
23536 }
23537
23538
23539 //# sourceMappingURL=helpers.dataset.js.map
23540
23541
23542 /***/ }
23543
23544 /******/ });
23545 /************************************************************************/
23546 /******/ // The module cache
23547 /******/ var __webpack_module_cache__ = {};
23548 /******/
23549 /******/ // The require function
23550 /******/ function __webpack_require__(moduleId) {
23551 /******/ // Check if module is in cache
23552 /******/ var cachedModule = __webpack_module_cache__[moduleId];
23553 /******/ if (cachedModule !== undefined) {
23554 /******/ return cachedModule.exports;
23555 /******/ }
23556 /******/ // Create a new module (and put it into the cache)
23557 /******/ var module = __webpack_module_cache__[moduleId] = {
23558 /******/ // no module.id needed
23559 /******/ // no module.loaded needed
23560 /******/ exports: {}
23561 /******/ };
23562 /******/
23563 /******/ // Execute the module function
23564 /******/ if (!(moduleId in __webpack_modules__)) {
23565 /******/ delete __webpack_module_cache__[moduleId];
23566 /******/ var e = new Error("Cannot find module '" + moduleId + "'");
23567 /******/ e.code = 'MODULE_NOT_FOUND';
23568 /******/ throw e;
23569 /******/ }
23570 /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
23571 /******/
23572 /******/ // Return the exports of the module
23573 /******/ return module.exports;
23574 /******/ }
23575 /******/
23576 /************************************************************************/
23577 /******/ /* webpack/runtime/compat get default export */
23578 /******/ (() => {
23579 /******/ // getDefaultExport function for compatibility with non-harmony modules
23580 /******/ __webpack_require__.n = (module) => {
23581 /******/ var getter = module && module.__esModule ?
23582 /******/ () => (module['default']) :
23583 /******/ () => (module);
23584 /******/ __webpack_require__.d(getter, { a: getter });
23585 /******/ return getter;
23586 /******/ };
23587 /******/ })();
23588 /******/
23589 /******/ /* webpack/runtime/define property getters */
23590 /******/ (() => {
23591 /******/ // define getter functions for harmony exports
23592 /******/ __webpack_require__.d = (exports, definition) => {
23593 /******/ for(var key in definition) {
23594 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
23595 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
23596 /******/ }
23597 /******/ }
23598 /******/ };
23599 /******/ })();
23600 /******/
23601 /******/ /* webpack/runtime/hasOwnProperty shorthand */
23602 /******/ (() => {
23603 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
23604 /******/ })();
23605 /******/
23606 /******/ /* webpack/runtime/make namespace object */
23607 /******/ (() => {
23608 /******/ // define __esModule on exports
23609 /******/ __webpack_require__.r = (exports) => {
23610 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
23611 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
23612 /******/ }
23613 /******/ Object.defineProperty(exports, '__esModule', { value: true });
23614 /******/ };
23615 /******/ })();
23616 /******/
23617 /************************************************************************/
23618 var __webpack_exports__ = {};
23619 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
23620 (() => {
23621 "use strict";
23622 /*!************************************************!*\
23623 !*** ./assets/src/js/admin/admin-statistic.js ***!
23624 \************************************************/
23625 __webpack_require__.r(__webpack_exports__);
23626 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
23627 /* harmony import */ var _statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./statistics/filter-bar.js */ "./assets/src/js/admin/statistics/filter-bar.js");
23628 /* harmony import */ var _statistics_report_modal_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./statistics/report-modal.js */ "./assets/src/js/admin/statistics/report-modal.js");
23629 /* harmony import */ var _statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./statistics/tab-overview.js */ "./assets/src/js/admin/statistics/tab-overview.js");
23630 /* harmony import */ var _statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./statistics/tab-orders.js */ "./assets/src/js/admin/statistics/tab-orders.js");
23631 /* harmony import */ var _statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./statistics/tab-courses.js */ "./assets/src/js/admin/statistics/tab-courses.js");
23632 /* harmony import */ var _statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./statistics/tab-users.js */ "./assets/src/js/admin/statistics/tab-users.js");
23633 /* harmony import */ var _statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./statistics/tab-instructors.js */ "./assets/src/js/admin/statistics/tab-instructors.js");
23634 /**
23635 * Statistics dashboard entry — bootstraps the per-tab modules.
23636 *
23637 * All four tabs run on the statistics/* module stack (state, api, chart,
23638 * data-table, report-modal); the legacy per-tab loaders are gone.
23639 *
23640 * @since 4.2.5.5
23641 * @version 2.0.0
23642 */
23643
23644
23645
23646
23647
23648
23649
23650
23651
23652 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.LpStatsFilterBar.selectors.elContainer, () => {
23653 _statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsFilterBar.init();
23654 });
23655 // SweetAlert2 popup: delegated events only, no rendered container to wait for.
23656 _statistics_report_modal_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsReportModal.init();
23657 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.LpStatsTabOverview.selectors.elContainer, () => {
23658 _statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.lpStatsTabOverview.init();
23659 });
23660 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.LpStatsTabOrders.selectors.elContainer, () => {
23661 _statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.lpStatsTabOrders.init();
23662 });
23663 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.LpStatsTabCourses.selectors.elContainer, () => {
23664 _statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.lpStatsTabCourses.init();
23665 });
23666 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.LpStatsTabUsers.selectors.elContainer, () => {
23667 _statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsTabUsers.init();
23668 });
23669 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.LpStatsTabInstructors.selectors.elContainer, () => {
23670 _statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.lpStatsTabInstructors.init();
23671 });
23672 })();
23673
23674 /******/ })()
23675 ;
23676 //# sourceMappingURL=admin-statistic.js.map