PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
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.4, at assets/js/dist/admin/admin-statistic.js

23,653 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.25
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 * @returns {boolean}
3607 */
3608 const isFirefox = () => navigator.userAgent.includes('Firefox');
3609
3610 /**
3611 * Gets the popup container which contains the backdrop and the popup itself.
3612 *
3613 * @returns {HTMLElement | null}
3614 */
3615 const getContainer = () => document.body.querySelector(`.${swalClasses.container}`);
3616
3617 /**
3618 * @param {string} selectorString
3619 * @returns {HTMLElement | null}
3620 */
3621 const elementBySelector = selectorString => {
3622 const container = getContainer();
3623 return container ? container.querySelector(selectorString) : null;
3624 };
3625
3626 /**
3627 * @param {string} className
3628 * @returns {HTMLElement | null}
3629 */
3630 const elementByClass = className => {
3631 return elementBySelector(`.${className}`);
3632 };
3633
3634 /**
3635 * @returns {HTMLElement | null}
3636 */
3637 const getPopup = () => elementByClass(swalClasses.popup);
3638
3639 /**
3640 * @returns {HTMLElement | null}
3641 */
3642 const getIcon = () => elementByClass(swalClasses.icon);
3643
3644 /**
3645 * @returns {HTMLElement | null}
3646 */
3647 const getIconContent = () => elementByClass(swalClasses['icon-content']);
3648
3649 /**
3650 * @returns {HTMLElement | null}
3651 */
3652 const getTitle = () => elementByClass(swalClasses.title);
3653
3654 /**
3655 * @returns {HTMLElement | null}
3656 */
3657 const getHtmlContainer = () => elementByClass(swalClasses['html-container']);
3658
3659 /**
3660 * @returns {HTMLElement | null}
3661 */
3662 const getImage = () => elementByClass(swalClasses.image);
3663
3664 /**
3665 * @returns {HTMLElement | null}
3666 */
3667 const getProgressSteps = () => elementByClass(swalClasses['progress-steps']);
3668
3669 /**
3670 * @returns {HTMLElement | null}
3671 */
3672 const getValidationMessage = () => elementByClass(swalClasses['validation-message']);
3673
3674 /**
3675 * @returns {HTMLButtonElement | null}
3676 */
3677 const getConfirmButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.confirm}`));
3678
3679 /**
3680 * @returns {HTMLButtonElement | null}
3681 */
3682 const getCancelButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.cancel}`));
3683
3684 /**
3685 * @returns {HTMLButtonElement | null}
3686 */
3687 const getDenyButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.deny}`));
3688
3689 /**
3690 * @returns {HTMLElement | null}
3691 */
3692 const getInputLabel = () => elementByClass(swalClasses['input-label']);
3693
3694 /**
3695 * @returns {HTMLElement | null}
3696 */
3697 const getLoader = () => elementBySelector(`.${swalClasses.loader}`);
3698
3699 /**
3700 * @returns {HTMLElement | null}
3701 */
3702 const getActions = () => elementByClass(swalClasses.actions);
3703
3704 /**
3705 * @returns {HTMLElement | null}
3706 */
3707 const getFooter = () => elementByClass(swalClasses.footer);
3708
3709 /**
3710 * @returns {HTMLElement | null}
3711 */
3712 const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']);
3713
3714 /**
3715 * @returns {HTMLElement | null}
3716 */
3717 const getCloseButton = () => elementByClass(swalClasses.close);
3718
3719 // https://github.com/jkup/focusable/blob/master/index.js
3720 const focusable = `
3721 a[href],
3722 area[href],
3723 input:not([disabled]),
3724 select:not([disabled]),
3725 textarea:not([disabled]),
3726 button:not([disabled]),
3727 iframe,
3728 object,
3729 embed,
3730 [tabindex="0"],
3731 [contenteditable],
3732 audio[controls],
3733 video[controls],
3734 summary
3735 `;
3736 /**
3737 * @returns {HTMLElement[]}
3738 */
3739 const getFocusableElements = () => {
3740 const popup = getPopup();
3741 if (!popup) {
3742 return [];
3743 }
3744 /** @type {NodeListOf<HTMLElement>} */
3745 const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])');
3746 const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex)
3747 // sort according to tabindex
3748 .sort((a, b) => {
3749 const tabindexA = parseInt(a.getAttribute('tabindex') || '0');
3750 const tabindexB = parseInt(b.getAttribute('tabindex') || '0');
3751 if (tabindexA > tabindexB) {
3752 return 1;
3753 } else if (tabindexA < tabindexB) {
3754 return -1;
3755 }
3756 return 0;
3757 });
3758
3759 /** @type {NodeListOf<HTMLElement>} */
3760 const otherFocusableElements = popup.querySelectorAll(focusable);
3761 const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1');
3762 return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el));
3763 };
3764
3765 /**
3766 * @returns {boolean}
3767 */
3768 const isModal = () => {
3769 return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']);
3770 };
3771
3772 /**
3773 * @returns {boolean}
3774 */
3775 const isToast = () => {
3776 const popup = getPopup();
3777 if (!popup) {
3778 return false;
3779 }
3780 return hasClass(popup, swalClasses.toast);
3781 };
3782
3783 /**
3784 * @returns {boolean}
3785 */
3786 const isLoading = () => {
3787 const popup = getPopup();
3788 if (!popup) {
3789 return false;
3790 }
3791 return popup.hasAttribute('data-loading');
3792 };
3793
3794 /**
3795 * Securely set innerHTML of an element
3796 * https://github.com/sweetalert2/sweetalert2/issues/1926
3797 *
3798 * @param {HTMLElement} elem
3799 * @param {string} html
3800 */
3801 const setInnerHtml = (elem, html) => {
3802 elem.textContent = '';
3803 if (html) {
3804 const parser = new DOMParser();
3805 const parsed = parser.parseFromString(html, `text/html`);
3806 const head = parsed.querySelector('head');
3807 if (head) {
3808 Array.from(head.childNodes).forEach(child => {
3809 elem.appendChild(child);
3810 });
3811 }
3812 const body = parsed.querySelector('body');
3813 if (body) {
3814 Array.from(body.childNodes).forEach(child => {
3815 if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) {
3816 elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507
3817 } else {
3818 elem.appendChild(child);
3819 }
3820 });
3821 }
3822 }
3823 };
3824
3825 /**
3826 * @param {HTMLElement} elem
3827 * @param {string} className
3828 * @returns {boolean}
3829 */
3830 const hasClass = (elem, className) => {
3831 if (!className) {
3832 return false;
3833 }
3834 return className.split(/\s+/).every(cls => elem.classList.contains(cls));
3835 };
3836
3837 /**
3838 * @param {HTMLElement} elem
3839 * @param {SweetAlertOptions} params
3840 */
3841 const removeCustomClasses = (elem, params) => {
3842 Array.from(elem.classList).forEach(className => {
3843 if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) {
3844 elem.classList.remove(className);
3845 }
3846 });
3847 };
3848
3849 /**
3850 * @param {HTMLElement} elem
3851 * @param {SweetAlertOptions} params
3852 * @param {string} className
3853 */
3854 const applyCustomClass = (elem, params, className) => {
3855 removeCustomClasses(elem, params);
3856 if (!params.customClass) {
3857 return;
3858 }
3859 const customClass = params.customClass[(/** @type {keyof SweetAlertCustomClass} */className)];
3860 if (!customClass) {
3861 return;
3862 }
3863 if (typeof customClass !== 'string' && !customClass.forEach) {
3864 warn(`Invalid type of customClass.${className}! Expected string or iterable object, got "${typeof customClass}"`);
3865 return;
3866 }
3867 addClass(elem, customClass);
3868 };
3869
3870 /**
3871 * @param {HTMLElement} popup
3872 * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass
3873 * @returns {HTMLInputElement | null}
3874 */
3875 const getInput$1 = (popup, inputClass) => {
3876 if (!inputClass) {
3877 return null;
3878 }
3879 switch (inputClass) {
3880 case 'select':
3881 case 'textarea':
3882 case 'file':
3883 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses[inputClass]}`);
3884 case 'checkbox':
3885 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.checkbox} input`);
3886 case 'radio':
3887 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:checked`) || popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:first-child`);
3888 case 'range':
3889 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.range} input`);
3890 default:
3891 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.input}`);
3892 }
3893 };
3894
3895 /**
3896 * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input
3897 */
3898 const focusInput = input => {
3899 input.focus();
3900
3901 // place cursor at end of text in text input
3902 if (input.type !== 'file') {
3903 // http://stackoverflow.com/a/2345915
3904 const val = input.value;
3905 input.value = '';
3906 input.value = val;
3907 }
3908 };
3909
3910 /**
3911 * @param {HTMLElement | HTMLElement[] | null} target
3912 * @param {string | string[] | readonly string[] | undefined} classList
3913 * @param {boolean} condition
3914 */
3915 const toggleClass = (target, classList, condition) => {
3916 if (!target || !classList) {
3917 return;
3918 }
3919 const classes = typeof classList === 'string' ? classList.split(/\s+/).filter(Boolean) : classList;
3920 const targets = Array.isArray(target) ? target : [target];
3921 targets.forEach(elem => {
3922 classes.forEach(className => {
3923 if (condition) {
3924 elem.classList.add(className);
3925 } else {
3926 elem.classList.remove(className);
3927 }
3928 });
3929 });
3930 };
3931
3932 /**
3933 * @param {HTMLElement | HTMLElement[] | null} target
3934 * @param {string | string[] | readonly string[] | undefined} classList
3935 */
3936 const addClass = (target, classList) => {
3937 toggleClass(target, classList, true);
3938 };
3939
3940 /**
3941 * @param {HTMLElement | HTMLElement[] | null} target
3942 * @param {string | string[] | readonly string[] | undefined} classList
3943 */
3944 const removeClass = (target, classList) => {
3945 toggleClass(target, classList, false);
3946 };
3947
3948 /**
3949 * Get direct child of an element by class name
3950 *
3951 * @param {HTMLElement} elem
3952 * @param {string} className
3953 * @returns {HTMLElement | undefined}
3954 */
3955 const getDirectChildByClass = (elem, className) => (/** @type {HTMLElement | undefined} */
3956 Array.from(elem.children).find(child => child instanceof HTMLElement && hasClass(child, className)));
3957
3958 /**
3959 * @param {HTMLElement} elem
3960 * @param {string} property
3961 * @param {string | number | null | undefined} value
3962 */
3963 const applyNumericalStyle = (elem, property, value) => {
3964 if (value === `${parseInt(`${value}`)}`) {
3965 value = parseInt(value);
3966 }
3967 if (value || value === 0) {
3968 elem.style.setProperty(property, typeof value === 'number' ? `${value}px` : (/** @type {string} */value));
3969 } else {
3970 elem.style.removeProperty(property);
3971 }
3972 };
3973
3974 /**
3975 * @param {HTMLElement | null} elem
3976 * @param {string} display
3977 */
3978 const show = (elem, display = 'flex') => {
3979 if (!elem) {
3980 return;
3981 }
3982 elem.style.display = display;
3983 };
3984
3985 /**
3986 * @param {HTMLElement | null} elem
3987 */
3988 const hide = elem => {
3989 if (!elem) {
3990 return;
3991 }
3992 elem.style.display = 'none';
3993 };
3994
3995 /**
3996 * @param {HTMLElement | null} elem
3997 * @param {string} display
3998 */
3999 const showWhenInnerHtmlPresent = (elem, display = 'block') => {
4000 if (!elem) {
4001 return;
4002 }
4003 new MutationObserver(() => {
4004 toggle(elem, elem.innerHTML, display);
4005 }).observe(elem, {
4006 childList: true,
4007 subtree: true
4008 });
4009 };
4010
4011 /**
4012 * @param {HTMLElement} parent
4013 * @param {string} selector
4014 * @param {string} property
4015 * @param {string} value
4016 */
4017 const setStyle = (parent, selector, property, value) => {
4018 /** @type {HTMLElement | null} */
4019 const el = parent.querySelector(selector);
4020 if (el) {
4021 el.style.setProperty(property, value);
4022 }
4023 };
4024
4025 /**
4026 * @param {HTMLElement} elem
4027 * @param {boolean | string | null | undefined} condition
4028 * @param {string} display
4029 */
4030 const toggle = (elem, condition, display = 'flex') => {
4031 if (condition) {
4032 show(elem, display);
4033 } else {
4034 hide(elem);
4035 }
4036 };
4037
4038 /**
4039 * borrowed from jquery $(elem).is(':visible') implementation
4040 *
4041 * @param {HTMLElement | null} elem
4042 * @returns {boolean}
4043 */
4044 const isVisible$1 = elem => Boolean(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length));
4045
4046 /**
4047 * @returns {boolean}
4048 */
4049 const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton());
4050
4051 /**
4052 * @param {HTMLElement} elem
4053 * @returns {boolean}
4054 */
4055 const isScrollable = elem => Boolean(elem.scrollHeight > elem.clientHeight);
4056
4057 /**
4058 * @param {HTMLElement} element
4059 * @param {HTMLElement} stopElement
4060 * @returns {boolean}
4061 */
4062 const selfOrParentIsScrollable = (element, stopElement) => {
4063 let parent = /** @type {HTMLElement | null} */element;
4064 while (parent && parent !== stopElement) {
4065 if (isScrollable(parent)) {
4066 return true;
4067 }
4068 parent = parent.parentElement;
4069 }
4070 return false;
4071 };
4072
4073 /**
4074 * borrowed from https://stackoverflow.com/a/46352119
4075 *
4076 * @param {HTMLElement} elem
4077 * @returns {boolean}
4078 */
4079 const hasCssAnimation = elem => {
4080 const style = window.getComputedStyle(elem);
4081 const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0');
4082 const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0');
4083 return animDuration > 0 || transDuration > 0;
4084 };
4085
4086 /**
4087 * @param {number} timer
4088 * @param {boolean} reset
4089 */
4090 const animateTimerProgressBar = (timer, reset = false) => {
4091 const timerProgressBar = getTimerProgressBar();
4092 if (!timerProgressBar) {
4093 return;
4094 }
4095 if (isVisible$1(timerProgressBar)) {
4096 if (reset) {
4097 timerProgressBar.style.transition = 'none';
4098 timerProgressBar.style.width = '100%';
4099 }
4100 setTimeout(() => {
4101 timerProgressBar.style.transition = `width ${timer / 1000}s linear`;
4102 timerProgressBar.style.width = '0%';
4103 }, 10);
4104 }
4105 };
4106 const stopTimerProgressBar = () => {
4107 const timerProgressBar = getTimerProgressBar();
4108 if (!timerProgressBar) {
4109 return;
4110 }
4111 const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4112 timerProgressBar.style.removeProperty('transition');
4113 timerProgressBar.style.width = '100%';
4114 const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4115 const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100;
4116 timerProgressBar.style.width = `${timerProgressBarPercent}%`;
4117 };
4118
4119 /**
4120 * Detect Node env
4121 *
4122 * @returns {boolean}
4123 */
4124 const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
4125
4126 const sweetHTML = `
4127 <div aria-labelledby="${swalClasses.title}" aria-describedby="${swalClasses['html-container']}" class="${swalClasses.popup}" tabindex="-1">
4128 <button type="button" class="${swalClasses.close}"></button>
4129 <ul class="${swalClasses['progress-steps']}"></ul>
4130 <div class="${swalClasses.icon}"></div>
4131 <img class="${swalClasses.image}" />
4132 <h2 class="${swalClasses.title}" id="${swalClasses.title}"></h2>
4133 <div class="${swalClasses['html-container']}" id="${swalClasses['html-container']}"></div>
4134 <input class="${swalClasses.input}" id="${swalClasses.input}" />
4135 <input type="file" class="${swalClasses.file}" />
4136 <div class="${swalClasses.range}">
4137 <input type="range" />
4138 <output></output>
4139 </div>
4140 <select class="${swalClasses.select}" id="${swalClasses.select}"></select>
4141 <div class="${swalClasses.radio}"></div>
4142 <label class="${swalClasses.checkbox}">
4143 <input type="checkbox" id="${swalClasses.checkbox}" />
4144 <span class="${swalClasses.label}"></span>
4145 </label>
4146 <textarea class="${swalClasses.textarea}" id="${swalClasses.textarea}"></textarea>
4147 <div class="${swalClasses['validation-message']}" id="${swalClasses['validation-message']}"></div>
4148 <div class="${swalClasses.actions}">
4149 <div class="${swalClasses.loader}"></div>
4150 <button type="button" class="${swalClasses.confirm}"></button>
4151 <button type="button" class="${swalClasses.deny}"></button>
4152 <button type="button" class="${swalClasses.cancel}"></button>
4153 </div>
4154 <div class="${swalClasses.footer}"></div>
4155 <div class="${swalClasses['timer-progress-bar-container']}">
4156 <div class="${swalClasses['timer-progress-bar']}"></div>
4157 </div>
4158 </div>
4159 `.replace(/(^|\n)\s*/g, '');
4160
4161 /**
4162 * @returns {boolean}
4163 */
4164 const resetOldContainer = () => {
4165 const oldContainer = getContainer();
4166 if (!oldContainer) {
4167 return false;
4168 }
4169 oldContainer.remove();
4170 removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'],
4171 // @ts-ignore: 'has-column' is not defined in swalClasses but may be set dynamically
4172 swalClasses['has-column']]);
4173 return true;
4174 };
4175 const resetValidationMessage$1 = () => {
4176 if (globalState.currentInstance) {
4177 globalState.currentInstance.resetValidationMessage();
4178 }
4179 };
4180 const addInputChangeListeners = () => {
4181 const popup = getPopup();
4182 if (!popup) {
4183 return;
4184 }
4185 const input = getDirectChildByClass(popup, swalClasses.input);
4186 const file = getDirectChildByClass(popup, swalClasses.file);
4187 /** @type {HTMLInputElement | null} */
4188 const range = popup.querySelector(`.${swalClasses.range} input`);
4189 /** @type {HTMLOutputElement | null} */
4190 const rangeOutput = popup.querySelector(`.${swalClasses.range} output`);
4191 const select = getDirectChildByClass(popup, swalClasses.select);
4192 /** @type {HTMLInputElement | null} */
4193 const checkbox = popup.querySelector(`.${swalClasses.checkbox} input`);
4194 const textarea = getDirectChildByClass(popup, swalClasses.textarea);
4195 if (input) {
4196 input.oninput = resetValidationMessage$1;
4197 }
4198 if (file) {
4199 file.onchange = resetValidationMessage$1;
4200 }
4201 if (select) {
4202 select.onchange = resetValidationMessage$1;
4203 }
4204 if (checkbox) {
4205 checkbox.onchange = resetValidationMessage$1;
4206 }
4207 if (textarea) {
4208 textarea.oninput = resetValidationMessage$1;
4209 }
4210 if (range && rangeOutput) {
4211 range.oninput = () => {
4212 resetValidationMessage$1();
4213 rangeOutput.value = range.value;
4214 };
4215 range.onchange = () => {
4216 resetValidationMessage$1();
4217 rangeOutput.value = range.value;
4218 };
4219 }
4220 };
4221
4222 /**
4223 * @param {string | HTMLElement} target
4224 * @returns {HTMLElement}
4225 */
4226 const getTarget = target => {
4227 if (typeof target === 'string') {
4228 const element = document.querySelector(target);
4229 if (!element) {
4230 throw new Error(`Target element "${target}" not found`);
4231 }
4232 return /** @type {HTMLElement} */element;
4233 }
4234 return target;
4235 };
4236
4237 /**
4238 * @param {SweetAlertOptions} params
4239 */
4240 const setupAccessibility = params => {
4241 const popup = getPopup();
4242 if (!popup) {
4243 return;
4244 }
4245 popup.setAttribute('role', params.toast ? 'alert' : 'dialog');
4246 popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive');
4247 if (!params.toast) {
4248 popup.setAttribute('aria-modal', 'true');
4249 }
4250 };
4251
4252 /**
4253 * @param {HTMLElement} targetElement
4254 */
4255 const setupRTL = targetElement => {
4256 if (window.getComputedStyle(targetElement).direction === 'rtl') {
4257 addClass(getContainer(), swalClasses.rtl);
4258 globalState.isRTL = true;
4259 }
4260 };
4261
4262 /**
4263 * Add modal + backdrop to DOM
4264 *
4265 * @param {SweetAlertOptions} params
4266 */
4267 const init = params => {
4268 // Clean up the old popup container if it exists
4269 const oldContainerExisted = resetOldContainer();
4270 if (isNodeEnv()) {
4271 error('SweetAlert2 requires document to initialize');
4272 return;
4273 }
4274 const container = document.createElement('div');
4275 container.className = swalClasses.container;
4276 if (oldContainerExisted) {
4277 addClass(container, swalClasses['no-transition']);
4278 }
4279 setInnerHtml(container, sweetHTML);
4280 container.dataset['swal2Theme'] = params.theme;
4281 const targetElement = getTarget(params.target || 'body');
4282 targetElement.appendChild(container);
4283 if (params.topLayer) {
4284 container.setAttribute('popover', '');
4285 container.showPopover();
4286 }
4287 setupAccessibility(params);
4288 setupRTL(targetElement);
4289 addInputChangeListeners();
4290 };
4291
4292 /**
4293 * @param {HTMLElement | object | string} param
4294 * @param {HTMLElement} target
4295 */
4296 const parseHtmlToContainer = (param, target) => {
4297 // DOM element
4298 if (param instanceof HTMLElement) {
4299 target.appendChild(param);
4300 }
4301
4302 // Object
4303 else if (typeof param === 'object') {
4304 handleObject(param, target);
4305 }
4306
4307 // Plain string
4308 else if (param) {
4309 setInnerHtml(target, param);
4310 }
4311 };
4312
4313 /**
4314 * @param {object} param
4315 * @param {HTMLElement} target
4316 */
4317 const handleObject = (param, target) => {
4318 // JQuery element(s)
4319 if ('jquery' in param) {
4320 handleJqueryElem(target, param);
4321 }
4322
4323 // For other objects use their string representation
4324 else {
4325 setInnerHtml(target, param.toString());
4326 }
4327 };
4328
4329 /**
4330 * @param {HTMLElement} target
4331 * @param {any} elem
4332 */
4333 const handleJqueryElem = (target, elem) => {
4334 target.textContent = '';
4335 if (0 in elem) {
4336 for (let i = 0; i in elem; i++) {
4337 target.appendChild(elem[i].cloneNode(true));
4338 }
4339 } else {
4340 target.appendChild(elem.cloneNode(true));
4341 }
4342 };
4343
4344 /**
4345 * @param {SweetAlert} instance
4346 * @param {SweetAlertOptions} params
4347 */
4348 const renderActions = (instance, params) => {
4349 const actions = getActions();
4350 const loader = getLoader();
4351 if (!actions || !loader) {
4352 return;
4353 }
4354
4355 // Actions (buttons) wrapper
4356 if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) {
4357 hide(actions);
4358 } else {
4359 show(actions);
4360 }
4361
4362 // Custom class
4363 applyCustomClass(actions, params, 'actions');
4364
4365 // Render all the buttons
4366 renderButtons(actions, loader, params);
4367
4368 // Loader
4369 setInnerHtml(loader, params.loaderHtml || '');
4370 applyCustomClass(loader, params, 'loader');
4371 };
4372
4373 /**
4374 * @param {HTMLElement} actions
4375 * @param {HTMLElement} loader
4376 * @param {SweetAlertOptions} params
4377 */
4378 function renderButtons(actions, loader, params) {
4379 const confirmButton = getConfirmButton();
4380 const denyButton = getDenyButton();
4381 const cancelButton = getCancelButton();
4382 if (!confirmButton || !denyButton || !cancelButton) {
4383 return;
4384 }
4385
4386 // Render buttons
4387 renderButton(confirmButton, 'confirm', params);
4388 renderButton(denyButton, 'deny', params);
4389 renderButton(cancelButton, 'cancel', params);
4390 handleButtonsStyling(confirmButton, denyButton, cancelButton, params);
4391 if (params.reverseButtons) {
4392 if (params.toast) {
4393 actions.insertBefore(cancelButton, confirmButton);
4394 actions.insertBefore(denyButton, confirmButton);
4395 } else {
4396 actions.insertBefore(cancelButton, loader);
4397 actions.insertBefore(denyButton, loader);
4398 actions.insertBefore(confirmButton, loader);
4399 }
4400 }
4401 }
4402
4403 /**
4404 * @param {HTMLElement} confirmButton
4405 * @param {HTMLElement} denyButton
4406 * @param {HTMLElement} cancelButton
4407 * @param {SweetAlertOptions} params
4408 */
4409 function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) {
4410 if (!params.buttonsStyling) {
4411 removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4412 return;
4413 }
4414 addClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4415
4416 // Apply custom background colors and outline colors to action buttons
4417 /** @type {[HTMLElement, string, string | undefined][]} */
4418 const buttons = [[confirmButton, 'confirm', params.confirmButtonColor], [denyButton, 'deny', params.denyButtonColor], [cancelButton, 'cancel', params.cancelButtonColor]];
4419 buttons.forEach(([button, type, color]) => {
4420 if (color) {
4421 button.style.setProperty(`--swal2-${type}-button-background-color`, color);
4422 }
4423 applyOutlineColor(button);
4424 });
4425 }
4426
4427 /**
4428 * @param {HTMLElement} button
4429 */
4430 function applyOutlineColor(button) {
4431 const buttonStyle = window.getComputedStyle(button);
4432 if (buttonStyle.getPropertyValue('--swal2-action-button-focus-box-shadow')) {
4433 // If the button already has a custom outline color, no need to change it
4434 return;
4435 }
4436 const outlineColor = buttonStyle.backgroundColor.replace(/rgba?\((\d+), (\d+), (\d+).*/, 'rgba($1, $2, $3, 0.5)');
4437 button.style.setProperty('--swal2-action-button-focus-box-shadow', buttonStyle.getPropertyValue('--swal2-outline').replace(/ rgba\(.*/, ` ${outlineColor}`));
4438 }
4439
4440 /**
4441 * @param {HTMLElement} button
4442 * @param {'confirm' | 'deny' | 'cancel'} buttonType
4443 * @param {SweetAlertOptions} params
4444 */
4445 function renderButton(button, buttonType, params) {
4446 const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType);
4447 toggle(button, params[`show${buttonName}Button`], 'inline-block');
4448 setInnerHtml(button, params[`${buttonType}ButtonText`] || ''); // Set caption text
4449 button.setAttribute('aria-label', params[`${buttonType}ButtonAriaLabel`] || ''); // ARIA label
4450
4451 // Add buttons custom classes
4452 button.className = swalClasses[buttonType];
4453 applyCustomClass(button, params, `${buttonType}Button`);
4454 }
4455
4456 /**
4457 * @param {SweetAlert} instance
4458 * @param {SweetAlertOptions} params
4459 */
4460 const renderCloseButton = (instance, params) => {
4461 const closeButton = getCloseButton();
4462 if (!closeButton) {
4463 return;
4464 }
4465 setInnerHtml(closeButton, params.closeButtonHtml || '');
4466
4467 // Custom class
4468 applyCustomClass(closeButton, params, 'closeButton');
4469 toggle(closeButton, params.showCloseButton);
4470 closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || '');
4471 };
4472
4473 /**
4474 * @param {SweetAlert} instance
4475 * @param {SweetAlertOptions} params
4476 */
4477 const renderContainer = (instance, params) => {
4478 const container = getContainer();
4479 if (!container) {
4480 return;
4481 }
4482 handleBackdropParam(container, params.backdrop);
4483 handlePositionParam(container, params.position);
4484 handleGrowParam(container, params.grow);
4485
4486 // Custom class
4487 applyCustomClass(container, params, 'container');
4488 };
4489
4490 /**
4491 * @param {HTMLElement} container
4492 * @param {SweetAlertOptions['backdrop']} backdrop
4493 */
4494 function handleBackdropParam(container, backdrop) {
4495 if (typeof backdrop === 'string') {
4496 container.style.background = backdrop;
4497 } else if (!backdrop) {
4498 addClass([document.documentElement, document.body], swalClasses['no-backdrop']);
4499 }
4500 }
4501
4502 /**
4503 * @param {HTMLElement} container
4504 * @param {SweetAlertOptions['position']} position
4505 */
4506 function handlePositionParam(container, position) {
4507 if (!position) {
4508 return;
4509 }
4510 if (position in swalClasses) {
4511 addClass(container, swalClasses[position]);
4512 } else {
4513 warn('The "position" parameter is not valid, defaulting to "center"');
4514 addClass(container, swalClasses.center);
4515 }
4516 }
4517
4518 /**
4519 * @param {HTMLElement} container
4520 * @param {SweetAlertOptions['grow']} grow
4521 */
4522 function handleGrowParam(container, grow) {
4523 if (!grow) {
4524 return;
4525 }
4526 addClass(container, swalClasses[`grow-${grow}`]);
4527 }
4528
4529 /**
4530 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
4531 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
4532 * This is the approach that Babel will probably take to implement private methods/fields
4533 * https://github.com/tc39/proposal-private-methods
4534 * https://github.com/babel/babel/pull/7555
4535 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
4536 * then we can use that language feature.
4537 */
4538
4539 var privateProps = {
4540 innerParams: new WeakMap(),
4541 domCache: new WeakMap(),
4542 focusedElement: new WeakMap()
4543 };
4544
4545 /// <reference path="../../../../sweetalert2.d.ts"/>
4546
4547
4548 /** @type {InputClass[]} */
4549 const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
4550
4551 /**
4552 * @param {SweetAlert} instance
4553 * @param {SweetAlertOptions} params
4554 */
4555 const renderInput = (instance, params) => {
4556 const popup = getPopup();
4557 if (!popup) {
4558 return;
4559 }
4560 const innerParams = privateProps.innerParams.get(instance);
4561 const rerender = !innerParams || params.input !== innerParams.input;
4562 inputClasses.forEach(inputClass => {
4563 const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]);
4564 if (!inputContainer) {
4565 return;
4566 }
4567
4568 // set attributes
4569 setAttributes(inputClass, params.inputAttributes);
4570
4571 // set class
4572 inputContainer.className = swalClasses[inputClass];
4573 if (rerender) {
4574 hide(inputContainer);
4575 }
4576 });
4577 if (params.input) {
4578 if (rerender) {
4579 showInput(params);
4580 }
4581 // set custom class
4582 setCustomClass(params);
4583 }
4584 };
4585
4586 /**
4587 * @param {SweetAlertOptions} params
4588 */
4589 const showInput = params => {
4590 if (!params.input) {
4591 return;
4592 }
4593 if (!renderInputType[params.input]) {
4594 error(`Unexpected type of input! Expected ${Object.keys(renderInputType).join(' | ')}, got "${params.input}"`);
4595 return;
4596 }
4597 const inputContainer = getInputContainer(params.input);
4598 if (!inputContainer) {
4599 return;
4600 }
4601 const input = renderInputType[params.input](inputContainer, params);
4602 show(inputContainer);
4603
4604 // input autofocus
4605 if (params.inputAutoFocus) {
4606 setTimeout(() => {
4607 focusInput(input);
4608 });
4609 }
4610 };
4611
4612 /**
4613 * @param {HTMLInputElement} input
4614 */
4615 const removeAttributes = input => {
4616 for (const {
4617 name
4618 } of Array.from(input.attributes)) {
4619 if (!['id', 'type', 'value', 'style'].includes(name)) {
4620 input.removeAttribute(name);
4621 }
4622 }
4623 };
4624
4625 /**
4626 * @param {InputClass} inputClass
4627 * @param {SweetAlertOptions['inputAttributes']} inputAttributes
4628 */
4629 const setAttributes = (inputClass, inputAttributes) => {
4630 const popup = getPopup();
4631 if (!popup) {
4632 return;
4633 }
4634 const input = getInput$1(popup, inputClass);
4635 if (!input) {
4636 return;
4637 }
4638 removeAttributes(input);
4639 for (const attr in inputAttributes) {
4640 input.setAttribute(attr, inputAttributes[attr]);
4641 }
4642 };
4643
4644 /**
4645 * @param {SweetAlertOptions} params
4646 */
4647 const setCustomClass = params => {
4648 if (!params.input) {
4649 return;
4650 }
4651 const inputContainer = getInputContainer(params.input);
4652 if (inputContainer) {
4653 applyCustomClass(inputContainer, params, 'input');
4654 }
4655 };
4656
4657 /**
4658 * @param {HTMLInputElement | HTMLTextAreaElement} input
4659 * @param {SweetAlertOptions} params
4660 */
4661 const setInputPlaceholder = (input, params) => {
4662 if (!input.placeholder && params.inputPlaceholder) {
4663 input.placeholder = params.inputPlaceholder;
4664 }
4665 };
4666
4667 /**
4668 * @param {Input} input
4669 * @param {Input} prependTo
4670 * @param {SweetAlertOptions} params
4671 */
4672 const setInputLabel = (input, prependTo, params) => {
4673 if (params.inputLabel) {
4674 const label = document.createElement('label');
4675 const labelClass = swalClasses['input-label'];
4676 label.setAttribute('for', input.id);
4677 label.className = labelClass;
4678 if (typeof params.customClass === 'object') {
4679 addClass(label, params.customClass.inputLabel);
4680 }
4681 label.innerText = params.inputLabel;
4682 prependTo.insertAdjacentElement('beforebegin', label);
4683 }
4684 };
4685
4686 /**
4687 * @param {SweetAlertInput} inputType
4688 * @returns {HTMLElement | undefined}
4689 */
4690 const getInputContainer = inputType => {
4691 const popup = getPopup();
4692 if (!popup) {
4693 return;
4694 }
4695 return getDirectChildByClass(popup, swalClasses[(/** @type {SwalClass} */inputType)] || swalClasses.input);
4696 };
4697
4698 /**
4699 * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input
4700 * @param {SweetAlertOptions['inputValue']} inputValue
4701 */
4702 const checkAndSetInputValue = (input, inputValue) => {
4703 if (['string', 'number'].includes(typeof inputValue)) {
4704 input.value = `${inputValue}`;
4705 } else if (!isPromise(inputValue)) {
4706 warn(`Unexpected type of inputValue! Expected "string", "number" or "Promise", got "${typeof inputValue}"`);
4707 }
4708 };
4709
4710 /** @type {Record<SweetAlertInput, (input: Input | HTMLElement, params: SweetAlertOptions) => Input>} */
4711 const renderInputType = {};
4712
4713 /**
4714 * @param {Input | HTMLElement} input
4715 * @param {SweetAlertOptions} params
4716 * @returns {Input}
4717 */
4718 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} */
4719 (input, params) => {
4720 // oxfmt-ignore
4721 const inputElement = /** @type {HTMLInputElement} */input;
4722 checkAndSetInputValue(inputElement, params.inputValue);
4723 setInputLabel(inputElement, inputElement, params);
4724 setInputPlaceholder(inputElement, params);
4725 // oxfmt-ignore
4726 inputElement.type = /** @type {string} */params.input;
4727 return inputElement;
4728 };
4729
4730 /**
4731 * @param {Input | HTMLElement} input
4732 * @param {SweetAlertOptions} params
4733 * @returns {Input}
4734 */
4735 renderInputType.file = (input, params) => {
4736 const inputElement = /** @type {HTMLInputElement} */input;
4737 setInputLabel(inputElement, inputElement, params);
4738 setInputPlaceholder(inputElement, params);
4739 return inputElement;
4740 };
4741
4742 /**
4743 * @param {Input | HTMLElement} range
4744 * @param {SweetAlertOptions} params
4745 * @returns {Input}
4746 */
4747 renderInputType.range = (range, params) => {
4748 const rangeContainer = /** @type {HTMLElement} */range;
4749 const rangeInput = rangeContainer.querySelector('input');
4750 const rangeOutput = rangeContainer.querySelector('output');
4751 if (rangeInput) {
4752 checkAndSetInputValue(rangeInput, params.inputValue);
4753 rangeInput.type = /** @type {string} */params.input;
4754 setInputLabel(rangeInput, /** @type {Input} */range, params);
4755 }
4756 if (rangeOutput) {
4757 checkAndSetInputValue(rangeOutput, params.inputValue);
4758 }
4759 return /** @type {Input} */range;
4760 };
4761
4762 /**
4763 * @param {Input | HTMLElement} select
4764 * @param {SweetAlertOptions} params
4765 * @returns {Input}
4766 */
4767 renderInputType.select = (select, params) => {
4768 const selectElement = /** @type {HTMLSelectElement} */select;
4769 selectElement.textContent = '';
4770 if (params.inputPlaceholder) {
4771 const placeholder = document.createElement('option');
4772 setInnerHtml(placeholder, params.inputPlaceholder);
4773 placeholder.value = '';
4774 placeholder.disabled = true;
4775 placeholder.selected = true;
4776 selectElement.appendChild(placeholder);
4777 }
4778 setInputLabel(selectElement, selectElement, params);
4779 return selectElement;
4780 };
4781
4782 /**
4783 * @param {Input | HTMLElement} radio
4784 * @returns {Input}
4785 */
4786 renderInputType.radio = radio => {
4787 const radioElement = /** @type {HTMLElement} */radio;
4788 radioElement.textContent = '';
4789 return /** @type {Input} */radio;
4790 };
4791
4792 /**
4793 * @param {Input | HTMLElement} checkboxContainer
4794 * @param {SweetAlertOptions} params
4795 * @returns {Input}
4796 */
4797 renderInputType.checkbox = (checkboxContainer, params) => {
4798 const popup = getPopup();
4799 if (!popup) {
4800 throw new Error('Popup not found');
4801 }
4802 const checkbox = getInput$1(popup, 'checkbox');
4803 if (!checkbox) {
4804 throw new Error('Checkbox input not found');
4805 }
4806 checkbox.value = '1';
4807 checkbox.checked = Boolean(params.inputValue);
4808 const containerElement = /** @type {HTMLElement} */checkboxContainer;
4809 const label = containerElement.querySelector('span');
4810 if (label) {
4811 const placeholderOrLabel = params.inputPlaceholder || params.inputLabel;
4812 if (placeholderOrLabel) {
4813 setInnerHtml(label, placeholderOrLabel);
4814 }
4815 }
4816 return checkbox;
4817 };
4818
4819 /**
4820 * @param {Input | HTMLElement} textarea
4821 * @param {SweetAlertOptions} params
4822 * @returns {Input}
4823 */
4824 renderInputType.textarea = (textarea, params) => {
4825 const textareaElement = /** @type {HTMLTextAreaElement} */textarea;
4826 checkAndSetInputValue(textareaElement, params.inputValue);
4827 setInputPlaceholder(textareaElement, params);
4828 setInputLabel(textareaElement, textareaElement, params);
4829
4830 /**
4831 * @param {HTMLElement} el
4832 * @returns {number}
4833 */
4834 const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight);
4835
4836 // https://github.com/sweetalert2/sweetalert2/issues/2291
4837 setTimeout(() => {
4838 // https://github.com/sweetalert2/sweetalert2/issues/1699
4839 if ('MutationObserver' in window) {
4840 const popup = getPopup();
4841 if (!popup) {
4842 return;
4843 }
4844 const initialPopupWidth = parseInt(window.getComputedStyle(popup).width);
4845 const textareaResizeHandler = () => {
4846 // check if texarea is still in document (i.e. popup wasn't closed in the meantime)
4847 if (!document.body.contains(textareaElement)) {
4848 return;
4849 }
4850 const textareaWidth = textareaElement.offsetWidth + getMargin(textareaElement);
4851 const popupElement = getPopup();
4852 if (popupElement) {
4853 if (textareaWidth > initialPopupWidth) {
4854 popupElement.style.width = `${textareaWidth}px`;
4855 } else {
4856 applyNumericalStyle(popupElement, 'width', params.width);
4857 }
4858 }
4859 };
4860 new MutationObserver(textareaResizeHandler).observe(textareaElement, {
4861 attributes: true,
4862 attributeFilter: ['style']
4863 });
4864 }
4865 });
4866 return textareaElement;
4867 };
4868
4869 /**
4870 * @param {SweetAlert} instance
4871 * @param {SweetAlertOptions} params
4872 */
4873 const renderContent = (instance, params) => {
4874 const htmlContainer = getHtmlContainer();
4875 if (!htmlContainer) {
4876 return;
4877 }
4878 showWhenInnerHtmlPresent(htmlContainer);
4879 applyCustomClass(htmlContainer, params, 'htmlContainer');
4880
4881 // Content as HTML
4882 if (params.html) {
4883 parseHtmlToContainer(params.html, htmlContainer);
4884 show(htmlContainer, 'block');
4885 }
4886
4887 // Content as plain text
4888 else if (params.text) {
4889 htmlContainer.textContent = params.text;
4890 show(htmlContainer, 'block');
4891 }
4892
4893 // No content
4894 else {
4895 hide(htmlContainer);
4896 }
4897 renderInput(instance, params);
4898 };
4899
4900 /**
4901 * @param {SweetAlert} instance
4902 * @param {SweetAlertOptions} params
4903 */
4904 const renderFooter = (instance, params) => {
4905 const footer = getFooter();
4906 if (!footer) {
4907 return;
4908 }
4909 showWhenInnerHtmlPresent(footer);
4910 toggle(footer, Boolean(params.footer), 'block');
4911 if (params.footer) {
4912 parseHtmlToContainer(params.footer, footer);
4913 }
4914
4915 // Custom class
4916 applyCustomClass(footer, params, 'footer');
4917 };
4918
4919 /**
4920 * @param {SweetAlert} instance
4921 * @param {SweetAlertOptions} params
4922 */
4923 const renderIcon = (instance, params) => {
4924 const innerParams = privateProps.innerParams.get(instance);
4925 const icon = getIcon();
4926 if (!icon) {
4927 return;
4928 }
4929
4930 // if the given icon already rendered, apply the styling without re-rendering the icon
4931 if (innerParams && params.icon === innerParams.icon) {
4932 // Custom or default content
4933 setContent(icon, params);
4934 applyStyles(icon, params);
4935 return;
4936 }
4937 if (!params.icon && !params.iconHtml) {
4938 hide(icon);
4939 return;
4940 }
4941 if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) {
4942 error(`Unknown icon! Expected "success", "error", "warning", "info" or "question", got "${params.icon}"`);
4943 hide(icon);
4944 return;
4945 }
4946 show(icon);
4947
4948 // Custom or default content
4949 setContent(icon, params);
4950 applyStyles(icon, params);
4951
4952 // Animate icon
4953 addClass(icon, params.showClass && params.showClass.icon);
4954
4955 // Re-adjust the success icon on system theme change
4956 const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
4957 colorSchemeQueryList.addEventListener('change', adjustSuccessIconBackgroundColor);
4958 };
4959
4960 /**
4961 * @param {HTMLElement} icon
4962 * @param {SweetAlertOptions} params
4963 */
4964 const applyStyles = (icon, params) => {
4965 for (const [iconType, iconClassName] of Object.entries(iconTypes)) {
4966 if (params.icon !== iconType) {
4967 removeClass(icon, iconClassName);
4968 }
4969 }
4970 addClass(icon, params.icon && iconTypes[params.icon]);
4971
4972 // Icon color
4973 setColor(icon, params);
4974
4975 // Success icon background color
4976 adjustSuccessIconBackgroundColor();
4977
4978 // Custom class
4979 applyCustomClass(icon, params, 'icon');
4980 };
4981
4982 // Adjust success icon background color to match the popup background color
4983 const adjustSuccessIconBackgroundColor = () => {
4984 const popup = getPopup();
4985 if (!popup) {
4986 return;
4987 }
4988 const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color');
4989 /** @type {NodeListOf<HTMLElement>} */
4990 const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix');
4991 successIconParts.forEach(part => {
4992 part.style.backgroundColor = popupBackgroundColor;
4993 });
4994 };
4995
4996 /**
4997 *
4998 * @param {SweetAlertOptions} params
4999 * @returns {string}
5000 */
5001 const successIconHtml = params => `
5002 ${params.animation ? '<div class="swal2-success-circular-line-left"></div>' : ''}
5003 <span class="swal2-success-line-tip"></span> <span class="swal2-success-line-long"></span>
5004 <div class="swal2-success-ring"></div>
5005 ${params.animation ? '<div class="swal2-success-fix"></div>' : ''}
5006 ${params.animation ? '<div class="swal2-success-circular-line-right"></div>' : ''}
5007 `;
5008 const errorIconHtml = `
5009 <span class="swal2-x-mark">
5010 <span class="swal2-x-mark-line-left"></span>
5011 <span class="swal2-x-mark-line-right"></span>
5012 </span>
5013 `;
5014
5015 /**
5016 * @param {HTMLElement} icon
5017 * @param {SweetAlertOptions} params
5018 */
5019 const setContent = (icon, params) => {
5020 if (!params.icon && !params.iconHtml) {
5021 return;
5022 }
5023 let oldContent = icon.innerHTML;
5024 let newContent = '';
5025 if (params.iconHtml) {
5026 newContent = iconContent(params.iconHtml);
5027 } else if (params.icon === 'success') {
5028 newContent = successIconHtml(params);
5029 oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor()
5030 } else if (params.icon === 'error') {
5031 newContent = errorIconHtml;
5032 } else if (params.icon) {
5033 const defaultIconHtml = {
5034 question: '?',
5035 warning: '!',
5036 info: 'i'
5037 };
5038 newContent = iconContent(defaultIconHtml[params.icon]);
5039 }
5040 if (oldContent.trim() !== newContent.trim()) {
5041 setInnerHtml(icon, newContent);
5042 }
5043 };
5044
5045 /**
5046 * @param {HTMLElement} icon
5047 * @param {SweetAlertOptions} params
5048 */
5049 const setColor = (icon, params) => {
5050 if (!params.iconColor) {
5051 return;
5052 }
5053 icon.style.color = params.iconColor;
5054 icon.style.borderColor = params.iconColor;
5055 for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) {
5056 setStyle(icon, sel, 'background-color', params.iconColor);
5057 }
5058 setStyle(icon, '.swal2-success-ring', 'border-color', params.iconColor);
5059 };
5060
5061 /**
5062 * @param {string} content
5063 * @returns {string}
5064 */
5065 const iconContent = content => `<div class="${swalClasses['icon-content']}">${content}</div>`;
5066
5067 /**
5068 * @param {SweetAlert} instance
5069 * @param {SweetAlertOptions} params
5070 */
5071 const renderImage = (instance, params) => {
5072 const image = getImage();
5073 if (!image) {
5074 return;
5075 }
5076 if (!params.imageUrl) {
5077 hide(image);
5078 return;
5079 }
5080 show(image, '');
5081
5082 // Src, alt
5083 image.setAttribute('src', params.imageUrl);
5084 image.setAttribute('alt', params.imageAlt || '');
5085
5086 // Width, height
5087 applyNumericalStyle(image, 'width', params.imageWidth);
5088 applyNumericalStyle(image, 'height', params.imageHeight);
5089
5090 // Class
5091 image.className = swalClasses.image;
5092 applyCustomClass(image, params, 'image');
5093 };
5094
5095 let dragging = false;
5096 let mousedownX = 0;
5097 let mousedownY = 0;
5098 let initialX = 0;
5099 let initialY = 0;
5100
5101 /**
5102 * @param {HTMLElement} popup
5103 */
5104 const addDraggableListeners = popup => {
5105 popup.addEventListener('mousedown', down);
5106 document.body.addEventListener('mousemove', move);
5107 popup.addEventListener('mouseup', up);
5108 popup.addEventListener('touchstart', down);
5109 document.body.addEventListener('touchmove', move);
5110 popup.addEventListener('touchend', up);
5111 };
5112
5113 /**
5114 * @param {HTMLElement} popup
5115 */
5116 const removeDraggableListeners = popup => {
5117 popup.removeEventListener('mousedown', down);
5118 document.body.removeEventListener('mousemove', move);
5119 popup.removeEventListener('mouseup', up);
5120 popup.removeEventListener('touchstart', down);
5121 document.body.removeEventListener('touchmove', move);
5122 popup.removeEventListener('touchend', up);
5123 };
5124
5125 /**
5126 * @param {MouseEvent | TouchEvent} event
5127 */
5128 const down = event => {
5129 const popup = getPopup();
5130 if (!popup) {
5131 return;
5132 }
5133 const icon = getIcon();
5134 if (event.target === popup || icon && icon.contains(/** @type {HTMLElement} */event.target)) {
5135 dragging = true;
5136 const clientXY = getClientXY(event);
5137 mousedownX = clientXY.clientX;
5138 mousedownY = clientXY.clientY;
5139 initialX = parseInt(popup.style.insetInlineStart) || 0;
5140 initialY = parseInt(popup.style.insetBlockStart) || 0;
5141 addClass(popup, 'swal2-dragging');
5142 }
5143 };
5144
5145 /**
5146 * @param {MouseEvent | TouchEvent} event
5147 */
5148 const move = event => {
5149 const popup = getPopup();
5150 if (!popup) {
5151 return;
5152 }
5153 if (dragging) {
5154 let {
5155 clientX,
5156 clientY
5157 } = getClientXY(event);
5158 const deltaX = clientX - mousedownX;
5159 // In RTL mode, negate the horizontal delta since insetInlineStart refers to the right edge
5160 popup.style.insetInlineStart = `${initialX + (globalState.isRTL ? -deltaX : deltaX)}px`;
5161 popup.style.insetBlockStart = `${initialY + (clientY - mousedownY)}px`;
5162 }
5163 };
5164 const up = () => {
5165 const popup = getPopup();
5166 dragging = false;
5167 removeClass(popup, 'swal2-dragging');
5168 };
5169
5170 /**
5171 * @param {MouseEvent | TouchEvent} event
5172 * @returns {{ clientX: number, clientY: number }}
5173 */
5174 const getClientXY = event => {
5175 const source = event.type.startsWith('touch') ? /** @type {TouchEvent} */event.touches[0] : (/** @type {MouseEvent} */event);
5176 return {
5177 clientX: source.clientX,
5178 clientY: source.clientY
5179 };
5180 };
5181
5182 /**
5183 * @param {SweetAlert} instance
5184 * @param {SweetAlertOptions} params
5185 */
5186 const renderPopup = (instance, params) => {
5187 const container = getContainer();
5188 const popup = getPopup();
5189 if (!container || !popup) {
5190 return;
5191 }
5192
5193 // Width
5194 // https://github.com/sweetalert2/sweetalert2/issues/2170
5195 if (params.toast) {
5196 applyNumericalStyle(container, 'width', params.width);
5197 popup.style.width = '100%';
5198 const loader = getLoader();
5199 if (loader) {
5200 popup.insertBefore(loader, getIcon());
5201 }
5202 } else {
5203 applyNumericalStyle(popup, 'width', params.width);
5204 }
5205
5206 // Padding
5207 applyNumericalStyle(popup, 'padding', params.padding);
5208
5209 // Color
5210 if (params.color) {
5211 popup.style.color = params.color;
5212 }
5213
5214 // Background
5215 if (params.background) {
5216 popup.style.background = params.background;
5217 }
5218 hide(getValidationMessage());
5219
5220 // Classes
5221 addClasses$1(popup, params);
5222 if (params.draggable && !params.toast) {
5223 addClass(popup, swalClasses.draggable);
5224 addDraggableListeners(popup);
5225 } else {
5226 removeClass(popup, swalClasses.draggable);
5227 removeDraggableListeners(popup);
5228 }
5229 };
5230
5231 /**
5232 * @param {HTMLElement} popup
5233 * @param {SweetAlertOptions} params
5234 */
5235 const addClasses$1 = (popup, params) => {
5236 const showClass = params.showClass || {};
5237 // Default Class + showClass when updating Swal.update({})
5238 popup.className = `${swalClasses.popup} ${isVisible$1(popup) ? showClass.popup : ''}`;
5239 if (params.toast) {
5240 addClass([document.documentElement, document.body], swalClasses['toast-shown']);
5241 addClass(popup, swalClasses.toast);
5242 } else {
5243 addClass(popup, swalClasses.modal);
5244 }
5245
5246 // Custom class
5247 applyCustomClass(popup, params, 'popup');
5248 // TODO: remove in the next major
5249 if (typeof params.customClass === 'string') {
5250 addClass(popup, params.customClass);
5251 }
5252
5253 // Icon class (#1842)
5254 if (params.icon) {
5255 addClass(popup, swalClasses[`icon-${params.icon}`]);
5256 }
5257 };
5258
5259 /**
5260 * @param {SweetAlert} instance
5261 * @param {SweetAlertOptions} params
5262 */
5263 const renderProgressSteps = (instance, params) => {
5264 const progressStepsContainer = getProgressSteps();
5265 if (!progressStepsContainer) {
5266 return;
5267 }
5268 const {
5269 progressSteps,
5270 currentProgressStep
5271 } = params;
5272 if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) {
5273 hide(progressStepsContainer);
5274 return;
5275 }
5276 show(progressStepsContainer);
5277 progressStepsContainer.textContent = '';
5278 if (currentProgressStep >= progressSteps.length) {
5279 warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)');
5280 }
5281 progressSteps.forEach((step, index) => {
5282 const stepEl = createStepElement(step);
5283 progressStepsContainer.appendChild(stepEl);
5284 if (index === currentProgressStep) {
5285 addClass(stepEl, swalClasses['active-progress-step']);
5286 }
5287 if (index !== progressSteps.length - 1) {
5288 const lineEl = createLineElement(params);
5289 progressStepsContainer.appendChild(lineEl);
5290 }
5291 });
5292 };
5293
5294 /**
5295 * @param {string} step
5296 * @returns {HTMLLIElement}
5297 */
5298 const createStepElement = step => {
5299 const stepEl = document.createElement('li');
5300 addClass(stepEl, swalClasses['progress-step']);
5301 setInnerHtml(stepEl, step);
5302 return stepEl;
5303 };
5304
5305 /**
5306 * @param {SweetAlertOptions} params
5307 * @returns {HTMLLIElement}
5308 */
5309 const createLineElement = params => {
5310 const lineEl = document.createElement('li');
5311 addClass(lineEl, swalClasses['progress-step-line']);
5312 if (params.progressStepsDistance) {
5313 applyNumericalStyle(lineEl, 'width', params.progressStepsDistance);
5314 }
5315 return lineEl;
5316 };
5317
5318 /**
5319 * @param {SweetAlert} instance
5320 * @param {SweetAlertOptions} params
5321 */
5322 const renderTitle = (instance, params) => {
5323 const title = getTitle();
5324 if (!title) {
5325 return;
5326 }
5327 showWhenInnerHtmlPresent(title);
5328 toggle(title, Boolean(params.title || params.titleText), 'block');
5329 if (params.title) {
5330 parseHtmlToContainer(params.title, title);
5331 }
5332 if (params.titleText) {
5333 title.innerText = params.titleText;
5334 }
5335
5336 // Custom class
5337 applyCustomClass(title, params, 'title');
5338 };
5339
5340 /**
5341 * @param {SweetAlert} instance
5342 * @param {SweetAlertOptions} params
5343 */
5344 const render = (instance, params) => {
5345 var _globalState$eventEmi;
5346 renderPopup(instance, params);
5347 renderContainer(instance, params);
5348 renderProgressSteps(instance, params);
5349 renderIcon(instance, params);
5350 renderImage(instance, params);
5351 renderTitle(instance, params);
5352 renderCloseButton(instance, params);
5353 renderContent(instance, params);
5354 renderActions(instance, params);
5355 renderFooter(instance, params);
5356 const popup = getPopup();
5357 if (typeof params.didRender === 'function' && popup) {
5358 params.didRender(popup);
5359 }
5360 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didRender', popup);
5361 };
5362
5363 /*
5364 * Global function to determine if SweetAlert2 popup is shown
5365 */
5366 const isVisible = () => {
5367 return isVisible$1(getPopup());
5368 };
5369
5370 /*
5371 * Global function to click 'Confirm' button
5372 */
5373 const clickConfirm = () => {
5374 var _dom$getConfirmButton;
5375 return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click();
5376 };
5377
5378 /*
5379 * Global function to click 'Deny' button
5380 */
5381 const clickDeny = () => {
5382 var _dom$getDenyButton;
5383 return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click();
5384 };
5385
5386 /*
5387 * Global function to click 'Cancel' button
5388 */
5389 const clickCancel = () => {
5390 var _dom$getCancelButton;
5391 return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click();
5392 };
5393
5394 /** @type {Record<DismissReason, DismissReason>} */
5395 const DismissReason = Object.freeze({
5396 cancel: 'cancel',
5397 backdrop: 'backdrop',
5398 close: 'close',
5399 esc: 'esc',
5400 timer: 'timer'
5401 });
5402
5403 /**
5404 * @param {GlobalState} globalState
5405 */
5406 const removeKeydownHandler = globalState => {
5407 if (globalState.keydownTarget && globalState.keydownHandlerAdded && globalState.keydownHandler) {
5408 const handler = /** @type {EventListenerOrEventListenerObject} */
5409 /** @type {unknown} */globalState.keydownHandler;
5410 globalState.keydownTarget.removeEventListener('keydown', handler, {
5411 capture: globalState.keydownListenerCapture
5412 });
5413 globalState.keydownHandlerAdded = false;
5414 }
5415 };
5416
5417 /**
5418 * @param {GlobalState} globalState
5419 * @param {SweetAlertOptions} innerParams
5420 * @param {(dismiss: DismissReason) => void} dismissWith
5421 */
5422 const addKeydownHandler = (globalState, innerParams, dismissWith) => {
5423 removeKeydownHandler(globalState);
5424 if (!innerParams.toast) {
5425 /** @type {(this: HTMLElement, event: KeyboardEvent) => void} */
5426 const handler = e => keydownHandler(innerParams, e, dismissWith);
5427 globalState.keydownHandler = handler;
5428 const target = innerParams.keydownListenerCapture ? window : getPopup();
5429 if (target) {
5430 globalState.keydownTarget = target;
5431 globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
5432 const eventHandler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */handler;
5433 globalState.keydownTarget.addEventListener('keydown', eventHandler, {
5434 capture: globalState.keydownListenerCapture
5435 });
5436 globalState.keydownHandlerAdded = true;
5437 }
5438 }
5439 };
5440
5441 /**
5442 * @param {number} index
5443 * @param {number} increment
5444 * @returns {boolean} shouldPreventDefault
5445 */
5446 const setFocus = (index, increment) => {
5447 var _dom$getPopup;
5448 const focusableElements = getFocusableElements();
5449 // search for visible elements and select the next possible match
5450 if (focusableElements.length) {
5451 index = index + increment;
5452
5453 // shift + tab when .swal2-popup is focused
5454 if (index === -2) {
5455 index = focusableElements.length - 1;
5456 }
5457
5458 // rollover to first item
5459 if (index === focusableElements.length) {
5460 index = 0;
5461
5462 // go to last item
5463 } else if (index === -1) {
5464 index = focusableElements.length - 1;
5465 }
5466 focusableElements[index].focus();
5467
5468 // don't prevent default for iframes (Firefox fix)
5469 // https://github.com/sweetalert2/sweetalert2/issues/2931
5470 if (isFirefox() && focusableElements[index] instanceof HTMLIFrameElement) {
5471 return false;
5472 }
5473 return true;
5474 }
5475 // no visible focusable elements, focus the popup
5476 (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus();
5477 return true;
5478 };
5479 const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
5480 const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
5481
5482 /**
5483 * @param {SweetAlertOptions} innerParams
5484 * @param {KeyboardEvent} event
5485 * @param {(dismiss: DismissReason) => void} dismissWith
5486 */
5487 const keydownHandler = (innerParams, event, dismissWith) => {
5488 if (!innerParams) {
5489 return; // This instance has already been destroyed
5490 }
5491
5492 // Ignore keydown during IME composition
5493 // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
5494 // https://github.com/sweetalert2/sweetalert2/issues/720
5495 // https://github.com/sweetalert2/sweetalert2/issues/2406
5496 if (event.isComposing || event.keyCode === 229) {
5497 return;
5498 }
5499 if (innerParams.stopKeydownPropagation) {
5500 event.stopPropagation();
5501 }
5502
5503 // ENTER
5504 if (event.key === 'Enter') {
5505 handleEnter(event, innerParams);
5506 }
5507
5508 // TAB
5509 else if (event.key === 'Tab') {
5510 handleTab(event);
5511 }
5512
5513 // ARROWS - switch focus between buttons
5514 else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) {
5515 handleArrows(event.key);
5516 }
5517
5518 // ESC
5519 else if (event.key === 'Escape') {
5520 handleEsc(event, innerParams, dismissWith);
5521 }
5522 };
5523
5524 /**
5525 * @param {KeyboardEvent} event
5526 * @param {SweetAlertOptions} innerParams
5527 */
5528 const handleEnter = (event, innerParams) => {
5529 // https://github.com/sweetalert2/sweetalert2/issues/2386
5530 if (!callIfFunction(innerParams.allowEnterKey)) {
5531 return;
5532 }
5533 const popup = getPopup();
5534 if (!popup || !innerParams.input) {
5535 return;
5536 }
5537 const input = getInput$1(popup, innerParams.input);
5538 if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) {
5539 if (['textarea', 'file'].includes(innerParams.input)) {
5540 return; // do not submit
5541 }
5542 clickConfirm();
5543 event.preventDefault();
5544 }
5545 };
5546
5547 /**
5548 * @param {KeyboardEvent} event
5549 */
5550 const handleTab = event => {
5551 const targetElement = event.target;
5552 const focusableElements = getFocusableElements();
5553 const btnIndex = focusableElements.findIndex(el => el === targetElement);
5554
5555 // don't prevent default for iframes (Firefox fix)
5556 // https://github.com/sweetalert2/sweetalert2/issues/2931
5557 let shouldPreventDefault = true;
5558
5559 // Cycle to the next button
5560 if (!event.shiftKey) {
5561 shouldPreventDefault = setFocus(btnIndex, 1);
5562 }
5563
5564 // Cycle to the prev button
5565 else {
5566 shouldPreventDefault = setFocus(btnIndex, -1);
5567 }
5568 event.stopPropagation();
5569 if (shouldPreventDefault) {
5570 event.preventDefault();
5571 }
5572 };
5573
5574 /**
5575 * @param {string} key
5576 */
5577 const handleArrows = key => {
5578 const actions = getActions();
5579 const confirmButton = getConfirmButton();
5580 const denyButton = getDenyButton();
5581 const cancelButton = getCancelButton();
5582 if (!actions || !confirmButton || !denyButton || !cancelButton) {
5583 return;
5584 }
5585 /** @type HTMLElement[] */
5586 const buttons = [confirmButton, denyButton, cancelButton];
5587 if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) {
5588 return;
5589 }
5590 const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
5591 let buttonToFocus = document.activeElement;
5592 if (!buttonToFocus) {
5593 return;
5594 }
5595 for (let i = 0; i < actions.children.length; i++) {
5596 buttonToFocus = buttonToFocus[sibling];
5597 if (!buttonToFocus) {
5598 return;
5599 }
5600 if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) {
5601 break;
5602 }
5603 }
5604 if (buttonToFocus instanceof HTMLButtonElement) {
5605 buttonToFocus.focus();
5606 }
5607 };
5608
5609 /**
5610 * @param {KeyboardEvent} event
5611 * @param {SweetAlertOptions} innerParams
5612 * @param {(dismiss: DismissReason) => void} dismissWith
5613 */
5614 const handleEsc = (event, innerParams, dismissWith) => {
5615 event.preventDefault();
5616 if (callIfFunction(innerParams.allowEscapeKey)) {
5617 dismissWith(DismissReason.esc);
5618 }
5619 };
5620
5621 /**
5622 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
5623 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
5624 * This is the approach that Babel will probably take to implement private methods/fields
5625 * https://github.com/tc39/proposal-private-methods
5626 * https://github.com/babel/babel/pull/7555
5627 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
5628 * then we can use that language feature.
5629 */
5630
5631 var privateMethods = {
5632 swalPromiseResolve: new WeakMap(),
5633 swalPromiseReject: new WeakMap()
5634 };
5635
5636 // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/
5637 // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
5638 // elements not within the active modal dialog will not be surfaced if a user opens a screen
5639 // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
5640
5641 const setAriaHidden = () => {
5642 const container = getContainer();
5643 const bodyChildren = Array.from(document.body.children);
5644 bodyChildren.forEach(el => {
5645 if (el.contains(container)) {
5646 return;
5647 }
5648 if (el.hasAttribute('aria-hidden')) {
5649 el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || '');
5650 }
5651 el.setAttribute('aria-hidden', 'true');
5652 });
5653 };
5654 const unsetAriaHidden = () => {
5655 const bodyChildren = Array.from(document.body.children);
5656 bodyChildren.forEach(el => {
5657 if (el.hasAttribute('data-previous-aria-hidden')) {
5658 el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || '');
5659 el.removeAttribute('data-previous-aria-hidden');
5660 } else {
5661 el.removeAttribute('aria-hidden');
5662 }
5663 });
5664 };
5665
5666 // @ts-ignore
5667 const isSafariOrIOS = typeof window !== 'undefined' && Boolean(window.GestureEvent); // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394
5668
5669 // @ts-ignore
5670 const isIOS = isSafariOrIOS && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
5671
5672 /**
5673 * Fix iOS scrolling
5674 * http://stackoverflow.com/q/39626302
5675 */
5676 const iOSfix = () => {
5677 if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) {
5678 const offset = document.body.scrollTop;
5679 document.body.style.top = `${offset * -1}px`;
5680 addClass(document.body, swalClasses.iosfix);
5681 lockBodyScroll();
5682 }
5683 };
5684
5685 /**
5686 * https://github.com/sweetalert2/sweetalert2/issues/1246
5687 */
5688 const lockBodyScroll = () => {
5689 const container = getContainer();
5690 if (!container) {
5691 return;
5692 }
5693 /** @type {boolean} */
5694 let preventTouchMove;
5695 /**
5696 * @param {TouchEvent} event
5697 */
5698 container.ontouchstart = event => {
5699 preventTouchMove = shouldPreventTouchMove(event);
5700 };
5701 /**
5702 * @param {TouchEvent} event
5703 */
5704 container.ontouchmove = event => {
5705 if (preventTouchMove) {
5706 event.preventDefault();
5707 event.stopPropagation();
5708 }
5709 };
5710 };
5711
5712 /**
5713 * @param {TouchEvent} event
5714 * @returns {boolean}
5715 */
5716 const shouldPreventTouchMove = event => {
5717 const target = event.target;
5718 const container = getContainer();
5719 const htmlContainer = getHtmlContainer();
5720 if (!container || !htmlContainer) {
5721 return false;
5722 }
5723 if (isStylus(event) || isZoom(event)) {
5724 return false;
5725 }
5726 if (target === container) {
5727 return true;
5728 }
5729 if (!isScrollable(container) && target instanceof HTMLElement && !selfOrParentIsScrollable(target, htmlContainer) &&
5730 // #2823
5731 target.tagName !== 'INPUT' &&
5732 // #1603
5733 target.tagName !== 'TEXTAREA' &&
5734 // #2266
5735 !(isScrollable(htmlContainer) &&
5736 // #1944
5737 htmlContainer.contains(target))) {
5738 return true;
5739 }
5740 return false;
5741 };
5742
5743 /**
5744 * https://github.com/sweetalert2/sweetalert2/issues/1786
5745 *
5746 * @param {TouchEvent} event
5747 * @returns {boolean}
5748 */
5749 const isStylus = event => {
5750 return Boolean(event.touches && event.touches.length &&
5751 // @ts-ignore - touchType is not a standard property
5752 event.touches[0].touchType === 'stylus');
5753 };
5754
5755 /**
5756 * https://github.com/sweetalert2/sweetalert2/issues/1891
5757 *
5758 * @param {TouchEvent} event
5759 * @returns {boolean}
5760 */
5761 const isZoom = event => {
5762 return event.touches && event.touches.length > 1;
5763 };
5764 const undoIOSfix = () => {
5765 if (hasClass(document.body, swalClasses.iosfix)) {
5766 const offset = parseInt(document.body.style.top, 10);
5767 removeClass(document.body, swalClasses.iosfix);
5768 document.body.style.top = '';
5769 document.body.scrollTop = offset * -1;
5770 }
5771 };
5772
5773 /**
5774 * Measure scrollbar width for padding body during modal show/hide
5775 * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js
5776 *
5777 * @returns {number}
5778 */
5779 const measureScrollbar = () => {
5780 const scrollDiv = document.createElement('div');
5781 scrollDiv.className = swalClasses['scrollbar-measure'];
5782 document.body.appendChild(scrollDiv);
5783 const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
5784 document.body.removeChild(scrollDiv);
5785 return scrollbarWidth;
5786 };
5787
5788 /**
5789 * Remember state in cases where opening and handling a modal will fiddle with it.
5790 * @type {number | null}
5791 */
5792 let previousBodyPadding = null;
5793
5794 /**
5795 * @param {string} initialBodyOverflow
5796 */
5797 const replaceScrollbarWithPadding = initialBodyOverflow => {
5798 // for queues, do not do this more than once
5799 if (previousBodyPadding !== null) {
5800 return;
5801 }
5802 // if the body has overflow
5803 if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663
5804 ) {
5805 // add padding so the content doesn't shift after removal of scrollbar
5806 previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
5807 document.body.style.paddingRight = `${previousBodyPadding + measureScrollbar()}px`;
5808 }
5809 };
5810 const undoReplaceScrollbarWithPadding = () => {
5811 if (previousBodyPadding !== null) {
5812 document.body.style.paddingRight = `${previousBodyPadding}px`;
5813 previousBodyPadding = null;
5814 }
5815 };
5816
5817 /**
5818 * @param {SweetAlert} instance
5819 * @param {HTMLElement} container
5820 * @param {boolean} returnFocus
5821 * @param {(() => void) | undefined} didClose
5822 */
5823 function removePopupAndResetState(instance, container, returnFocus, didClose) {
5824 if (isToast()) {
5825 triggerDidCloseAndDispose(instance, didClose);
5826 } else {
5827 restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
5828 removeKeydownHandler(globalState);
5829 }
5830
5831 // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088
5832 // for some reason removing the container in Safari will scroll the document to bottom
5833 if (isSafariOrIOS) {
5834 container.setAttribute('style', 'display:none !important');
5835 container.removeAttribute('class');
5836 container.innerHTML = '';
5837 } else {
5838 container.remove();
5839 }
5840 if (isModal()) {
5841 undoReplaceScrollbarWithPadding();
5842 undoIOSfix();
5843 unsetAriaHidden();
5844 }
5845 removeBodyClasses();
5846 }
5847
5848 /**
5849 * Remove SweetAlert2 classes from body
5850 */
5851 function removeBodyClasses() {
5852 removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
5853 }
5854
5855 /**
5856 * Instance method to close sweetAlert
5857 *
5858 * @param {SweetAlertResult | undefined} resolveValue
5859 * @this {SweetAlert}
5860 */
5861 function close(resolveValue) {
5862 resolveValue = prepareResolveValue(resolveValue);
5863 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
5864 const didClose = triggerClosePopup(this);
5865 if (this.isAwaitingPromise) {
5866 // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
5867 if (!resolveValue.isDismissed) {
5868 handleAwaitingPromise(this);
5869 swalPromiseResolve(resolveValue);
5870 }
5871 } else if (didClose) {
5872 // Resolve Swal promise
5873 swalPromiseResolve(resolveValue);
5874 }
5875 }
5876
5877 /**
5878 * @param {SweetAlert} instance
5879 * @returns {boolean}
5880 */
5881 const triggerClosePopup = instance => {
5882 const popup = getPopup();
5883 if (!popup) {
5884 return false;
5885 }
5886 const innerParams = privateProps.innerParams.get(instance);
5887 if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
5888 return false;
5889 }
5890 removeClass(popup, innerParams.showClass.popup);
5891 addClass(popup, innerParams.hideClass.popup);
5892 const backdrop = getContainer();
5893 removeClass(backdrop, innerParams.showClass.backdrop);
5894 addClass(backdrop, innerParams.hideClass.backdrop);
5895 handlePopupAnimation(instance, popup, innerParams);
5896 return true;
5897 };
5898
5899 /**
5900 * @param {Error | string} error
5901 * @this {SweetAlert}
5902 */
5903 function rejectPromise(error) {
5904 const rejectPromise = privateMethods.swalPromiseReject.get(this);
5905 handleAwaitingPromise(this);
5906 if (rejectPromise) {
5907 // Reject Swal promise
5908 rejectPromise(error);
5909 }
5910 }
5911
5912 /**
5913 * @param {SweetAlert} instance
5914 */
5915 const handleAwaitingPromise = instance => {
5916 if (instance.isAwaitingPromise) {
5917 // @ts-ignore
5918 delete instance.isAwaitingPromise;
5919 // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
5920 if (!privateProps.innerParams.get(instance)) {
5921 instance._destroy();
5922 }
5923 }
5924 };
5925
5926 /**
5927 * @param {SweetAlertResult | undefined} resolveValue
5928 * @returns {SweetAlertResult}
5929 */
5930 const prepareResolveValue = resolveValue => {
5931 // When user calls Swal.close()
5932 if (typeof resolveValue === 'undefined') {
5933 return {
5934 isConfirmed: false,
5935 isDenied: false,
5936 isDismissed: true
5937 };
5938 }
5939 return Object.assign({
5940 isConfirmed: false,
5941 isDenied: false,
5942 isDismissed: false
5943 }, resolveValue);
5944 };
5945
5946 /**
5947 * @param {SweetAlert} instance
5948 * @param {HTMLElement} popup
5949 * @param {SweetAlertOptions} innerParams
5950 */
5951 const handlePopupAnimation = (instance, popup, innerParams) => {
5952 var _globalState$eventEmi;
5953 const container = getContainer();
5954 // If animation is supported, animate
5955 const animationIsSupported = hasCssAnimation(popup);
5956 if (typeof innerParams.willClose === 'function') {
5957 innerParams.willClose(popup);
5958 }
5959 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willClose', popup);
5960 if (animationIsSupported && container) {
5961 animatePopup(instance, popup, container, Boolean(innerParams.returnFocus), innerParams.didClose);
5962 } else if (container) {
5963 // Otherwise, remove immediately
5964 removePopupAndResetState(instance, container, Boolean(innerParams.returnFocus), innerParams.didClose);
5965 }
5966 };
5967
5968 /**
5969 * @param {SweetAlert} instance
5970 * @param {HTMLElement} popup
5971 * @param {HTMLElement} container
5972 * @param {boolean} returnFocus
5973 * @param {(() => void) | undefined} didClose
5974 */
5975 const animatePopup = (instance, popup, container, returnFocus, didClose) => {
5976 globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
5977 /**
5978 * @param {AnimationEvent | TransitionEvent} e
5979 */
5980 const swalCloseAnimationFinished = function (e) {
5981 if (e.target === popup) {
5982 var _globalState$swalClos;
5983 (_globalState$swalClos = globalState.swalCloseEventFinishedCallback) === null || _globalState$swalClos === void 0 || _globalState$swalClos.call(globalState);
5984 delete globalState.swalCloseEventFinishedCallback;
5985 popup.removeEventListener('animationend', swalCloseAnimationFinished);
5986 popup.removeEventListener('transitionend', swalCloseAnimationFinished);
5987 }
5988 };
5989 popup.addEventListener('animationend', swalCloseAnimationFinished);
5990 popup.addEventListener('transitionend', swalCloseAnimationFinished);
5991 };
5992
5993 /**
5994 * @param {SweetAlert} instance
5995 * @param {(() => void) | undefined} didClose
5996 */
5997 const triggerDidCloseAndDispose = (instance, didClose) => {
5998 setTimeout(() => {
5999 var _globalState$eventEmi2;
6000 if (typeof didClose === 'function') {
6001 didClose.bind(instance.params)();
6002 }
6003 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didClose');
6004 // instance might have been destroyed already
6005 if (instance._destroy) {
6006 instance._destroy();
6007 }
6008 });
6009 };
6010
6011 /**
6012 * Shows loader (spinner), this is useful with AJAX requests.
6013 * By default the loader be shown instead of the "Confirm" button.
6014 *
6015 * @param {HTMLButtonElement | null} [buttonToReplace]
6016 */
6017 const showLoading = buttonToReplace => {
6018 let popup = getPopup();
6019 if (!popup) {
6020 new Swal();
6021 }
6022 popup = getPopup();
6023 if (!popup) {
6024 return;
6025 }
6026 const loader = getLoader();
6027 if (isToast()) {
6028 hide(getIcon());
6029 } else {
6030 replaceButton(popup, buttonToReplace);
6031 }
6032 show(loader);
6033 popup.setAttribute('data-loading', 'true');
6034 popup.setAttribute('aria-busy', 'true');
6035 popup.focus();
6036 };
6037
6038 /**
6039 * @param {HTMLElement} popup
6040 * @param {HTMLButtonElement | null} [buttonToReplace]
6041 */
6042 const replaceButton = (popup, buttonToReplace) => {
6043 const actions = getActions();
6044 const loader = getLoader();
6045 if (!actions || !loader) {
6046 return;
6047 }
6048 if (!buttonToReplace && isVisible$1(getConfirmButton())) {
6049 buttonToReplace = getConfirmButton();
6050 }
6051 show(actions);
6052 if (buttonToReplace) {
6053 hide(buttonToReplace);
6054 loader.setAttribute('data-button-to-replace', buttonToReplace.className);
6055 actions.insertBefore(loader, buttonToReplace);
6056 }
6057 addClass([popup, actions], swalClasses.loading);
6058 };
6059
6060 /**
6061 * @param {SweetAlert} instance
6062 * @param {SweetAlertOptions} params
6063 */
6064 const handleInputOptionsAndValue = (instance, params) => {
6065 if (params.input === 'select' || params.input === 'radio') {
6066 handleInputOptions(instance, params);
6067 } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
6068 showLoading(getConfirmButton());
6069 handleInputValue(instance, params);
6070 }
6071 };
6072
6073 /**
6074 * @param {SweetAlert} instance
6075 * @param {SweetAlertOptions} innerParams
6076 * @returns {SweetAlertInputValue}
6077 */
6078 const getInputValue = (instance, innerParams) => {
6079 const input = instance.getInput();
6080 if (!input) {
6081 return null;
6082 }
6083 switch (innerParams.input) {
6084 case 'checkbox':
6085 return getCheckboxValue(input);
6086 case 'radio':
6087 return getRadioValue(input);
6088 case 'file':
6089 return getFileValue(input);
6090 default:
6091 return innerParams.inputAutoTrim ? input.value.trim() : input.value;
6092 }
6093 };
6094
6095 /**
6096 * @param {HTMLInputElement} input
6097 * @returns {number}
6098 */
6099 const getCheckboxValue = input => input.checked ? 1 : 0;
6100
6101 /**
6102 * @param {HTMLInputElement} input
6103 * @returns {string | null}
6104 */
6105 const getRadioValue = input => input.checked ? input.value : null;
6106
6107 /**
6108 * @param {HTMLInputElement} input
6109 * @returns {FileList | File | null}
6110 */
6111 const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null;
6112
6113 /**
6114 * @param {SweetAlert} instance
6115 * @param {SweetAlertOptions} params
6116 */
6117 const handleInputOptions = (instance, params) => {
6118 const popup = getPopup();
6119 if (!popup) {
6120 return;
6121 }
6122 /**
6123 * @param {*} inputOptions
6124 */
6125 const processInputOptions = inputOptions => {
6126 if (params.input === 'select') {
6127 populateSelectOptions(popup, formatInputOptions(inputOptions), params);
6128 } else if (params.input === 'radio') {
6129 populateRadioOptions(popup, formatInputOptions(inputOptions), params);
6130 }
6131 };
6132 if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) {
6133 showLoading(getConfirmButton());
6134 asPromise(params.inputOptions).then(inputOptions => {
6135 instance.hideLoading();
6136 processInputOptions(inputOptions);
6137 });
6138 } else if (typeof params.inputOptions === 'object') {
6139 processInputOptions(params.inputOptions);
6140 } else {
6141 error(`Unexpected type of inputOptions! Expected object, Map or Promise, got ${typeof params.inputOptions}`);
6142 }
6143 };
6144
6145 /**
6146 * @param {SweetAlert} instance
6147 * @param {SweetAlertOptions} params
6148 */
6149 const handleInputValue = (instance, params) => {
6150 const input = instance.getInput();
6151 if (!input) {
6152 return;
6153 }
6154 hide(input);
6155 asPromise(params.inputValue).then(inputValue => {
6156 input.value = params.input === 'number' ? `${parseFloat(inputValue) || 0}` : `${inputValue}`;
6157 show(input);
6158 input.focus();
6159 instance.hideLoading();
6160 }).catch(err => {
6161 error(`Error in inputValue promise: ${err}`);
6162 input.value = '';
6163 show(input);
6164 input.focus();
6165 instance.hideLoading();
6166 });
6167 };
6168
6169 /**
6170 * @param {HTMLElement} popup
6171 * @param {InputOptionFlattened[]} inputOptions
6172 * @param {SweetAlertOptions} params
6173 */
6174 function populateSelectOptions(popup, inputOptions, params) {
6175 const select = getDirectChildByClass(popup, swalClasses.select);
6176 if (!select) {
6177 return;
6178 }
6179 /**
6180 * @param {HTMLElement} parent
6181 * @param {string} optionLabel
6182 * @param {string} optionValue
6183 */
6184 const renderOption = (parent, optionLabel, optionValue) => {
6185 const option = document.createElement('option');
6186 option.value = optionValue;
6187 setInnerHtml(option, optionLabel);
6188 option.selected = isSelected(optionValue, params.inputValue);
6189 parent.appendChild(option);
6190 };
6191 inputOptions.forEach(inputOption => {
6192 const optionValue = inputOption[0];
6193 const optionLabel = inputOption[1];
6194 // <optgroup> spec:
6195 // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
6196 // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
6197 // check whether this is a <optgroup>
6198 if (Array.isArray(optionLabel)) {
6199 // if it is an array, then it is an <optgroup>
6200 const optgroup = document.createElement('optgroup');
6201 optgroup.label = optionValue;
6202 optgroup.disabled = false; // not configurable for now
6203 select.appendChild(optgroup);
6204 optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
6205 } else {
6206 // case of <option>
6207 renderOption(select, optionLabel, optionValue);
6208 }
6209 });
6210 select.focus();
6211 }
6212
6213 /**
6214 * @param {HTMLElement} popup
6215 * @param {InputOptionFlattened[]} inputOptions
6216 * @param {SweetAlertOptions} params
6217 */
6218 function populateRadioOptions(popup, inputOptions, params) {
6219 const radio = getDirectChildByClass(popup, swalClasses.radio);
6220 if (!radio) {
6221 return;
6222 }
6223 inputOptions.forEach(inputOption => {
6224 const radioValue = inputOption[0];
6225 const radioLabel = inputOption[1];
6226 const radioInput = document.createElement('input');
6227 const radioLabelElement = document.createElement('label');
6228 radioInput.type = 'radio';
6229 radioInput.name = swalClasses.radio;
6230 radioInput.value = radioValue;
6231 if (isSelected(radioValue, params.inputValue)) {
6232 radioInput.checked = true;
6233 }
6234 const label = document.createElement('span');
6235 setInnerHtml(label, radioLabel);
6236 label.className = swalClasses.label;
6237 radioLabelElement.appendChild(radioInput);
6238 radioLabelElement.appendChild(label);
6239 radio.appendChild(radioLabelElement);
6240 });
6241 const radios = radio.querySelectorAll('input');
6242 if (radios.length) {
6243 radios[0].focus();
6244 }
6245 }
6246
6247 /**
6248 * Converts `inputOptions` into an array of `[value, label]`s
6249 *
6250 * @param {*} inputOptions
6251 * @typedef {string[]} InputOptionFlattened
6252 * @returns {InputOptionFlattened[]}
6253 */
6254 const formatInputOptions = inputOptions => {
6255 const entries = inputOptions instanceof Map ? Array.from(inputOptions) : Object.entries(inputOptions);
6256 return entries.map(([key, value]) => [key, typeof value === 'object' ? formatInputOptions(value) : value]); // case of <optgroup>
6257 };
6258
6259 /**
6260 * @param {string} optionValue
6261 * @param {SweetAlertInputValue} inputValue
6262 * @returns {boolean}
6263 */
6264 const isSelected = (optionValue, inputValue) => Boolean(inputValue) && inputValue != null && inputValue.toString() === optionValue.toString();
6265
6266 /**
6267 * @param {SweetAlert} instance
6268 */
6269 const handleConfirmButtonClick = instance => {
6270 const innerParams = privateProps.innerParams.get(instance);
6271 instance.disableButtons();
6272 if (innerParams.input) {
6273 handleConfirmOrDenyWithInput(instance, 'confirm');
6274 } else {
6275 confirm(instance, true);
6276 }
6277 };
6278
6279 /**
6280 * @param {SweetAlert} instance
6281 */
6282 const handleDenyButtonClick = instance => {
6283 const innerParams = privateProps.innerParams.get(instance);
6284 instance.disableButtons();
6285 if (innerParams.returnInputValueOnDeny) {
6286 handleConfirmOrDenyWithInput(instance, 'deny');
6287 } else {
6288 deny(instance, false);
6289 }
6290 };
6291
6292 /**
6293 * @param {SweetAlert} instance
6294 * @param {(dismiss: DismissReason) => void} dismissWith
6295 */
6296 const handleCancelButtonClick = (instance, dismissWith) => {
6297 instance.disableButtons();
6298 dismissWith(DismissReason.cancel);
6299 };
6300
6301 /**
6302 * @param {SweetAlert} instance
6303 * @param {'confirm' | 'deny'} type
6304 */
6305 const handleConfirmOrDenyWithInput = (instance, type) => {
6306 const innerParams = privateProps.innerParams.get(instance);
6307 if (!innerParams.input) {
6308 error(`The "input" parameter is needed to be set when using returnInputValueOn${capitalizeFirstLetter(type)}`);
6309 return;
6310 }
6311 const input = instance.getInput();
6312 const inputValue = getInputValue(instance, innerParams);
6313 if (innerParams.inputValidator) {
6314 handleInputValidator(instance, inputValue, type);
6315 } else if (input && !input.checkValidity()) {
6316 instance.enableButtons();
6317 instance.showValidationMessage(innerParams.validationMessage || input.validationMessage);
6318 } else if (type === 'deny') {
6319 deny(instance, inputValue);
6320 } else {
6321 confirm(instance, inputValue);
6322 }
6323 };
6324
6325 /**
6326 * @param {SweetAlert} instance
6327 * @param {SweetAlertInputValue} inputValue
6328 * @param {'confirm' | 'deny'} type
6329 */
6330 const handleInputValidator = (instance, inputValue, type) => {
6331 const innerParams = privateProps.innerParams.get(instance);
6332 instance.disableInput();
6333 const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
6334 validationPromise.then(validationMessage => {
6335 instance.enableButtons();
6336 instance.enableInput();
6337 if (validationMessage) {
6338 instance.showValidationMessage(validationMessage);
6339 } else if (type === 'deny') {
6340 deny(instance, inputValue);
6341 } else {
6342 confirm(instance, inputValue);
6343 }
6344 });
6345 };
6346
6347 /**
6348 * @param {SweetAlert} instance
6349 * @param {*} value
6350 */
6351 const deny = (instance, value) => {
6352 const innerParams = privateProps.innerParams.get(instance);
6353 if (innerParams.showLoaderOnDeny) {
6354 showLoading(getDenyButton());
6355 }
6356 if (innerParams.preDeny) {
6357 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
6358 const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
6359 preDenyPromise.then(preDenyValue => {
6360 if (preDenyValue === false) {
6361 instance.hideLoading();
6362 handleAwaitingPromise(instance);
6363 } else {
6364 instance.close(/** @type SweetAlertResult */{
6365 isDenied: true,
6366 value: typeof preDenyValue === 'undefined' ? value : preDenyValue
6367 });
6368 }
6369 }).catch(error => rejectWith(instance, error));
6370 } else {
6371 instance.close(/** @type SweetAlertResult */{
6372 isDenied: true,
6373 value
6374 });
6375 }
6376 };
6377
6378 /**
6379 * @param {SweetAlert} instance
6380 * @param {*} value
6381 */
6382 const succeedWith = (instance, value) => {
6383 instance.close(/** @type SweetAlertResult */{
6384 isConfirmed: true,
6385 value
6386 });
6387 };
6388
6389 /**
6390 *
6391 * @param {SweetAlert} instance
6392 * @param {string} error
6393 */
6394 const rejectWith = (instance, error) => {
6395 instance.rejectPromise(error);
6396 };
6397
6398 /**
6399 *
6400 * @param {SweetAlert} instance
6401 * @param {*} value
6402 */
6403 const confirm = (instance, value) => {
6404 const innerParams = privateProps.innerParams.get(instance);
6405 if (innerParams.showLoaderOnConfirm) {
6406 showLoading();
6407 }
6408 if (innerParams.preConfirm) {
6409 instance.resetValidationMessage();
6410 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
6411 const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
6412 preConfirmPromise.then(preConfirmValue => {
6413 if (isVisible$1(getValidationMessage()) || preConfirmValue === false) {
6414 instance.hideLoading();
6415 handleAwaitingPromise(instance);
6416 } else {
6417 succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
6418 }
6419 }).catch(error => rejectWith(instance, error));
6420 } else {
6421 succeedWith(instance, value);
6422 }
6423 };
6424
6425 /**
6426 * Hides loader and shows back the button which was hidden by .showLoading()
6427 * @this {SweetAlert}
6428 */
6429 function hideLoading() {
6430 // do nothing if popup is closed
6431 const innerParams = privateProps.innerParams.get(this);
6432 if (!innerParams) {
6433 return;
6434 }
6435 const domCache = privateProps.domCache.get(this);
6436 hide(domCache.loader);
6437 if (isToast()) {
6438 if (innerParams.icon) {
6439 show(getIcon());
6440 }
6441 } else {
6442 showRelatedButton(domCache);
6443 }
6444 removeClass([domCache.popup, domCache.actions], swalClasses.loading);
6445 domCache.popup.removeAttribute('aria-busy');
6446 domCache.popup.removeAttribute('data-loading');
6447 this.enableButtons();
6448 }
6449
6450 /**
6451 * @param {DomCache} domCache
6452 */
6453 const showRelatedButton = domCache => {
6454 const dataButtonToReplace = domCache.loader.getAttribute('data-button-to-replace');
6455 const buttonToReplace = dataButtonToReplace ? domCache.popup.getElementsByClassName(dataButtonToReplace) : [];
6456 if (buttonToReplace.length) {
6457 show(/** @type {HTMLElement} */buttonToReplace[0], 'inline-block');
6458 } else if (allButtonsAreHidden()) {
6459 hide(domCache.actions);
6460 }
6461 };
6462
6463 /**
6464 * Gets the input DOM node, this method works with input parameter.
6465 *
6466 * @returns {HTMLInputElement | null}
6467 * @this {SweetAlert}
6468 */
6469 function getInput() {
6470 const innerParams = privateProps.innerParams.get(this);
6471 const domCache = privateProps.domCache.get(this);
6472 if (!domCache) {
6473 return null;
6474 }
6475 return getInput$1(domCache.popup, innerParams.input);
6476 }
6477
6478 /**
6479 * @param {SweetAlert} instance
6480 * @param {string[]} buttons
6481 * @param {boolean} disabled
6482 */
6483 function setButtonsDisabled(instance, buttons, disabled) {
6484 const domCache = privateProps.domCache.get(instance);
6485 buttons.forEach(button => {
6486 domCache[button].disabled = disabled;
6487 });
6488 }
6489
6490 /**
6491 * @param {HTMLInputElement | null} input
6492 * @param {boolean} disabled
6493 */
6494 function setInputDisabled(input, disabled) {
6495 const popup = getPopup();
6496 if (!popup || !input) {
6497 return;
6498 }
6499 if (input.type === 'radio') {
6500 /** @type {NodeListOf<HTMLInputElement>} */
6501 const radios = popup.querySelectorAll(`[name="${swalClasses.radio}"]`);
6502 radios.forEach(radio => {
6503 radio.disabled = disabled;
6504 });
6505 } else {
6506 input.disabled = disabled;
6507 }
6508 }
6509
6510 /**
6511 * Enable all the buttons
6512 * @this {SweetAlert}
6513 */
6514 function enableButtons() {
6515 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
6516 const focusedElement = privateProps.focusedElement.get(this);
6517 if (focusedElement instanceof HTMLElement && document.activeElement === document.body) {
6518 focusedElement.focus();
6519 }
6520 privateProps.focusedElement.delete(this);
6521 }
6522
6523 /**
6524 * Disable all the buttons
6525 * @this {SweetAlert}
6526 */
6527 function disableButtons() {
6528 privateProps.focusedElement.set(this, document.activeElement);
6529 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
6530 }
6531
6532 /**
6533 * Enable the input field
6534 * @this {SweetAlert}
6535 */
6536 function enableInput() {
6537 setInputDisabled(this.getInput(), false);
6538 }
6539
6540 /**
6541 * Disable the input field
6542 * @this {SweetAlert}
6543 */
6544 function disableInput() {
6545 setInputDisabled(this.getInput(), true);
6546 }
6547
6548 /**
6549 * Show block with validation message
6550 *
6551 * @param {string} error
6552 * @this {SweetAlert}
6553 */
6554 function showValidationMessage(error) {
6555 const domCache = privateProps.domCache.get(this);
6556 const params = privateProps.innerParams.get(this);
6557 setInnerHtml(domCache.validationMessage, error);
6558 domCache.validationMessage.className = swalClasses['validation-message'];
6559 if (params.customClass && params.customClass.validationMessage) {
6560 addClass(domCache.validationMessage, params.customClass.validationMessage);
6561 }
6562 show(domCache.validationMessage);
6563 const input = this.getInput();
6564 if (input) {
6565 input.setAttribute('aria-invalid', 'true');
6566 input.setAttribute('aria-describedby', swalClasses['validation-message']);
6567 focusInput(input);
6568 addClass(input, swalClasses.inputerror);
6569 }
6570 }
6571
6572 /**
6573 * Hide block with validation message
6574 *
6575 * @this {SweetAlert}
6576 */
6577 function resetValidationMessage() {
6578 const domCache = privateProps.domCache.get(this);
6579 if (domCache.validationMessage) {
6580 hide(domCache.validationMessage);
6581 }
6582 const input = this.getInput();
6583 if (input) {
6584 input.removeAttribute('aria-invalid');
6585 input.removeAttribute('aria-describedby');
6586 removeClass(input, swalClasses.inputerror);
6587 }
6588 }
6589
6590 const defaultParams = {
6591 title: '',
6592 titleText: '',
6593 text: '',
6594 html: '',
6595 footer: '',
6596 icon: undefined,
6597 iconColor: undefined,
6598 iconHtml: undefined,
6599 template: undefined,
6600 toast: false,
6601 draggable: false,
6602 animation: true,
6603 theme: 'light',
6604 showClass: {
6605 popup: 'swal2-show',
6606 backdrop: 'swal2-backdrop-show',
6607 icon: 'swal2-icon-show'
6608 },
6609 hideClass: {
6610 popup: 'swal2-hide',
6611 backdrop: 'swal2-backdrop-hide',
6612 icon: 'swal2-icon-hide'
6613 },
6614 customClass: {},
6615 target: 'body',
6616 color: undefined,
6617 backdrop: true,
6618 heightAuto: true,
6619 allowOutsideClick: true,
6620 allowEscapeKey: true,
6621 allowEnterKey: true,
6622 stopKeydownPropagation: true,
6623 keydownListenerCapture: false,
6624 showConfirmButton: true,
6625 showDenyButton: false,
6626 showCancelButton: false,
6627 preConfirm: undefined,
6628 preDeny: undefined,
6629 confirmButtonText: 'OK',
6630 confirmButtonAriaLabel: '',
6631 confirmButtonColor: undefined,
6632 denyButtonText: 'No',
6633 denyButtonAriaLabel: '',
6634 denyButtonColor: undefined,
6635 cancelButtonText: 'Cancel',
6636 cancelButtonAriaLabel: '',
6637 cancelButtonColor: undefined,
6638 buttonsStyling: true,
6639 reverseButtons: false,
6640 focusConfirm: true,
6641 focusDeny: false,
6642 focusCancel: false,
6643 returnFocus: true,
6644 showCloseButton: false,
6645 closeButtonHtml: '&times;',
6646 closeButtonAriaLabel: 'Close this dialog',
6647 loaderHtml: '',
6648 showLoaderOnConfirm: false,
6649 showLoaderOnDeny: false,
6650 imageUrl: undefined,
6651 imageWidth: undefined,
6652 imageHeight: undefined,
6653 imageAlt: '',
6654 timer: undefined,
6655 timerProgressBar: false,
6656 width: undefined,
6657 padding: undefined,
6658 background: undefined,
6659 input: undefined,
6660 inputPlaceholder: '',
6661 inputLabel: '',
6662 inputValue: '',
6663 inputOptions: {},
6664 inputAutoFocus: true,
6665 inputAutoTrim: true,
6666 inputAttributes: {},
6667 inputValidator: undefined,
6668 returnInputValueOnDeny: false,
6669 validationMessage: undefined,
6670 grow: false,
6671 position: 'center',
6672 progressSteps: [],
6673 currentProgressStep: undefined,
6674 progressStepsDistance: undefined,
6675 willOpen: undefined,
6676 didOpen: undefined,
6677 didRender: undefined,
6678 willClose: undefined,
6679 didClose: undefined,
6680 didDestroy: undefined,
6681 scrollbarPadding: true,
6682 topLayer: false
6683 };
6684 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'];
6685
6686 /** @type {Record<string, string | undefined>} */
6687 const deprecatedParams = {
6688 allowEnterKey: undefined
6689 };
6690 const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'draggable', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
6691
6692 /**
6693 * Is valid parameter
6694 *
6695 * @param {string} paramName
6696 * @returns {boolean}
6697 */
6698 const isValidParameter = paramName => {
6699 return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
6700 };
6701
6702 /**
6703 * Is valid parameter for Swal.update() method
6704 *
6705 * @param {string} paramName
6706 * @returns {boolean}
6707 */
6708 const isUpdatableParameter = paramName => {
6709 return updatableParams.indexOf(paramName) !== -1;
6710 };
6711
6712 /**
6713 * Is deprecated parameter
6714 *
6715 * @param {string} paramName
6716 * @returns {string | undefined}
6717 */
6718 const isDeprecatedParameter = paramName => {
6719 return deprecatedParams[paramName];
6720 };
6721
6722 /**
6723 * @param {string} param
6724 */
6725 const checkIfParamIsValid = param => {
6726 if (!isValidParameter(param)) {
6727 warn(`Unknown parameter "${param}"`);
6728 }
6729 };
6730
6731 /**
6732 * @param {string} param
6733 */
6734 const checkIfToastParamIsValid = param => {
6735 if (toastIncompatibleParams.includes(param)) {
6736 warn(`The parameter "${param}" is incompatible with toasts`);
6737 }
6738 };
6739
6740 /**
6741 * @param {string} param
6742 */
6743 const checkIfParamIsDeprecated = param => {
6744 const isDeprecated = isDeprecatedParameter(param);
6745 if (isDeprecated) {
6746 warnAboutDeprecation(param, isDeprecated);
6747 }
6748 };
6749
6750 /**
6751 * Show relevant warnings for given params
6752 *
6753 * @param {SweetAlertOptions} params
6754 */
6755 const showWarningsForParams = params => {
6756 if (params.backdrop === false && params.allowOutsideClick) {
6757 warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
6758 }
6759 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)) {
6760 warn(`Invalid theme "${params.theme}"`);
6761 }
6762 for (const param in params) {
6763 checkIfParamIsValid(param);
6764 if (params.toast) {
6765 checkIfToastParamIsValid(param);
6766 }
6767 checkIfParamIsDeprecated(param);
6768 }
6769 };
6770
6771 /**
6772 * Updates popup parameters.
6773 *
6774 * @this {any}
6775 * @param {SweetAlertOptions} params
6776 */
6777 function update(params) {
6778 const container = getContainer();
6779 const popup = getPopup();
6780 const innerParams = privateProps.innerParams.get(this);
6781 if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
6782 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.`);
6783 return;
6784 }
6785 const validUpdatableParams = filterValidParams(params);
6786 const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
6787 showWarningsForParams(updatedParams);
6788 if (container) {
6789 container.dataset['swal2Theme'] = updatedParams.theme;
6790 }
6791 render(this, updatedParams);
6792 privateProps.innerParams.set(this, updatedParams);
6793 Object.defineProperties(this, {
6794 params: {
6795 value: Object.assign({}, this.params, params),
6796 writable: false,
6797 enumerable: true
6798 }
6799 });
6800 }
6801
6802 /**
6803 * @param {SweetAlertOptions} params
6804 * @returns {SweetAlertOptions}
6805 */
6806 const filterValidParams = params => {
6807 /** @type {Record<string, any>} */
6808 const validUpdatableParams = {};
6809 Object.keys(params).forEach(param => {
6810 if (isUpdatableParameter(param)) {
6811 const typedParams = /** @type {Record<string, any>} */params;
6812 validUpdatableParams[param] = typedParams[param];
6813 } else {
6814 warn(`Invalid parameter to update: ${param}`);
6815 }
6816 });
6817 return validUpdatableParams;
6818 };
6819
6820 /**
6821 * Dispose the current SweetAlert2 instance
6822 * @this {SweetAlert}
6823 */
6824 function _destroy() {
6825 var _globalState$eventEmi;
6826 const domCache = privateProps.domCache.get(this);
6827 const innerParams = privateProps.innerParams.get(this);
6828 if (!innerParams) {
6829 disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
6830 return; // This instance has already been destroyed
6831 }
6832
6833 // Check if there is another Swal closing
6834 if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
6835 globalState.swalCloseEventFinishedCallback();
6836 delete globalState.swalCloseEventFinishedCallback;
6837 }
6838 if (typeof innerParams.didDestroy === 'function') {
6839 innerParams.didDestroy();
6840 }
6841 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didDestroy');
6842 disposeSwal(this);
6843 }
6844
6845 /**
6846 * @param {SweetAlert} instance
6847 */
6848 const disposeSwal = instance => {
6849 disposeWeakMaps(instance);
6850 // Unset this.params so GC will dispose it (#1569)
6851 // @ts-ignore
6852 delete instance.params;
6853 // Unset globalState props so GC will dispose globalState (#1569)
6854 delete globalState.keydownHandler;
6855 delete globalState.keydownTarget;
6856 // Unset currentInstance
6857 delete globalState.currentInstance;
6858 };
6859
6860 /**
6861 * @param {SweetAlert} instance
6862 */
6863 const disposeWeakMaps = instance => {
6864 // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
6865 if (instance.isAwaitingPromise) {
6866 unsetWeakMaps(privateProps, instance);
6867 instance.isAwaitingPromise = true;
6868 } else {
6869 unsetWeakMaps(privateMethods, instance);
6870 unsetWeakMaps(privateProps, instance);
6871
6872 // @ts-ignore
6873 delete instance.isAwaitingPromise;
6874 // Unset instance methods
6875 // @ts-ignore
6876 delete instance.disableButtons;
6877 // @ts-ignore
6878 delete instance.enableButtons;
6879 // @ts-ignore
6880 delete instance.getInput;
6881 // @ts-ignore
6882 delete instance.disableInput;
6883 // @ts-ignore
6884 delete instance.enableInput;
6885 // @ts-ignore
6886 delete instance.hideLoading;
6887 // @ts-ignore
6888 delete instance.disableLoading;
6889 // @ts-ignore
6890 delete instance.showValidationMessage;
6891 // @ts-ignore
6892 delete instance.resetValidationMessage;
6893 // @ts-ignore
6894 delete instance.close;
6895 // @ts-ignore
6896 delete instance.closePopup;
6897 // @ts-ignore
6898 delete instance.closeModal;
6899 // @ts-ignore
6900 delete instance.closeToast;
6901 // @ts-ignore
6902 delete instance.rejectPromise;
6903 // @ts-ignore
6904 delete instance.update;
6905 // @ts-ignore
6906 delete instance._destroy;
6907 }
6908 };
6909
6910 /**
6911 * @param {Record<string, WeakMap<any, any>>} obj
6912 * @param {SweetAlert} instance
6913 */
6914 const unsetWeakMaps = (obj, instance) => {
6915 for (const i in obj) {
6916 obj[i].delete(instance);
6917 }
6918 };
6919
6920 var instanceMethods = /*#__PURE__*/Object.freeze({
6921 __proto__: null,
6922 _destroy: _destroy,
6923 close: close,
6924 closeModal: close,
6925 closePopup: close,
6926 closeToast: close,
6927 disableButtons: disableButtons,
6928 disableInput: disableInput,
6929 disableLoading: hideLoading,
6930 enableButtons: enableButtons,
6931 enableInput: enableInput,
6932 getInput: getInput,
6933 handleAwaitingPromise: handleAwaitingPromise,
6934 hideLoading: hideLoading,
6935 rejectPromise: rejectPromise,
6936 resetValidationMessage: resetValidationMessage,
6937 showValidationMessage: showValidationMessage,
6938 update: update
6939 });
6940
6941 /**
6942 * @param {SweetAlertOptions} innerParams
6943 * @param {DomCache} domCache
6944 * @param {(dismiss: DismissReason) => void} dismissWith
6945 */
6946 const handlePopupClick = (innerParams, domCache, dismissWith) => {
6947 if (innerParams.toast) {
6948 handleToastClick(innerParams, domCache, dismissWith);
6949 } else {
6950 // Ignore click events that had mousedown on the popup but mouseup on the container
6951 // This can happen when the user drags a slider
6952 handleModalMousedown(domCache);
6953
6954 // Ignore click events that had mousedown on the container but mouseup on the popup
6955 handleContainerMousedown(domCache);
6956 handleModalClick(innerParams, domCache, dismissWith);
6957 }
6958 };
6959
6960 /**
6961 * @param {SweetAlertOptions} innerParams
6962 * @param {DomCache} domCache
6963 * @param {(dismiss: DismissReason) => void} dismissWith
6964 */
6965 const handleToastClick = (innerParams, domCache, dismissWith) => {
6966 // Closing toast by internal click
6967 domCache.popup.onclick = () => {
6968 if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
6969 return;
6970 }
6971 dismissWith(DismissReason.close);
6972 };
6973 };
6974
6975 /**
6976 * @param {SweetAlertOptions} innerParams
6977 * @returns {boolean}
6978 */
6979 const isAnyButtonShown = innerParams => {
6980 return Boolean(innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton);
6981 };
6982 let ignoreOutsideClick = false;
6983
6984 /**
6985 * @param {DomCache} domCache
6986 */
6987 const handleModalMousedown = domCache => {
6988 domCache.popup.onmousedown = () => {
6989 domCache.container.onmouseup = function (e) {
6990 domCache.container.onmouseup = () => {};
6991 // We only check if the mouseup target is the container because usually it doesn't
6992 // have any other direct children aside of the popup
6993 if (e.target === domCache.container) {
6994 ignoreOutsideClick = true;
6995 }
6996 };
6997 };
6998 };
6999
7000 /**
7001 * @param {DomCache} domCache
7002 */
7003 const handleContainerMousedown = domCache => {
7004 domCache.container.onmousedown = e => {
7005 // prevent the modal text from being selected on double click on the container (allowOutsideClick: false)
7006 if (e.target === domCache.container) {
7007 e.preventDefault();
7008 }
7009 domCache.popup.onmouseup = function (e) {
7010 domCache.popup.onmouseup = () => {};
7011 // We also need to check if the mouseup target is a child of the popup
7012 if (e.target === domCache.popup || e.target instanceof HTMLElement && domCache.popup.contains(e.target)) {
7013 ignoreOutsideClick = true;
7014 }
7015 };
7016 };
7017 };
7018
7019 /**
7020 * @param {SweetAlertOptions} innerParams
7021 * @param {DomCache} domCache
7022 * @param {(dismiss: DismissReason) => void} dismissWith
7023 */
7024 const handleModalClick = (innerParams, domCache, dismissWith) => {
7025 domCache.container.onclick = e => {
7026 if (ignoreOutsideClick) {
7027 ignoreOutsideClick = false;
7028 return;
7029 }
7030 if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
7031 dismissWith(DismissReason.backdrop);
7032 }
7033 };
7034 };
7035
7036 /**
7037 * @param {unknown} elem
7038 * @returns {boolean}
7039 */
7040 const isJqueryElement = elem => typeof elem === 'object' && elem !== null && 'jquery' in elem;
7041
7042 /**
7043 * @param {unknown} elem
7044 * @returns {boolean}
7045 */
7046 const isElement = elem => elem instanceof Element || isJqueryElement(elem);
7047
7048 /**
7049 * @param {ReadonlyArray<unknown>} args
7050 * @returns {SweetAlertOptions}
7051 */
7052 const argsToParams = args => {
7053 /** @type {Record<string, unknown>} */
7054 const params = {};
7055 if (typeof args[0] === 'object' && !isElement(args[0])) {
7056 Object.assign(params, args[0]);
7057 } else {
7058 ['title', 'html', 'icon'].forEach((name, index) => {
7059 const arg = args[index];
7060 if (typeof arg === 'string' || isElement(arg)) {
7061 params[name] = arg;
7062 } else if (arg !== undefined) {
7063 error(`Unexpected type of ${name}! Expected "string" or "Element", got ${typeof arg}`);
7064 }
7065 });
7066 }
7067 return /** @type {SweetAlertOptions} */params;
7068 };
7069
7070 /**
7071 * Main method to create a new SweetAlert2 popup
7072 *
7073 * @this {new (...args: any[]) => any}
7074 * @param {...SweetAlertOptions} args
7075 * @returns {Promise<SweetAlertResult>}
7076 */
7077 function fire(...args) {
7078 return new this(...args);
7079 }
7080
7081 /**
7082 * Returns an extended version of `Swal` containing `params` as defaults.
7083 * Useful for reusing Swal configuration.
7084 *
7085 * For example:
7086 *
7087 * Before:
7088 * const textPromptOptions = { input: 'text', showCancelButton: true }
7089 * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
7090 * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
7091 *
7092 * After:
7093 * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
7094 * const {value: firstName} = await TextPrompt('What is your first name?')
7095 * const {value: lastName} = await TextPrompt('What is your last name?')
7096 *
7097 * @param {SweetAlertOptions} mixinParams
7098 * @returns {SweetAlert}
7099 * @this {typeof import('../SweetAlert.js').SweetAlert}
7100 */
7101 function mixin(mixinParams) {
7102 // @ts-ignore: 'this' refers to the SweetAlert constructor
7103 class MixinSwal extends this {
7104 /**
7105 * @param {any} params
7106 * @param {any} priorityMixinParams
7107 */
7108 _main(params, priorityMixinParams) {
7109 return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
7110 }
7111 }
7112 // @ts-ignore
7113 return MixinSwal;
7114 }
7115
7116 /**
7117 * If `timer` parameter is set, returns number of milliseconds of timer remained.
7118 * Otherwise, returns undefined.
7119 *
7120 * @returns {number | undefined}
7121 */
7122 const getTimerLeft = () => {
7123 return globalState.timeout && globalState.timeout.getTimerLeft();
7124 };
7125
7126 /**
7127 * Stop timer. Returns number of milliseconds of timer remained.
7128 * If `timer` parameter isn't set, returns undefined.
7129 *
7130 * @returns {number | undefined}
7131 */
7132 const stopTimer = () => {
7133 if (globalState.timeout) {
7134 stopTimerProgressBar();
7135 return globalState.timeout.stop();
7136 }
7137 };
7138
7139 /**
7140 * Resume timer. Returns number of milliseconds of timer remained.
7141 * If `timer` parameter isn't set, returns undefined.
7142 *
7143 * @returns {number | undefined}
7144 */
7145 const resumeTimer = () => {
7146 if (globalState.timeout) {
7147 const remaining = globalState.timeout.start();
7148 animateTimerProgressBar(remaining);
7149 return remaining;
7150 }
7151 };
7152
7153 /**
7154 * Resume timer. Returns number of milliseconds of timer remained.
7155 * If `timer` parameter isn't set, returns undefined.
7156 *
7157 * @returns {number | undefined}
7158 */
7159 const toggleTimer = () => {
7160 const timer = globalState.timeout;
7161 return timer && (timer.running ? stopTimer() : resumeTimer());
7162 };
7163
7164 /**
7165 * Increase timer. Returns number of milliseconds of an updated timer.
7166 * If `timer` parameter isn't set, returns undefined.
7167 *
7168 * @param {number} ms
7169 * @returns {number | undefined}
7170 */
7171 const increaseTimer = ms => {
7172 if (globalState.timeout) {
7173 const remaining = globalState.timeout.increase(ms);
7174 animateTimerProgressBar(remaining, true);
7175 return remaining;
7176 }
7177 };
7178
7179 /**
7180 * Check if timer is running. Returns true if timer is running
7181 * or false if timer is paused or stopped.
7182 * If `timer` parameter isn't set, returns undefined
7183 *
7184 * @returns {boolean}
7185 */
7186 const isTimerRunning = () => {
7187 return Boolean(globalState.timeout && globalState.timeout.isRunning());
7188 };
7189
7190 let bodyClickListenerAdded = false;
7191 /** @type {Record<string, any>} */
7192 const clickHandlers = {};
7193
7194 /**
7195 * @this {any}
7196 * @param {string} attr
7197 */
7198 function bindClickHandler(attr = 'data-swal-template') {
7199 clickHandlers[attr] = this;
7200 if (!bodyClickListenerAdded) {
7201 document.body.addEventListener('click', bodyClickListener);
7202 bodyClickListenerAdded = true;
7203 }
7204 }
7205
7206 /**
7207 * @param {MouseEvent} event
7208 */
7209 const bodyClickListener = event => {
7210 for (let el = /** @type {any} */event.target; el && el !== document; el = el.parentNode) {
7211 for (const attr in clickHandlers) {
7212 const template = el.getAttribute && el.getAttribute(attr);
7213 if (template) {
7214 clickHandlers[attr].fire({
7215 template
7216 });
7217 return;
7218 }
7219 }
7220 }
7221 };
7222
7223 // Source: https://gist.github.com/mudge/5830382?permalink_comment_id=2691957#gistcomment-2691957
7224
7225 class EventEmitter {
7226 constructor() {
7227 /** @type {Events} */
7228 this.events = {};
7229 }
7230
7231 /**
7232 * @param {string} eventName
7233 * @returns {EventHandlers}
7234 */
7235 _getHandlersByEventName(eventName) {
7236 if (typeof this.events[eventName] === 'undefined') {
7237 // not Set because we need to keep the FIFO order
7238 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1748990334
7239 this.events[eventName] = [];
7240 }
7241 return this.events[eventName];
7242 }
7243
7244 /**
7245 * @param {string} eventName
7246 * @param {EventHandler} eventHandler
7247 */
7248 on(eventName, eventHandler) {
7249 const currentHandlers = this._getHandlersByEventName(eventName);
7250 if (!currentHandlers.includes(eventHandler)) {
7251 currentHandlers.push(eventHandler);
7252 }
7253 }
7254
7255 /**
7256 * @param {string} eventName
7257 * @param {EventHandler} eventHandler
7258 */
7259 once(eventName, eventHandler) {
7260 /**
7261 * @param {...any} args
7262 */
7263 const onceFn = (...args) => {
7264 this.removeListener(eventName, onceFn);
7265 // @ts-ignore
7266 eventHandler.apply(this, args);
7267 };
7268 this.on(eventName, onceFn);
7269 }
7270
7271 /**
7272 * @param {string} eventName
7273 * @param {...any} args
7274 */
7275 emit(eventName, ...args) {
7276 this._getHandlersByEventName(eventName).forEach(
7277 /**
7278 * @param {EventHandler} eventHandler
7279 */
7280 eventHandler => {
7281 try {
7282 // @ts-ignore
7283 eventHandler.apply(this, args);
7284 } catch (error) {
7285 console.error(error);
7286 }
7287 });
7288 }
7289
7290 /**
7291 * @param {string} eventName
7292 * @param {EventHandler} eventHandler
7293 */
7294 removeListener(eventName, eventHandler) {
7295 const currentHandlers = this._getHandlersByEventName(eventName);
7296 const index = currentHandlers.indexOf(eventHandler);
7297 if (index > -1) {
7298 currentHandlers.splice(index, 1);
7299 }
7300 }
7301
7302 /**
7303 * @param {string} eventName
7304 */
7305 removeAllListeners(eventName) {
7306 if (this.events[eventName] !== undefined) {
7307 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1749239222
7308 this.events[eventName].length = 0;
7309 }
7310 }
7311 reset() {
7312 this.events = {};
7313 }
7314 }
7315
7316 globalState.eventEmitter = new EventEmitter();
7317
7318 /**
7319 * @param {string} eventName
7320 * @param {EventHandler} eventHandler
7321 */
7322 const on = (eventName, eventHandler) => {
7323 if (globalState.eventEmitter) {
7324 globalState.eventEmitter.on(eventName, eventHandler);
7325 }
7326 };
7327
7328 /**
7329 * @param {string} eventName
7330 * @param {EventHandler} eventHandler
7331 */
7332 const once = (eventName, eventHandler) => {
7333 if (globalState.eventEmitter) {
7334 globalState.eventEmitter.once(eventName, eventHandler);
7335 }
7336 };
7337
7338 /**
7339 * @param {string} [eventName]
7340 * @param {EventHandler} [eventHandler]
7341 */
7342 const off = (eventName, eventHandler) => {
7343 if (!globalState.eventEmitter) {
7344 return;
7345 }
7346
7347 // Remove all handlers for all events
7348 if (!eventName) {
7349 globalState.eventEmitter.reset();
7350 return;
7351 }
7352 if (eventHandler) {
7353 // Remove a specific handler
7354 globalState.eventEmitter.removeListener(eventName, eventHandler);
7355 } else {
7356 // Remove all handlers for a specific event
7357 globalState.eventEmitter.removeAllListeners(eventName);
7358 }
7359 };
7360
7361 var staticMethods = /*#__PURE__*/Object.freeze({
7362 __proto__: null,
7363 argsToParams: argsToParams,
7364 bindClickHandler: bindClickHandler,
7365 clickCancel: clickCancel,
7366 clickConfirm: clickConfirm,
7367 clickDeny: clickDeny,
7368 enableLoading: showLoading,
7369 fire: fire,
7370 getActions: getActions,
7371 getCancelButton: getCancelButton,
7372 getCloseButton: getCloseButton,
7373 getConfirmButton: getConfirmButton,
7374 getContainer: getContainer,
7375 getDenyButton: getDenyButton,
7376 getFocusableElements: getFocusableElements,
7377 getFooter: getFooter,
7378 getHtmlContainer: getHtmlContainer,
7379 getIcon: getIcon,
7380 getIconContent: getIconContent,
7381 getImage: getImage,
7382 getInputLabel: getInputLabel,
7383 getLoader: getLoader,
7384 getPopup: getPopup,
7385 getProgressSteps: getProgressSteps,
7386 getTimerLeft: getTimerLeft,
7387 getTimerProgressBar: getTimerProgressBar,
7388 getTitle: getTitle,
7389 getValidationMessage: getValidationMessage,
7390 increaseTimer: increaseTimer,
7391 isDeprecatedParameter: isDeprecatedParameter,
7392 isLoading: isLoading,
7393 isTimerRunning: isTimerRunning,
7394 isUpdatableParameter: isUpdatableParameter,
7395 isValidParameter: isValidParameter,
7396 isVisible: isVisible,
7397 mixin: mixin,
7398 off: off,
7399 on: on,
7400 once: once,
7401 resumeTimer: resumeTimer,
7402 showLoading: showLoading,
7403 stopTimer: stopTimer,
7404 toggleTimer: toggleTimer
7405 });
7406
7407 class Timer {
7408 /**
7409 * @param {() => void} callback
7410 * @param {number} delay
7411 */
7412 constructor(callback, delay) {
7413 this.callback = callback;
7414 this.remaining = delay;
7415 this.running = false;
7416 this.start();
7417 }
7418
7419 /**
7420 * @returns {number}
7421 */
7422 start() {
7423 if (!this.running) {
7424 this.running = true;
7425 this.started = new Date();
7426 this.id = setTimeout(this.callback, this.remaining);
7427 }
7428 return this.remaining;
7429 }
7430
7431 /**
7432 * @returns {number}
7433 */
7434 stop() {
7435 if (this.started && this.running) {
7436 this.running = false;
7437 clearTimeout(this.id);
7438 this.remaining -= new Date().getTime() - this.started.getTime();
7439 }
7440 return this.remaining;
7441 }
7442
7443 /**
7444 * @param {number} n
7445 * @returns {number}
7446 */
7447 increase(n) {
7448 const running = this.running;
7449 if (running) {
7450 this.stop();
7451 }
7452 this.remaining += n;
7453 if (running) {
7454 this.start();
7455 }
7456 return this.remaining;
7457 }
7458
7459 /**
7460 * @returns {number}
7461 */
7462 getTimerLeft() {
7463 if (this.running) {
7464 this.stop();
7465 this.start();
7466 }
7467 return this.remaining;
7468 }
7469
7470 /**
7471 * @returns {boolean}
7472 */
7473 isRunning() {
7474 return this.running;
7475 }
7476 }
7477
7478 const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
7479
7480 /**
7481 * @param {SweetAlertOptions} params
7482 * @returns {SweetAlertOptions}
7483 */
7484 const getTemplateParams = params => {
7485 const template = typeof params.template === 'string' ? (/** @type {HTMLTemplateElement} */document.querySelector(params.template)) : params.template;
7486 if (!template) {
7487 return {};
7488 }
7489 /** @type {DocumentFragment} */
7490 const templateContent = template.content;
7491 showWarningsForElements(templateContent);
7492 const result = Object.assign(getSwalParams(templateContent), getSwalFunctionParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
7493 return result;
7494 };
7495
7496 /**
7497 * @param {DocumentFragment} templateContent
7498 * @returns {Record<string, string | boolean | number>}
7499 */
7500 const getSwalParams = templateContent => {
7501 /** @type {Record<string, string | boolean | number>} */
7502 const result = {};
7503 /** @type {HTMLElement[]} */
7504 const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
7505 swalParams.forEach(param => {
7506 showWarningsForAttributes(param, ['name', 'value']);
7507 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7508 const value = param.getAttribute('value');
7509 if (!paramName || !value) {
7510 return;
7511 }
7512 if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'boolean') {
7513 result[paramName] = value !== 'false';
7514 } else if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'object') {
7515 result[paramName] = JSON.parse(value);
7516 } else {
7517 result[paramName] = value;
7518 }
7519 });
7520 return result;
7521 };
7522
7523 /**
7524 * @param {DocumentFragment} templateContent
7525 * @returns {Record<string, () => void>}
7526 */
7527 const getSwalFunctionParams = templateContent => {
7528 /** @type {Record<string, () => void>} */
7529 const result = {};
7530 /** @type {HTMLElement[]} */
7531 const swalFunctions = Array.from(templateContent.querySelectorAll('swal-function-param'));
7532 swalFunctions.forEach(param => {
7533 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7534 const value = param.getAttribute('value');
7535 if (!paramName || !value) {
7536 return;
7537 }
7538 result[paramName] = new Function(`return ${value}`)();
7539 });
7540 return result;
7541 };
7542
7543 /**
7544 * @param {DocumentFragment} templateContent
7545 * @returns {Record<string, string | boolean>}
7546 */
7547 const getSwalButtons = templateContent => {
7548 /** @type {Record<string, string | boolean>} */
7549 const result = {};
7550 /** @type {HTMLElement[]} */
7551 const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
7552 swalButtons.forEach(button => {
7553 showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
7554 const type = button.getAttribute('type');
7555 if (!type || !['confirm', 'cancel', 'deny'].includes(type)) {
7556 return;
7557 }
7558 result[`${type}ButtonText`] = button.innerHTML;
7559 result[`show${capitalizeFirstLetter(type)}Button`] = true;
7560 const color = button.getAttribute('color');
7561 if (color !== null) {
7562 result[`${type}ButtonColor`] = color;
7563 }
7564 const ariaLabel = button.getAttribute('aria-label');
7565 if (ariaLabel !== null) {
7566 result[`${type}ButtonAriaLabel`] = ariaLabel;
7567 }
7568 });
7569 return result;
7570 };
7571
7572 /**
7573 * @param {DocumentFragment} templateContent
7574 * @returns {Pick<SweetAlertOptions, 'imageUrl' | 'imageWidth' | 'imageHeight' | 'imageAlt'>}
7575 */
7576 const getSwalImage = templateContent => {
7577 const result = {};
7578 /** @type {HTMLElement | null} */
7579 const image = templateContent.querySelector('swal-image');
7580 if (image) {
7581 showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
7582 // getAttribute returns null if attribute is absent; `|| undefined` converts empty string to undefined
7583 const src = image.getAttribute('src');
7584 if (src !== null) result.imageUrl = src || undefined;
7585 const width = image.getAttribute('width');
7586 if (width !== null) result.imageWidth = width || undefined;
7587 const height = image.getAttribute('height');
7588 if (height !== null) result.imageHeight = height || undefined;
7589 const alt = image.getAttribute('alt');
7590 if (alt !== null) result.imageAlt = alt || undefined;
7591 }
7592 return result;
7593 };
7594
7595 /**
7596 * @param {DocumentFragment} templateContent
7597 * @returns {object}
7598 */
7599 const getSwalIcon = templateContent => {
7600 const result = {};
7601 /** @type {HTMLElement | null} */
7602 const icon = templateContent.querySelector('swal-icon');
7603 if (icon) {
7604 showWarningsForAttributes(icon, ['type', 'color']);
7605 if (icon.hasAttribute('type')) {
7606 result.icon = icon.getAttribute('type');
7607 }
7608 if (icon.hasAttribute('color')) {
7609 result.iconColor = icon.getAttribute('color');
7610 }
7611 result.iconHtml = icon.innerHTML;
7612 }
7613 return result;
7614 };
7615
7616 /**
7617 * @param {DocumentFragment} templateContent
7618 * @returns {object}
7619 */
7620 const getSwalInput = templateContent => {
7621 /** @type {Record<string, any>} */
7622 const result = {};
7623 /** @type {HTMLElement | null} */
7624 const input = templateContent.querySelector('swal-input');
7625 if (input) {
7626 showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
7627 result.input = input.getAttribute('type') || 'text';
7628 if (input.hasAttribute('label')) {
7629 result.inputLabel = input.getAttribute('label');
7630 }
7631 if (input.hasAttribute('placeholder')) {
7632 result.inputPlaceholder = input.getAttribute('placeholder');
7633 }
7634 if (input.hasAttribute('value')) {
7635 result.inputValue = input.getAttribute('value');
7636 }
7637 }
7638 /** @type {HTMLElement[]} */
7639 const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
7640 if (inputOptions.length) {
7641 result.inputOptions = {};
7642 inputOptions.forEach(option => {
7643 showWarningsForAttributes(option, ['value']);
7644 const optionValue = option.getAttribute('value');
7645 if (!optionValue) {
7646 return;
7647 }
7648 const optionName = option.innerHTML;
7649 result.inputOptions[optionValue] = optionName;
7650 });
7651 }
7652 return result;
7653 };
7654
7655 /**
7656 * @param {DocumentFragment} templateContent
7657 * @param {string[]} paramNames
7658 * @returns {Record<string, string>}
7659 */
7660 const getSwalStringParams = (templateContent, paramNames) => {
7661 /** @type {Record<string, string>} */
7662 const result = {};
7663 for (const i in paramNames) {
7664 const paramName = paramNames[i];
7665 /** @type {HTMLElement | null} */
7666 const tag = templateContent.querySelector(paramName);
7667 if (tag) {
7668 showWarningsForAttributes(tag, []);
7669 result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
7670 }
7671 }
7672 return result;
7673 };
7674
7675 /**
7676 * @param {DocumentFragment} templateContent
7677 */
7678 const showWarningsForElements = templateContent => {
7679 const allowedElements = swalStringParams.concat(['swal-param', 'swal-function-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
7680 Array.from(templateContent.children).forEach(el => {
7681 const tagName = el.tagName.toLowerCase();
7682 if (!allowedElements.includes(tagName)) {
7683 warn(`Unrecognized element <${tagName}>`);
7684 }
7685 });
7686 };
7687
7688 /**
7689 * @param {HTMLElement} el
7690 * @param {string[]} allowedAttributes
7691 */
7692 const showWarningsForAttributes = (el, allowedAttributes) => {
7693 Array.from(el.attributes).forEach(attribute => {
7694 if (allowedAttributes.indexOf(attribute.name) === -1) {
7695 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.'}`]);
7696 }
7697 });
7698 };
7699
7700 const SHOW_CLASS_TIMEOUT = 10;
7701
7702 /**
7703 * Open popup, add necessary classes and styles, fix scrollbar
7704 *
7705 * @param {SweetAlertOptions} params
7706 */
7707 const openPopup = params => {
7708 var _globalState$eventEmi, _globalState$eventEmi2;
7709 const container = getContainer();
7710 const popup = getPopup();
7711 if (!container || !popup) {
7712 return;
7713 }
7714 if (typeof params.willOpen === 'function') {
7715 params.willOpen(popup);
7716 }
7717 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willOpen', popup);
7718 const bodyStyles = window.getComputedStyle(document.body);
7719 const initialBodyOverflow = bodyStyles.overflowY;
7720 addClasses(container, popup, params);
7721
7722 // scrolling is 'hidden' until animation is done, after that 'auto'
7723 setTimeout(() => {
7724 setScrollingVisibility(container, popup);
7725 }, SHOW_CLASS_TIMEOUT);
7726 if (isModal()) {
7727 fixScrollContainer(container, params.scrollbarPadding !== undefined ? params.scrollbarPadding : false, initialBodyOverflow);
7728 setAriaHidden();
7729 }
7730
7731 // https://github.com/sweetalert2/sweetalert2/issues/2923
7732 if (isIOS && params.backdrop === false && popup.scrollHeight > container.clientHeight) {
7733 // remove pointer-events: none from container, it breaks scrolling tall popups in iOS
7734 container.style.pointerEvents = 'auto';
7735 }
7736 if (!isToast() && !globalState.previousActiveElement) {
7737 globalState.previousActiveElement = document.activeElement;
7738 }
7739 if (typeof params.didOpen === 'function') {
7740 const didOpen = params.didOpen;
7741 setTimeout(() => didOpen(popup));
7742 }
7743 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didOpen', popup);
7744 };
7745
7746 /**
7747 * @param {Event} event
7748 */
7749 const swalOpenAnimationFinished = event => {
7750 const popup = getPopup();
7751 if (!popup || event.target !== popup) {
7752 return;
7753 }
7754 const container = getContainer();
7755 if (!container) {
7756 return;
7757 }
7758 popup.removeEventListener('animationend', swalOpenAnimationFinished);
7759 popup.removeEventListener('transitionend', swalOpenAnimationFinished);
7760 container.style.overflowY = 'auto';
7761
7762 // no-transition is added in init() in case one swal is opened right after another
7763 removeClass(container, swalClasses['no-transition']);
7764 };
7765
7766 /**
7767 * @param {HTMLElement} container
7768 * @param {HTMLElement} popup
7769 */
7770 const setScrollingVisibility = (container, popup) => {
7771 if (hasCssAnimation(popup)) {
7772 container.style.overflowY = 'hidden';
7773 popup.addEventListener('animationend', swalOpenAnimationFinished);
7774 popup.addEventListener('transitionend', swalOpenAnimationFinished);
7775 } else {
7776 container.style.overflowY = 'auto';
7777 }
7778 };
7779
7780 /**
7781 * @param {HTMLElement} container
7782 * @param {boolean} scrollbarPadding
7783 * @param {string} initialBodyOverflow
7784 */
7785 const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
7786 iOSfix();
7787 if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
7788 replaceScrollbarWithPadding(initialBodyOverflow);
7789 }
7790
7791 // sweetalert2/issues/1247
7792 setTimeout(() => {
7793 container.scrollTop = 0;
7794 });
7795 };
7796
7797 /**
7798 * @param {HTMLElement} container
7799 * @param {HTMLElement} popup
7800 * @param {SweetAlertOptions} params
7801 */
7802 const addClasses = (container, popup, params) => {
7803 var _params$showClass;
7804 if ((_params$showClass = params.showClass) !== null && _params$showClass !== void 0 && _params$showClass.backdrop) {
7805 addClass(container, params.showClass.backdrop);
7806 }
7807 if (params.animation) {
7808 // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
7809 popup.style.setProperty('opacity', '0', 'important');
7810 show(popup, 'grid');
7811 setTimeout(() => {
7812 var _params$showClass2;
7813 // Animate popup right after showing it
7814 if ((_params$showClass2 = params.showClass) !== null && _params$showClass2 !== void 0 && _params$showClass2.popup) {
7815 addClass(popup, params.showClass.popup);
7816 }
7817 // and remove the opacity workaround
7818 popup.style.removeProperty('opacity');
7819 }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
7820 } else {
7821 show(popup, 'grid');
7822 }
7823 addClass([document.documentElement, document.body], swalClasses.shown);
7824 if (params.heightAuto && params.backdrop && !params.toast) {
7825 addClass([document.documentElement, document.body], swalClasses['height-auto']);
7826 }
7827 };
7828
7829 var defaultInputValidators = {
7830 /**
7831 * @param {string} string
7832 * @param {string} [validationMessage]
7833 * @returns {Promise<string | void>}
7834 */
7835 email: (string, validationMessage) => {
7836 return /^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
7837 },
7838 /**
7839 * @param {string} string
7840 * @param {string} [validationMessage]
7841 * @returns {Promise<string | void>}
7842 */
7843 url: (string, validationMessage) => {
7844 // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
7845 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');
7846 }
7847 };
7848
7849 /**
7850 * @param {SweetAlertOptions} params
7851 */
7852 function setDefaultInputValidators(params) {
7853 // Use default `inputValidator` for supported input types if not provided
7854 if (params.inputValidator) {
7855 return;
7856 }
7857 if (params.input === 'email') {
7858 params.inputValidator = defaultInputValidators['email'];
7859 }
7860 if (params.input === 'url') {
7861 params.inputValidator = defaultInputValidators['url'];
7862 }
7863 }
7864
7865 /**
7866 * @param {SweetAlertOptions} params
7867 */
7868 function validateCustomTargetElement(params) {
7869 // Determine if the custom target element is valid
7870 if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
7871 warn('Target parameter is not valid, defaulting to "body"');
7872 params.target = 'body';
7873 }
7874 }
7875
7876 /**
7877 * Set type, text and actions on popup
7878 *
7879 * @param {SweetAlertOptions} params
7880 */
7881 function setParameters(params) {
7882 setDefaultInputValidators(params);
7883
7884 // showLoaderOnConfirm && preConfirm
7885 if (params.showLoaderOnConfirm && !params.preConfirm) {
7886 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');
7887 }
7888 validateCustomTargetElement(params);
7889
7890 // Replace newlines with <br> in title
7891 if (typeof params.title === 'string') {
7892 params.title = params.title.split('\n').join('<br />');
7893 }
7894 init(params);
7895 }
7896
7897 /** @type {SweetAlert} */
7898 let currentInstance;
7899 var _promise = /*#__PURE__*/new WeakMap();
7900 class SweetAlert {
7901 /**
7902 * @param {...(SweetAlertOptions | string)} args
7903 * @this {SweetAlert}
7904 */
7905 constructor(...args) {
7906 /**
7907 * @type {Promise<SweetAlertResult>}
7908 */
7909 _classPrivateFieldInitSpec(this, _promise, /** @type {Promise<SweetAlertResult>} */
7910 Promise.resolve({
7911 isConfirmed: false,
7912 isDenied: false,
7913 isDismissed: true
7914 }));
7915 // Prevent run in Node env
7916 if (typeof window === 'undefined') {
7917 return;
7918 }
7919 currentInstance = this;
7920
7921 // @ts-ignore
7922 const outerParams = Object.freeze(this.constructor.argsToParams(args));
7923
7924 /** @type {Readonly<SweetAlertOptions>} */
7925 this.params = outerParams;
7926
7927 /** @type {boolean} */
7928 this.isAwaitingPromise = false;
7929 _classPrivateFieldSet2(_promise, this, this._main(currentInstance.params));
7930 }
7931
7932 /**
7933 * @param {any} userParams
7934 * @param {any} mixinParams
7935 */
7936 _main(userParams, mixinParams = {}) {
7937 showWarningsForParams(Object.assign({}, mixinParams, userParams));
7938 if (globalState.currentInstance) {
7939 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance);
7940 const {
7941 isAwaitingPromise
7942 } = globalState.currentInstance;
7943 globalState.currentInstance._destroy();
7944 if (!isAwaitingPromise) {
7945 swalPromiseResolve({
7946 isDismissed: true
7947 });
7948 }
7949 if (isModal()) {
7950 unsetAriaHidden();
7951 }
7952 }
7953 globalState.currentInstance = currentInstance;
7954 const innerParams = prepareParams(userParams, mixinParams);
7955 setParameters(innerParams);
7956 Object.freeze(innerParams);
7957
7958 // clear the previous timer
7959 if (globalState.timeout) {
7960 globalState.timeout.stop();
7961 delete globalState.timeout;
7962 }
7963
7964 // clear the restore focus timeout
7965 clearTimeout(globalState.restoreFocusTimeout);
7966 const domCache = populateDomCache(currentInstance);
7967 render(currentInstance, innerParams);
7968 privateProps.innerParams.set(currentInstance, innerParams);
7969 return swalPromise(currentInstance, domCache, innerParams);
7970 }
7971
7972 // `catch` cannot be the name of a module export, so we define our thenable methods here instead
7973 /**
7974 * @param {any} onFulfilled
7975 */
7976 // oxlint-disable-next-line unicorn/no-thenable
7977 then(onFulfilled) {
7978 return _classPrivateFieldGet2(_promise, this).then(onFulfilled);
7979 }
7980
7981 /**
7982 * @param {any} onFinally
7983 */
7984 finally(onFinally) {
7985 return _classPrivateFieldGet2(_promise, this).finally(onFinally);
7986 }
7987 }
7988
7989 /**
7990 * @param {SweetAlert} instance
7991 * @param {DomCache} domCache
7992 * @param {SweetAlertOptions} innerParams
7993 * @returns {Promise<SweetAlertResult>}
7994 */
7995 const swalPromise = (instance, domCache, innerParams) => {
7996 return new Promise((resolve, reject) => {
7997 // functions to handle all closings/dismissals
7998 /**
7999 * @param {DismissReason} dismiss
8000 */
8001 const dismissWith = dismiss => {
8002 instance.close({
8003 isDismissed: true,
8004 dismiss,
8005 isConfirmed: false,
8006 isDenied: false
8007 });
8008 };
8009 privateMethods.swalPromiseResolve.set(instance, resolve);
8010 privateMethods.swalPromiseReject.set(instance, reject);
8011 domCache.confirmButton.onclick = () => {
8012 handleConfirmButtonClick(instance);
8013 };
8014 domCache.denyButton.onclick = () => {
8015 handleDenyButtonClick(instance);
8016 };
8017 domCache.cancelButton.onclick = () => {
8018 handleCancelButtonClick(instance, dismissWith);
8019 };
8020 domCache.closeButton.onclick = () => {
8021 dismissWith(DismissReason.close);
8022 };
8023 handlePopupClick(innerParams, domCache, dismissWith);
8024 addKeydownHandler(globalState, innerParams, dismissWith);
8025 handleInputOptionsAndValue(instance, innerParams);
8026 openPopup(innerParams);
8027 setupTimer(globalState, innerParams, dismissWith);
8028 initFocus(domCache, innerParams);
8029
8030 // Scroll container to top on open (#1247, #1946)
8031 setTimeout(() => {
8032 domCache.container.scrollTop = 0;
8033 });
8034 });
8035 };
8036
8037 /**
8038 * @param {SweetAlertOptions} userParams
8039 * @param {SweetAlertOptions} mixinParams
8040 * @returns {SweetAlertOptions}
8041 */
8042 const prepareParams = (userParams, mixinParams) => {
8043 const templateParams = getTemplateParams(userParams);
8044 const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams); // precedence is described in #2131
8045 params.showClass = Object.assign({}, defaultParams.showClass, params.showClass);
8046 params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass);
8047 if (params.animation === false) {
8048 params.showClass = {
8049 backdrop: 'swal2-noanimation'
8050 };
8051 params.hideClass = {};
8052 }
8053 return params;
8054 };
8055
8056 /**
8057 * @param {SweetAlert} instance
8058 * @returns {DomCache}
8059 */
8060 const populateDomCache = instance => {
8061 const domCache = /** @type {DomCache} */{
8062 popup: (/** @type {HTMLElement} */getPopup()),
8063 container: (/** @type {HTMLElement} */getContainer()),
8064 actions: (/** @type {HTMLElement} */getActions()),
8065 confirmButton: (/** @type {HTMLElement} */getConfirmButton()),
8066 denyButton: (/** @type {HTMLElement} */getDenyButton()),
8067 cancelButton: (/** @type {HTMLElement} */getCancelButton()),
8068 loader: (/** @type {HTMLElement} */getLoader()),
8069 closeButton: (/** @type {HTMLElement} */getCloseButton()),
8070 validationMessage: (/** @type {HTMLElement} */getValidationMessage()),
8071 progressSteps: (/** @type {HTMLElement} */getProgressSteps())
8072 };
8073 privateProps.domCache.set(instance, domCache);
8074 return domCache;
8075 };
8076
8077 /**
8078 * @param {GlobalState} globalState
8079 * @param {SweetAlertOptions} innerParams
8080 * @param {(dismiss: DismissReason) => void} dismissWith
8081 */
8082 const setupTimer = (globalState, innerParams, dismissWith) => {
8083 const timerProgressBar = getTimerProgressBar();
8084 hide(timerProgressBar);
8085 if (innerParams.timer) {
8086 globalState.timeout = new Timer(() => {
8087 dismissWith('timer');
8088 delete globalState.timeout;
8089 }, innerParams.timer);
8090 if (innerParams.timerProgressBar && timerProgressBar) {
8091 show(timerProgressBar);
8092 applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar');
8093 setTimeout(() => {
8094 if (globalState.timeout && globalState.timeout.running) {
8095 // timer can be already stopped or unset at this point
8096 animateTimerProgressBar(/** @type {number} */innerParams.timer);
8097 }
8098 });
8099 }
8100 }
8101 };
8102
8103 /**
8104 * Initialize focus in the popup:
8105 *
8106 * 1. If `toast` is `true`, don't steal focus from the document.
8107 * 2. Else if there is an [autofocus] element, focus it.
8108 * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it.
8109 * 4. Else if `focusDeny` is `true` and deny button is visible, focus it.
8110 * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it.
8111 * 6. Else focus the first focusable element in a popup (if any).
8112 *
8113 * @param {DomCache} domCache
8114 * @param {SweetAlertOptions} innerParams
8115 */
8116 const initFocus = (domCache, innerParams) => {
8117 if (innerParams.toast) {
8118 return;
8119 }
8120 // TODO: this is dumb, remove `allowEnterKey` param in the next major version
8121 if (!callIfFunction(innerParams.allowEnterKey)) {
8122 warnAboutDeprecation('allowEnterKey', 'preConfirm: () => false');
8123 domCache.popup.focus();
8124 return;
8125 }
8126 if (focusAutofocus(domCache)) {
8127 return;
8128 }
8129 if (focusButton(domCache, innerParams)) {
8130 return;
8131 }
8132 setFocus(-1, 1);
8133 };
8134
8135 /**
8136 * @param {DomCache} domCache
8137 * @returns {boolean}
8138 */
8139 const focusAutofocus = domCache => {
8140 const autofocusElements = Array.from(domCache.popup.querySelectorAll('[autofocus]'));
8141 for (const autofocusElement of autofocusElements) {
8142 if (autofocusElement instanceof HTMLElement && isVisible$1(autofocusElement)) {
8143 autofocusElement.focus();
8144 return true;
8145 }
8146 }
8147 return false;
8148 };
8149
8150 /**
8151 * @param {DomCache} domCache
8152 * @param {SweetAlertOptions} innerParams
8153 * @returns {boolean}
8154 */
8155 const focusButton = (domCache, innerParams) => {
8156 if (innerParams.focusDeny && isVisible$1(domCache.denyButton)) {
8157 domCache.denyButton.focus();
8158 return true;
8159 }
8160 if (innerParams.focusCancel && isVisible$1(domCache.cancelButton)) {
8161 domCache.cancelButton.focus();
8162 return true;
8163 }
8164 if (innerParams.focusConfirm && isVisible$1(domCache.confirmButton)) {
8165 domCache.confirmButton.focus();
8166 return true;
8167 }
8168 return false;
8169 };
8170
8171 // Assign instance methods from src/instanceMethods/*.js to prototype
8172 SweetAlert.prototype.disableButtons = disableButtons;
8173 SweetAlert.prototype.enableButtons = enableButtons;
8174 SweetAlert.prototype.getInput = getInput;
8175 SweetAlert.prototype.disableInput = disableInput;
8176 SweetAlert.prototype.enableInput = enableInput;
8177 SweetAlert.prototype.hideLoading = hideLoading;
8178 SweetAlert.prototype.disableLoading = hideLoading;
8179 SweetAlert.prototype.showValidationMessage = showValidationMessage;
8180 SweetAlert.prototype.resetValidationMessage = resetValidationMessage;
8181 SweetAlert.prototype.close = close;
8182 SweetAlert.prototype.closePopup = close;
8183 SweetAlert.prototype.closeModal = close;
8184 SweetAlert.prototype.closeToast = close;
8185 SweetAlert.prototype.rejectPromise = rejectPromise;
8186 SweetAlert.prototype.update = update;
8187 SweetAlert.prototype._destroy = _destroy;
8188
8189 // Assign static methods from src/staticMethods/*.js to constructor
8190 Object.assign(SweetAlert, staticMethods);
8191
8192 // Proxy to instance methods to constructor, for now, for backwards compatibility
8193 Object.keys(instanceMethods).forEach(key => {
8194 /**
8195 * @param {...(SweetAlertOptions | string | undefined)} args
8196 * @returns {SweetAlertResult | Promise<SweetAlertResult> | undefined}
8197 */
8198 // @ts-ignore: Dynamic property assignment for backwards compatibility
8199 SweetAlert[key] = function (...args) {
8200 // @ts-ignore
8201 if (currentInstance && currentInstance[key]) {
8202 // @ts-ignore
8203 return currentInstance[key](...args);
8204 }
8205 return undefined;
8206 };
8207 });
8208 SweetAlert.DismissReason = DismissReason;
8209 SweetAlert.version = '11.26.25';
8210
8211 const Swal = SweetAlert;
8212 // @ts-ignore
8213 Swal.default = Swal;
8214
8215 return Swal;
8216
8217 }));
8218 if (typeof this !== 'undefined' && this.Sweetalert2){this.swal = this.sweetAlert = this.Swal = this.SweetAlert = this.Sweetalert2}
8219 "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-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:auto}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}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)}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}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}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}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)}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:auto}.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}.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}}");
8220
8221 /***/ },
8222
8223 /***/ "./node_modules/@kurkle/color/dist/color.esm.js"
8224 /*!******************************************************!*\
8225 !*** ./node_modules/@kurkle/color/dist/color.esm.js ***!
8226 \******************************************************/
8227 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8228
8229 "use strict";
8230 __webpack_require__.r(__webpack_exports__);
8231 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8232 /* harmony export */ Color: () => (/* binding */ Color),
8233 /* harmony export */ b2n: () => (/* binding */ b2n),
8234 /* harmony export */ b2p: () => (/* binding */ b2p),
8235 /* harmony export */ "default": () => (/* binding */ index_esm),
8236 /* harmony export */ hexParse: () => (/* binding */ hexParse),
8237 /* harmony export */ hexString: () => (/* binding */ hexString),
8238 /* harmony export */ hsl2rgb: () => (/* binding */ hsl2rgb),
8239 /* harmony export */ hslString: () => (/* binding */ hslString),
8240 /* harmony export */ hsv2rgb: () => (/* binding */ hsv2rgb),
8241 /* harmony export */ hueParse: () => (/* binding */ hueParse),
8242 /* harmony export */ hwb2rgb: () => (/* binding */ hwb2rgb),
8243 /* harmony export */ lim: () => (/* binding */ lim),
8244 /* harmony export */ n2b: () => (/* binding */ n2b),
8245 /* harmony export */ n2p: () => (/* binding */ n2p),
8246 /* harmony export */ nameParse: () => (/* binding */ nameParse),
8247 /* harmony export */ p2b: () => (/* binding */ p2b),
8248 /* harmony export */ rgb2hsl: () => (/* binding */ rgb2hsl),
8249 /* harmony export */ rgbParse: () => (/* binding */ rgbParse),
8250 /* harmony export */ rgbString: () => (/* binding */ rgbString),
8251 /* harmony export */ rotate: () => (/* binding */ rotate),
8252 /* harmony export */ round: () => (/* binding */ round)
8253 /* harmony export */ });
8254 /*!
8255 * @kurkle/color v0.3.4
8256 * https://github.com/kurkle/color#readme
8257 * (c) 2024 Jukka Kurkela
8258 * Released under the MIT License
8259 */
8260 function round(v) {
8261 return v + 0.5 | 0;
8262 }
8263 const lim = (v, l, h) => Math.max(Math.min(v, h), l);
8264 function p2b(v) {
8265 return lim(round(v * 2.55), 0, 255);
8266 }
8267 function b2p(v) {
8268 return lim(round(v / 2.55), 0, 100);
8269 }
8270 function n2b(v) {
8271 return lim(round(v * 255), 0, 255);
8272 }
8273 function b2n(v) {
8274 return lim(round(v / 2.55) / 100, 0, 1);
8275 }
8276 function n2p(v) {
8277 return lim(round(v * 100), 0, 100);
8278 }
8279
8280 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};
8281 const hex = [...'0123456789ABCDEF'];
8282 const h1 = b => hex[b & 0xF];
8283 const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF];
8284 const eq = b => ((b & 0xF0) >> 4) === (b & 0xF);
8285 const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);
8286 function hexParse(str) {
8287 var len = str.length;
8288 var ret;
8289 if (str[0] === '#') {
8290 if (len === 4 || len === 5) {
8291 ret = {
8292 r: 255 & map$1[str[1]] * 17,
8293 g: 255 & map$1[str[2]] * 17,
8294 b: 255 & map$1[str[3]] * 17,
8295 a: len === 5 ? map$1[str[4]] * 17 : 255
8296 };
8297 } else if (len === 7 || len === 9) {
8298 ret = {
8299 r: map$1[str[1]] << 4 | map$1[str[2]],
8300 g: map$1[str[3]] << 4 | map$1[str[4]],
8301 b: map$1[str[5]] << 4 | map$1[str[6]],
8302 a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255
8303 };
8304 }
8305 }
8306 return ret;
8307 }
8308 const alpha = (a, f) => a < 255 ? f(a) : '';
8309 function hexString(v) {
8310 var f = isShort(v) ? h1 : h2;
8311 return v
8312 ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f)
8313 : undefined;
8314 }
8315
8316 const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
8317 function hsl2rgbn(h, s, l) {
8318 const a = s * Math.min(l, 1 - l);
8319 const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
8320 return [f(0), f(8), f(4)];
8321 }
8322 function hsv2rgbn(h, s, v) {
8323 const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
8324 return [f(5), f(3), f(1)];
8325 }
8326 function hwb2rgbn(h, w, b) {
8327 const rgb = hsl2rgbn(h, 1, 0.5);
8328 let i;
8329 if (w + b > 1) {
8330 i = 1 / (w + b);
8331 w *= i;
8332 b *= i;
8333 }
8334 for (i = 0; i < 3; i++) {
8335 rgb[i] *= 1 - w - b;
8336 rgb[i] += w;
8337 }
8338 return rgb;
8339 }
8340 function hueValue(r, g, b, d, max) {
8341 if (r === max) {
8342 return ((g - b) / d) + (g < b ? 6 : 0);
8343 }
8344 if (g === max) {
8345 return (b - r) / d + 2;
8346 }
8347 return (r - g) / d + 4;
8348 }
8349 function rgb2hsl(v) {
8350 const range = 255;
8351 const r = v.r / range;
8352 const g = v.g / range;
8353 const b = v.b / range;
8354 const max = Math.max(r, g, b);
8355 const min = Math.min(r, g, b);
8356 const l = (max + min) / 2;
8357 let h, s, d;
8358 if (max !== min) {
8359 d = max - min;
8360 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
8361 h = hueValue(r, g, b, d, max);
8362 h = h * 60 + 0.5;
8363 }
8364 return [h | 0, s || 0, l];
8365 }
8366 function calln(f, a, b, c) {
8367 return (
8368 Array.isArray(a)
8369 ? f(a[0], a[1], a[2])
8370 : f(a, b, c)
8371 ).map(n2b);
8372 }
8373 function hsl2rgb(h, s, l) {
8374 return calln(hsl2rgbn, h, s, l);
8375 }
8376 function hwb2rgb(h, w, b) {
8377 return calln(hwb2rgbn, h, w, b);
8378 }
8379 function hsv2rgb(h, s, v) {
8380 return calln(hsv2rgbn, h, s, v);
8381 }
8382 function hue(h) {
8383 return (h % 360 + 360) % 360;
8384 }
8385 function hueParse(str) {
8386 const m = HUE_RE.exec(str);
8387 let a = 255;
8388 let v;
8389 if (!m) {
8390 return;
8391 }
8392 if (m[5] !== v) {
8393 a = m[6] ? p2b(+m[5]) : n2b(+m[5]);
8394 }
8395 const h = hue(+m[2]);
8396 const p1 = +m[3] / 100;
8397 const p2 = +m[4] / 100;
8398 if (m[1] === 'hwb') {
8399 v = hwb2rgb(h, p1, p2);
8400 } else if (m[1] === 'hsv') {
8401 v = hsv2rgb(h, p1, p2);
8402 } else {
8403 v = hsl2rgb(h, p1, p2);
8404 }
8405 return {
8406 r: v[0],
8407 g: v[1],
8408 b: v[2],
8409 a: a
8410 };
8411 }
8412 function rotate(v, deg) {
8413 var h = rgb2hsl(v);
8414 h[0] = hue(h[0] + deg);
8415 h = hsl2rgb(h);
8416 v.r = h[0];
8417 v.g = h[1];
8418 v.b = h[2];
8419 }
8420 function hslString(v) {
8421 if (!v) {
8422 return;
8423 }
8424 const a = rgb2hsl(v);
8425 const h = a[0];
8426 const s = n2p(a[1]);
8427 const l = n2p(a[2]);
8428 return v.a < 255
8429 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`
8430 : `hsl(${h}, ${s}%, ${l}%)`;
8431 }
8432
8433 const map = {
8434 x: 'dark',
8435 Z: 'light',
8436 Y: 're',
8437 X: 'blu',
8438 W: 'gr',
8439 V: 'medium',
8440 U: 'slate',
8441 A: 'ee',
8442 T: 'ol',
8443 S: 'or',
8444 B: 'ra',
8445 C: 'lateg',
8446 D: 'ights',
8447 R: 'in',
8448 Q: 'turquois',
8449 E: 'hi',
8450 P: 'ro',
8451 O: 'al',
8452 N: 'le',
8453 M: 'de',
8454 L: 'yello',
8455 F: 'en',
8456 K: 'ch',
8457 G: 'arks',
8458 H: 'ea',
8459 I: 'ightg',
8460 J: 'wh'
8461 };
8462 const names$1 = {
8463 OiceXe: 'f0f8ff',
8464 antiquewEte: 'faebd7',
8465 aqua: 'ffff',
8466 aquamarRe: '7fffd4',
8467 azuY: 'f0ffff',
8468 beige: 'f5f5dc',
8469 bisque: 'ffe4c4',
8470 black: '0',
8471 blanKedOmond: 'ffebcd',
8472 Xe: 'ff',
8473 XeviTet: '8a2be2',
8474 bPwn: 'a52a2a',
8475 burlywood: 'deb887',
8476 caMtXe: '5f9ea0',
8477 KartYuse: '7fff00',
8478 KocTate: 'd2691e',
8479 cSO: 'ff7f50',
8480 cSnflowerXe: '6495ed',
8481 cSnsilk: 'fff8dc',
8482 crimson: 'dc143c',
8483 cyan: 'ffff',
8484 xXe: '8b',
8485 xcyan: '8b8b',
8486 xgTMnPd: 'b8860b',
8487 xWay: 'a9a9a9',
8488 xgYF: '6400',
8489 xgYy: 'a9a9a9',
8490 xkhaki: 'bdb76b',
8491 xmagFta: '8b008b',
8492 xTivegYF: '556b2f',
8493 xSange: 'ff8c00',
8494 xScEd: '9932cc',
8495 xYd: '8b0000',
8496 xsOmon: 'e9967a',
8497 xsHgYF: '8fbc8f',
8498 xUXe: '483d8b',
8499 xUWay: '2f4f4f',
8500 xUgYy: '2f4f4f',
8501 xQe: 'ced1',
8502 xviTet: '9400d3',
8503 dAppRk: 'ff1493',
8504 dApskyXe: 'bfff',
8505 dimWay: '696969',
8506 dimgYy: '696969',
8507 dodgerXe: '1e90ff',
8508 fiYbrick: 'b22222',
8509 flSOwEte: 'fffaf0',
8510 foYstWAn: '228b22',
8511 fuKsia: 'ff00ff',
8512 gaRsbSo: 'dcdcdc',
8513 ghostwEte: 'f8f8ff',
8514 gTd: 'ffd700',
8515 gTMnPd: 'daa520',
8516 Way: '808080',
8517 gYF: '8000',
8518 gYFLw: 'adff2f',
8519 gYy: '808080',
8520 honeyMw: 'f0fff0',
8521 hotpRk: 'ff69b4',
8522 RdianYd: 'cd5c5c',
8523 Rdigo: '4b0082',
8524 ivSy: 'fffff0',
8525 khaki: 'f0e68c',
8526 lavFMr: 'e6e6fa',
8527 lavFMrXsh: 'fff0f5',
8528 lawngYF: '7cfc00',
8529 NmoncEffon: 'fffacd',
8530 ZXe: 'add8e6',
8531 ZcSO: 'f08080',
8532 Zcyan: 'e0ffff',
8533 ZgTMnPdLw: 'fafad2',
8534 ZWay: 'd3d3d3',
8535 ZgYF: '90ee90',
8536 ZgYy: 'd3d3d3',
8537 ZpRk: 'ffb6c1',
8538 ZsOmon: 'ffa07a',
8539 ZsHgYF: '20b2aa',
8540 ZskyXe: '87cefa',
8541 ZUWay: '778899',
8542 ZUgYy: '778899',
8543 ZstAlXe: 'b0c4de',
8544 ZLw: 'ffffe0',
8545 lime: 'ff00',
8546 limegYF: '32cd32',
8547 lRF: 'faf0e6',
8548 magFta: 'ff00ff',
8549 maPon: '800000',
8550 VaquamarRe: '66cdaa',
8551 VXe: 'cd',
8552 VScEd: 'ba55d3',
8553 VpurpN: '9370db',
8554 VsHgYF: '3cb371',
8555 VUXe: '7b68ee',
8556 VsprRggYF: 'fa9a',
8557 VQe: '48d1cc',
8558 VviTetYd: 'c71585',
8559 midnightXe: '191970',
8560 mRtcYam: 'f5fffa',
8561 mistyPse: 'ffe4e1',
8562 moccasR: 'ffe4b5',
8563 navajowEte: 'ffdead',
8564 navy: '80',
8565 Tdlace: 'fdf5e6',
8566 Tive: '808000',
8567 TivedBb: '6b8e23',
8568 Sange: 'ffa500',
8569 SangeYd: 'ff4500',
8570 ScEd: 'da70d6',
8571 pOegTMnPd: 'eee8aa',
8572 pOegYF: '98fb98',
8573 pOeQe: 'afeeee',
8574 pOeviTetYd: 'db7093',
8575 papayawEp: 'ffefd5',
8576 pHKpuff: 'ffdab9',
8577 peru: 'cd853f',
8578 pRk: 'ffc0cb',
8579 plum: 'dda0dd',
8580 powMrXe: 'b0e0e6',
8581 purpN: '800080',
8582 YbeccapurpN: '663399',
8583 Yd: 'ff0000',
8584 Psybrown: 'bc8f8f',
8585 PyOXe: '4169e1',
8586 saddNbPwn: '8b4513',
8587 sOmon: 'fa8072',
8588 sandybPwn: 'f4a460',
8589 sHgYF: '2e8b57',
8590 sHshell: 'fff5ee',
8591 siFna: 'a0522d',
8592 silver: 'c0c0c0',
8593 skyXe: '87ceeb',
8594 UXe: '6a5acd',
8595 UWay: '708090',
8596 UgYy: '708090',
8597 snow: 'fffafa',
8598 sprRggYF: 'ff7f',
8599 stAlXe: '4682b4',
8600 tan: 'd2b48c',
8601 teO: '8080',
8602 tEstN: 'd8bfd8',
8603 tomato: 'ff6347',
8604 Qe: '40e0d0',
8605 viTet: 'ee82ee',
8606 JHt: 'f5deb3',
8607 wEte: 'ffffff',
8608 wEtesmoke: 'f5f5f5',
8609 Lw: 'ffff00',
8610 LwgYF: '9acd32'
8611 };
8612 function unpack() {
8613 const unpacked = {};
8614 const keys = Object.keys(names$1);
8615 const tkeys = Object.keys(map);
8616 let i, j, k, ok, nk;
8617 for (i = 0; i < keys.length; i++) {
8618 ok = nk = keys[i];
8619 for (j = 0; j < tkeys.length; j++) {
8620 k = tkeys[j];
8621 nk = nk.replace(k, map[k]);
8622 }
8623 k = parseInt(names$1[ok], 16);
8624 unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];
8625 }
8626 return unpacked;
8627 }
8628
8629 let names;
8630 function nameParse(str) {
8631 if (!names) {
8632 names = unpack();
8633 names.transparent = [0, 0, 0, 0];
8634 }
8635 const a = names[str.toLowerCase()];
8636 return a && {
8637 r: a[0],
8638 g: a[1],
8639 b: a[2],
8640 a: a.length === 4 ? a[3] : 255
8641 };
8642 }
8643
8644 const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
8645 function rgbParse(str) {
8646 const m = RGB_RE.exec(str);
8647 let a = 255;
8648 let r, g, b;
8649 if (!m) {
8650 return;
8651 }
8652 if (m[7] !== r) {
8653 const v = +m[7];
8654 a = m[8] ? p2b(v) : lim(v * 255, 0, 255);
8655 }
8656 r = +m[1];
8657 g = +m[3];
8658 b = +m[5];
8659 r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255));
8660 g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255));
8661 b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255));
8662 return {
8663 r: r,
8664 g: g,
8665 b: b,
8666 a: a
8667 };
8668 }
8669 function rgbString(v) {
8670 return v && (
8671 v.a < 255
8672 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`
8673 : `rgb(${v.r}, ${v.g}, ${v.b})`
8674 );
8675 }
8676
8677 const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055;
8678 const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
8679 function interpolate(rgb1, rgb2, t) {
8680 const r = from(b2n(rgb1.r));
8681 const g = from(b2n(rgb1.g));
8682 const b = from(b2n(rgb1.b));
8683 return {
8684 r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))),
8685 g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))),
8686 b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))),
8687 a: rgb1.a + t * (rgb2.a - rgb1.a)
8688 };
8689 }
8690
8691 function modHSL(v, i, ratio) {
8692 if (v) {
8693 let tmp = rgb2hsl(v);
8694 tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));
8695 tmp = hsl2rgb(tmp);
8696 v.r = tmp[0];
8697 v.g = tmp[1];
8698 v.b = tmp[2];
8699 }
8700 }
8701 function clone(v, proto) {
8702 return v ? Object.assign(proto || {}, v) : v;
8703 }
8704 function fromObject(input) {
8705 var v = {r: 0, g: 0, b: 0, a: 255};
8706 if (Array.isArray(input)) {
8707 if (input.length >= 3) {
8708 v = {r: input[0], g: input[1], b: input[2], a: 255};
8709 if (input.length > 3) {
8710 v.a = n2b(input[3]);
8711 }
8712 }
8713 } else {
8714 v = clone(input, {r: 0, g: 0, b: 0, a: 1});
8715 v.a = n2b(v.a);
8716 }
8717 return v;
8718 }
8719 function functionParse(str) {
8720 if (str.charAt(0) === 'r') {
8721 return rgbParse(str);
8722 }
8723 return hueParse(str);
8724 }
8725 class Color {
8726 constructor(input) {
8727 if (input instanceof Color) {
8728 return input;
8729 }
8730 const type = typeof input;
8731 let v;
8732 if (type === 'object') {
8733 v = fromObject(input);
8734 } else if (type === 'string') {
8735 v = hexParse(input) || nameParse(input) || functionParse(input);
8736 }
8737 this._rgb = v;
8738 this._valid = !!v;
8739 }
8740 get valid() {
8741 return this._valid;
8742 }
8743 get rgb() {
8744 var v = clone(this._rgb);
8745 if (v) {
8746 v.a = b2n(v.a);
8747 }
8748 return v;
8749 }
8750 set rgb(obj) {
8751 this._rgb = fromObject(obj);
8752 }
8753 rgbString() {
8754 return this._valid ? rgbString(this._rgb) : undefined;
8755 }
8756 hexString() {
8757 return this._valid ? hexString(this._rgb) : undefined;
8758 }
8759 hslString() {
8760 return this._valid ? hslString(this._rgb) : undefined;
8761 }
8762 mix(color, weight) {
8763 if (color) {
8764 const c1 = this.rgb;
8765 const c2 = color.rgb;
8766 let w2;
8767 const p = weight === w2 ? 0.5 : weight;
8768 const w = 2 * p - 1;
8769 const a = c1.a - c2.a;
8770 const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
8771 w2 = 1 - w1;
8772 c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;
8773 c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;
8774 c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;
8775 c1.a = p * c1.a + (1 - p) * c2.a;
8776 this.rgb = c1;
8777 }
8778 return this;
8779 }
8780 interpolate(color, t) {
8781 if (color) {
8782 this._rgb = interpolate(this._rgb, color._rgb, t);
8783 }
8784 return this;
8785 }
8786 clone() {
8787 return new Color(this.rgb);
8788 }
8789 alpha(a) {
8790 this._rgb.a = n2b(a);
8791 return this;
8792 }
8793 clearer(ratio) {
8794 const rgb = this._rgb;
8795 rgb.a *= 1 - ratio;
8796 return this;
8797 }
8798 greyscale() {
8799 const rgb = this._rgb;
8800 const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
8801 rgb.r = rgb.g = rgb.b = val;
8802 return this;
8803 }
8804 opaquer(ratio) {
8805 const rgb = this._rgb;
8806 rgb.a *= 1 + ratio;
8807 return this;
8808 }
8809 negate() {
8810 const v = this._rgb;
8811 v.r = 255 - v.r;
8812 v.g = 255 - v.g;
8813 v.b = 255 - v.b;
8814 return this;
8815 }
8816 lighten(ratio) {
8817 modHSL(this._rgb, 2, ratio);
8818 return this;
8819 }
8820 darken(ratio) {
8821 modHSL(this._rgb, 2, -ratio);
8822 return this;
8823 }
8824 saturate(ratio) {
8825 modHSL(this._rgb, 1, ratio);
8826 return this;
8827 }
8828 desaturate(ratio) {
8829 modHSL(this._rgb, 1, -ratio);
8830 return this;
8831 }
8832 rotate(deg) {
8833 rotate(this._rgb, deg);
8834 return this;
8835 }
8836 }
8837
8838 function index_esm(input) {
8839 return new Color(input);
8840 }
8841
8842
8843
8844
8845 /***/ },
8846
8847 /***/ "./node_modules/chart.js/auto/auto.js"
8848 /*!********************************************!*\
8849 !*** ./node_modules/chart.js/auto/auto.js ***!
8850 \********************************************/
8851 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8852
8853 "use strict";
8854 __webpack_require__.r(__webpack_exports__);
8855 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8856 /* harmony export */ Animation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animation),
8857 /* harmony export */ Animations: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animations),
8858 /* harmony export */ ArcElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ArcElement),
8859 /* harmony export */ BarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarController),
8860 /* harmony export */ BarElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarElement),
8861 /* harmony export */ BasePlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasePlatform),
8862 /* harmony export */ BasicPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasicPlatform),
8863 /* harmony export */ BubbleController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BubbleController),
8864 /* harmony export */ CategoryScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.CategoryScale),
8865 /* harmony export */ Chart: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart),
8866 /* harmony export */ Colors: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Colors),
8867 /* harmony export */ DatasetController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DatasetController),
8868 /* harmony export */ Decimation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Decimation),
8869 /* harmony export */ DomPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DomPlatform),
8870 /* harmony export */ DoughnutController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DoughnutController),
8871 /* harmony export */ Element: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Element),
8872 /* harmony export */ Filler: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Filler),
8873 /* harmony export */ Interaction: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Interaction),
8874 /* harmony export */ Legend: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Legend),
8875 /* harmony export */ LineController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineController),
8876 /* harmony export */ LineElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineElement),
8877 /* harmony export */ LinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LinearScale),
8878 /* harmony export */ LogarithmicScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LogarithmicScale),
8879 /* harmony export */ PieController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PieController),
8880 /* harmony export */ PointElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PointElement),
8881 /* harmony export */ PolarAreaController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PolarAreaController),
8882 /* harmony export */ RadarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadarController),
8883 /* harmony export */ RadialLinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadialLinearScale),
8884 /* harmony export */ Scale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Scale),
8885 /* harmony export */ ScatterController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ScatterController),
8886 /* harmony export */ SubTitle: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.SubTitle),
8887 /* harmony export */ Ticks: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Ticks),
8888 /* harmony export */ TimeScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeScale),
8889 /* harmony export */ TimeSeriesScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeSeriesScale),
8890 /* harmony export */ Title: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Title),
8891 /* harmony export */ Tooltip: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Tooltip),
8892 /* harmony export */ _adapters: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._adapters),
8893 /* harmony export */ _detectPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._detectPlatform),
8894 /* harmony export */ animator: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.animator),
8895 /* harmony export */ controllers: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.controllers),
8896 /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
8897 /* harmony export */ defaults: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.defaults),
8898 /* harmony export */ elements: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.elements),
8899 /* harmony export */ layouts: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.layouts),
8900 /* harmony export */ plugins: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.plugins),
8901 /* harmony export */ registerables: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables),
8902 /* harmony export */ registry: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registry),
8903 /* harmony export */ scales: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.scales)
8904 /* harmony export */ });
8905 /* harmony import */ var _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../dist/chart.js */ "./node_modules/chart.js/dist/chart.js");
8906
8907
8908 _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart.register(..._dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables);
8909
8910
8911 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart);
8912
8913
8914 /***/ },
8915
8916 /***/ "./node_modules/chart.js/dist/chart.js"
8917 /*!*********************************************!*\
8918 !*** ./node_modules/chart.js/dist/chart.js ***!
8919 \*********************************************/
8920 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8921
8922 "use strict";
8923 __webpack_require__.r(__webpack_exports__);
8924 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8925 /* harmony export */ Animation: () => (/* binding */ Animation),
8926 /* harmony export */ Animations: () => (/* binding */ Animations),
8927 /* harmony export */ ArcElement: () => (/* binding */ ArcElement),
8928 /* harmony export */ BarController: () => (/* binding */ BarController),
8929 /* harmony export */ BarElement: () => (/* binding */ BarElement),
8930 /* harmony export */ BasePlatform: () => (/* binding */ BasePlatform),
8931 /* harmony export */ BasicPlatform: () => (/* binding */ BasicPlatform),
8932 /* harmony export */ BubbleController: () => (/* binding */ BubbleController),
8933 /* harmony export */ CategoryScale: () => (/* binding */ CategoryScale),
8934 /* harmony export */ Chart: () => (/* binding */ Chart),
8935 /* harmony export */ Colors: () => (/* binding */ plugin_colors),
8936 /* harmony export */ DatasetController: () => (/* binding */ DatasetController),
8937 /* harmony export */ Decimation: () => (/* binding */ plugin_decimation),
8938 /* harmony export */ DomPlatform: () => (/* binding */ DomPlatform),
8939 /* harmony export */ DoughnutController: () => (/* binding */ DoughnutController),
8940 /* harmony export */ Element: () => (/* binding */ Element),
8941 /* harmony export */ Filler: () => (/* binding */ index),
8942 /* harmony export */ Interaction: () => (/* binding */ Interaction),
8943 /* harmony export */ Legend: () => (/* binding */ plugin_legend),
8944 /* harmony export */ LineController: () => (/* binding */ LineController),
8945 /* harmony export */ LineElement: () => (/* binding */ LineElement),
8946 /* harmony export */ LinearScale: () => (/* binding */ LinearScale),
8947 /* harmony export */ LogarithmicScale: () => (/* binding */ LogarithmicScale),
8948 /* harmony export */ PieController: () => (/* binding */ PieController),
8949 /* harmony export */ PointElement: () => (/* binding */ PointElement),
8950 /* harmony export */ PolarAreaController: () => (/* binding */ PolarAreaController),
8951 /* harmony export */ RadarController: () => (/* binding */ RadarController),
8952 /* harmony export */ RadialLinearScale: () => (/* binding */ RadialLinearScale),
8953 /* harmony export */ Scale: () => (/* binding */ Scale),
8954 /* harmony export */ ScatterController: () => (/* binding */ ScatterController),
8955 /* harmony export */ SubTitle: () => (/* binding */ plugin_subtitle),
8956 /* harmony export */ Ticks: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM),
8957 /* harmony export */ TimeScale: () => (/* binding */ TimeScale),
8958 /* harmony export */ TimeSeriesScale: () => (/* binding */ TimeSeriesScale),
8959 /* harmony export */ Title: () => (/* binding */ plugin_title),
8960 /* harmony export */ Tooltip: () => (/* binding */ plugin_tooltip),
8961 /* harmony export */ _adapters: () => (/* binding */ adapters),
8962 /* harmony export */ _detectPlatform: () => (/* binding */ _detectPlatform),
8963 /* harmony export */ animator: () => (/* binding */ animator),
8964 /* harmony export */ controllers: () => (/* binding */ controllers),
8965 /* harmony export */ defaults: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d),
8966 /* harmony export */ elements: () => (/* binding */ elements),
8967 /* harmony export */ layouts: () => (/* binding */ layouts),
8968 /* harmony export */ plugins: () => (/* binding */ plugins),
8969 /* harmony export */ registerables: () => (/* binding */ registerables),
8970 /* harmony export */ registry: () => (/* binding */ registry),
8971 /* harmony export */ scales: () => (/* binding */ scales)
8972 /* harmony export */ });
8973 /* 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");
8974 /*!
8975 * Chart.js v4.5.1
8976 * https://www.chartjs.org
8977 * (c) 2025 Chart.js Contributors
8978 * Released under the MIT License
8979 */
8980
8981
8982
8983 class Animator {
8984 constructor(){
8985 this._request = null;
8986 this._charts = new Map();
8987 this._running = false;
8988 this._lastDate = undefined;
8989 }
8990 _notify(chart, anims, date, type) {
8991 const callbacks = anims.listeners[type];
8992 const numSteps = anims.duration;
8993 callbacks.forEach((fn)=>fn({
8994 chart,
8995 initial: anims.initial,
8996 numSteps,
8997 currentStep: Math.min(date - anims.start, numSteps)
8998 }));
8999 }
9000 _refresh() {
9001 if (this._request) {
9002 return;
9003 }
9004 this._running = true;
9005 this._request = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.r.call(window, ()=>{
9006 this._update();
9007 this._request = null;
9008 if (this._running) {
9009 this._refresh();
9010 }
9011 });
9012 }
9013 _update(date = Date.now()) {
9014 let remaining = 0;
9015 this._charts.forEach((anims, chart)=>{
9016 if (!anims.running || !anims.items.length) {
9017 return;
9018 }
9019 const items = anims.items;
9020 let i = items.length - 1;
9021 let draw = false;
9022 let item;
9023 for(; i >= 0; --i){
9024 item = items[i];
9025 if (item._active) {
9026 if (item._total > anims.duration) {
9027 anims.duration = item._total;
9028 }
9029 item.tick(date);
9030 draw = true;
9031 } else {
9032 items[i] = items[items.length - 1];
9033 items.pop();
9034 }
9035 }
9036 if (draw) {
9037 chart.draw();
9038 this._notify(chart, anims, date, 'progress');
9039 }
9040 if (!items.length) {
9041 anims.running = false;
9042 this._notify(chart, anims, date, 'complete');
9043 anims.initial = false;
9044 }
9045 remaining += items.length;
9046 });
9047 this._lastDate = date;
9048 if (remaining === 0) {
9049 this._running = false;
9050 }
9051 }
9052 _getAnims(chart) {
9053 const charts = this._charts;
9054 let anims = charts.get(chart);
9055 if (!anims) {
9056 anims = {
9057 running: false,
9058 initial: true,
9059 items: [],
9060 listeners: {
9061 complete: [],
9062 progress: []
9063 }
9064 };
9065 charts.set(chart, anims);
9066 }
9067 return anims;
9068 }
9069 listen(chart, event, cb) {
9070 this._getAnims(chart).listeners[event].push(cb);
9071 }
9072 add(chart, items) {
9073 if (!items || !items.length) {
9074 return;
9075 }
9076 this._getAnims(chart).items.push(...items);
9077 }
9078 has(chart) {
9079 return this._getAnims(chart).items.length > 0;
9080 }
9081 start(chart) {
9082 const anims = this._charts.get(chart);
9083 if (!anims) {
9084 return;
9085 }
9086 anims.running = true;
9087 anims.start = Date.now();
9088 anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0);
9089 this._refresh();
9090 }
9091 running(chart) {
9092 if (!this._running) {
9093 return false;
9094 }
9095 const anims = this._charts.get(chart);
9096 if (!anims || !anims.running || !anims.items.length) {
9097 return false;
9098 }
9099 return true;
9100 }
9101 stop(chart) {
9102 const anims = this._charts.get(chart);
9103 if (!anims || !anims.items.length) {
9104 return;
9105 }
9106 const items = anims.items;
9107 let i = items.length - 1;
9108 for(; i >= 0; --i){
9109 items[i].cancel();
9110 }
9111 anims.items = [];
9112 this._notify(chart, anims, Date.now(), 'complete');
9113 }
9114 remove(chart) {
9115 return this._charts.delete(chart);
9116 }
9117 }
9118 var animator = /* #__PURE__ */ new Animator();
9119
9120 const transparent = 'transparent';
9121 const interpolators = {
9122 boolean (from, to, factor) {
9123 return factor > 0.5 ? to : from;
9124 },
9125 color (from, to, factor) {
9126 const c0 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(from || transparent);
9127 const c1 = c0.valid && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(to || transparent);
9128 return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;
9129 },
9130 number (from, to, factor) {
9131 return from + (to - from) * factor;
9132 }
9133 };
9134 class Animation {
9135 constructor(cfg, target, prop, to){
9136 const currentValue = target[prop];
9137 to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9138 cfg.to,
9139 to,
9140 currentValue,
9141 cfg.from
9142 ]);
9143 const from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9144 cfg.from,
9145 currentValue,
9146 to
9147 ]);
9148 this._active = true;
9149 this._fn = cfg.fn || interpolators[cfg.type || typeof from];
9150 this._easing = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e[cfg.easing] || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e.linear;
9151 this._start = Math.floor(Date.now() + (cfg.delay || 0));
9152 this._duration = this._total = Math.floor(cfg.duration);
9153 this._loop = !!cfg.loop;
9154 this._target = target;
9155 this._prop = prop;
9156 this._from = from;
9157 this._to = to;
9158 this._promises = undefined;
9159 }
9160 active() {
9161 return this._active;
9162 }
9163 update(cfg, to, date) {
9164 if (this._active) {
9165 this._notify(false);
9166 const currentValue = this._target[this._prop];
9167 const elapsed = date - this._start;
9168 const remain = this._duration - elapsed;
9169 this._start = date;
9170 this._duration = Math.floor(Math.max(remain, cfg.duration));
9171 this._total += elapsed;
9172 this._loop = !!cfg.loop;
9173 this._to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9174 cfg.to,
9175 to,
9176 currentValue,
9177 cfg.from
9178 ]);
9179 this._from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9180 cfg.from,
9181 currentValue,
9182 to
9183 ]);
9184 }
9185 }
9186 cancel() {
9187 if (this._active) {
9188 this.tick(Date.now());
9189 this._active = false;
9190 this._notify(false);
9191 }
9192 }
9193 tick(date) {
9194 const elapsed = date - this._start;
9195 const duration = this._duration;
9196 const prop = this._prop;
9197 const from = this._from;
9198 const loop = this._loop;
9199 const to = this._to;
9200 let factor;
9201 this._active = from !== to && (loop || elapsed < duration);
9202 if (!this._active) {
9203 this._target[prop] = to;
9204 this._notify(true);
9205 return;
9206 }
9207 if (elapsed < 0) {
9208 this._target[prop] = from;
9209 return;
9210 }
9211 factor = elapsed / duration % 2;
9212 factor = loop && factor > 1 ? 2 - factor : factor;
9213 factor = this._easing(Math.min(1, Math.max(0, factor)));
9214 this._target[prop] = this._fn(from, to, factor);
9215 }
9216 wait() {
9217 const promises = this._promises || (this._promises = []);
9218 return new Promise((res, rej)=>{
9219 promises.push({
9220 res,
9221 rej
9222 });
9223 });
9224 }
9225 _notify(resolved) {
9226 const method = resolved ? 'res' : 'rej';
9227 const promises = this._promises || [];
9228 for(let i = 0; i < promises.length; i++){
9229 promises[i][method]();
9230 }
9231 }
9232 }
9233
9234 class Animations {
9235 constructor(chart, config){
9236 this._chart = chart;
9237 this._properties = new Map();
9238 this.configure(config);
9239 }
9240 configure(config) {
9241 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(config)) {
9242 return;
9243 }
9244 const animationOptions = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.animation);
9245 const animatedProps = this._properties;
9246 Object.getOwnPropertyNames(config).forEach((key)=>{
9247 const cfg = config[key];
9248 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(cfg)) {
9249 return;
9250 }
9251 const resolved = {};
9252 for (const option of animationOptions){
9253 resolved[option] = cfg[option];
9254 }
9255 ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(cfg.properties) && cfg.properties || [
9256 key
9257 ]).forEach((prop)=>{
9258 if (prop === key || !animatedProps.has(prop)) {
9259 animatedProps.set(prop, resolved);
9260 }
9261 });
9262 });
9263 }
9264 _animateOptions(target, values) {
9265 const newOptions = values.options;
9266 const options = resolveTargetOptions(target, newOptions);
9267 if (!options) {
9268 return [];
9269 }
9270 const animations = this._createAnimations(options, newOptions);
9271 if (newOptions.$shared) {
9272 awaitAll(target.options.$animations, newOptions).then(()=>{
9273 target.options = newOptions;
9274 }, ()=>{
9275 });
9276 }
9277 return animations;
9278 }
9279 _createAnimations(target, values) {
9280 const animatedProps = this._properties;
9281 const animations = [];
9282 const running = target.$animations || (target.$animations = {});
9283 const props = Object.keys(values);
9284 const date = Date.now();
9285 let i;
9286 for(i = props.length - 1; i >= 0; --i){
9287 const prop = props[i];
9288 if (prop.charAt(0) === '$') {
9289 continue;
9290 }
9291 if (prop === 'options') {
9292 animations.push(...this._animateOptions(target, values));
9293 continue;
9294 }
9295 const value = values[prop];
9296 let animation = running[prop];
9297 const cfg = animatedProps.get(prop);
9298 if (animation) {
9299 if (cfg && animation.active()) {
9300 animation.update(cfg, value, date);
9301 continue;
9302 } else {
9303 animation.cancel();
9304 }
9305 }
9306 if (!cfg || !cfg.duration) {
9307 target[prop] = value;
9308 continue;
9309 }
9310 running[prop] = animation = new Animation(cfg, target, prop, value);
9311 animations.push(animation);
9312 }
9313 return animations;
9314 }
9315 update(target, values) {
9316 if (this._properties.size === 0) {
9317 Object.assign(target, values);
9318 return;
9319 }
9320 const animations = this._createAnimations(target, values);
9321 if (animations.length) {
9322 animator.add(this._chart, animations);
9323 return true;
9324 }
9325 }
9326 }
9327 function awaitAll(animations, properties) {
9328 const running = [];
9329 const keys = Object.keys(properties);
9330 for(let i = 0; i < keys.length; i++){
9331 const anim = animations[keys[i]];
9332 if (anim && anim.active()) {
9333 running.push(anim.wait());
9334 }
9335 }
9336 return Promise.all(running);
9337 }
9338 function resolveTargetOptions(target, newOptions) {
9339 if (!newOptions) {
9340 return;
9341 }
9342 let options = target.options;
9343 if (!options) {
9344 target.options = newOptions;
9345 return;
9346 }
9347 if (options.$shared) {
9348 target.options = options = Object.assign({}, options, {
9349 $shared: false,
9350 $animations: {}
9351 });
9352 }
9353 return options;
9354 }
9355
9356 function scaleClip(scale, allowedOverflow) {
9357 const opts = scale && scale.options || {};
9358 const reverse = opts.reverse;
9359 const min = opts.min === undefined ? allowedOverflow : 0;
9360 const max = opts.max === undefined ? allowedOverflow : 0;
9361 return {
9362 start: reverse ? max : min,
9363 end: reverse ? min : max
9364 };
9365 }
9366 function defaultClip(xScale, yScale, allowedOverflow) {
9367 if (allowedOverflow === false) {
9368 return false;
9369 }
9370 const x = scaleClip(xScale, allowedOverflow);
9371 const y = scaleClip(yScale, allowedOverflow);
9372 return {
9373 top: y.end,
9374 right: x.end,
9375 bottom: y.start,
9376 left: x.start
9377 };
9378 }
9379 function toClip(value) {
9380 let t, r, b, l;
9381 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value)) {
9382 t = value.top;
9383 r = value.right;
9384 b = value.bottom;
9385 l = value.left;
9386 } else {
9387 t = r = b = l = value;
9388 }
9389 return {
9390 top: t,
9391 right: r,
9392 bottom: b,
9393 left: l,
9394 disabled: value === false
9395 };
9396 }
9397 function getSortedDatasetIndices(chart, filterVisible) {
9398 const keys = [];
9399 const metasets = chart._getSortedDatasetMetas(filterVisible);
9400 let i, ilen;
9401 for(i = 0, ilen = metasets.length; i < ilen; ++i){
9402 keys.push(metasets[i].index);
9403 }
9404 return keys;
9405 }
9406 function applyStack(stack, value, dsIndex, options = {}) {
9407 const keys = stack.keys;
9408 const singleMode = options.mode === 'single';
9409 let i, ilen, datasetIndex, otherValue;
9410 if (value === null) {
9411 return;
9412 }
9413 let found = false;
9414 for(i = 0, ilen = keys.length; i < ilen; ++i){
9415 datasetIndex = +keys[i];
9416 if (datasetIndex === dsIndex) {
9417 found = true;
9418 if (options.all) {
9419 continue;
9420 }
9421 break;
9422 }
9423 otherValue = stack.values[datasetIndex];
9424 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))) {
9425 value += otherValue;
9426 }
9427 }
9428 if (!found && !options.all) {
9429 return 0;
9430 }
9431 return value;
9432 }
9433 function convertObjectDataToArray(data, meta) {
9434 const { iScale , vScale } = meta;
9435 const iAxisKey = iScale.axis === 'x' ? 'x' : 'y';
9436 const vAxisKey = vScale.axis === 'x' ? 'x' : 'y';
9437 const keys = Object.keys(data);
9438 const adata = new Array(keys.length);
9439 let i, ilen, key;
9440 for(i = 0, ilen = keys.length; i < ilen; ++i){
9441 key = keys[i];
9442 adata[i] = {
9443 [iAxisKey]: key,
9444 [vAxisKey]: data[key]
9445 };
9446 }
9447 return adata;
9448 }
9449 function isStacked(scale, meta) {
9450 const stacked = scale && scale.options.stacked;
9451 return stacked || stacked === undefined && meta.stack !== undefined;
9452 }
9453 function getStackKey(indexScale, valueScale, meta) {
9454 return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
9455 }
9456 function getUserBounds(scale) {
9457 const { min , max , minDefined , maxDefined } = scale.getUserBounds();
9458 return {
9459 min: minDefined ? min : Number.NEGATIVE_INFINITY,
9460 max: maxDefined ? max : Number.POSITIVE_INFINITY
9461 };
9462 }
9463 function getOrCreateStack(stacks, stackKey, indexValue) {
9464 const subStack = stacks[stackKey] || (stacks[stackKey] = {});
9465 return subStack[indexValue] || (subStack[indexValue] = {});
9466 }
9467 function getLastIndexInStack(stack, vScale, positive, type) {
9468 for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){
9469 const value = stack[meta.index];
9470 if (positive && value > 0 || !positive && value < 0) {
9471 return meta.index;
9472 }
9473 }
9474 return null;
9475 }
9476 function updateStacks(controller, parsed) {
9477 const { chart , _cachedMeta: meta } = controller;
9478 const stacks = chart._stacks || (chart._stacks = {});
9479 const { iScale , vScale , index: datasetIndex } = meta;
9480 const iAxis = iScale.axis;
9481 const vAxis = vScale.axis;
9482 const key = getStackKey(iScale, vScale, meta);
9483 const ilen = parsed.length;
9484 let stack;
9485 for(let i = 0; i < ilen; ++i){
9486 const item = parsed[i];
9487 const { [iAxis]: index , [vAxis]: value } = item;
9488 const itemStacks = item._stacks || (item._stacks = {});
9489 stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
9490 stack[datasetIndex] = value;
9491 stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
9492 stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
9493 const visualValues = stack._visualValues || (stack._visualValues = {});
9494 visualValues[datasetIndex] = value;
9495 }
9496 }
9497 function getFirstScaleId(chart, axis) {
9498 const scales = chart.scales;
9499 return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift();
9500 }
9501 function createDatasetContext(parent, index) {
9502 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9503 active: false,
9504 dataset: undefined,
9505 datasetIndex: index,
9506 index,
9507 mode: 'default',
9508 type: 'dataset'
9509 });
9510 }
9511 function createDataContext(parent, index, element) {
9512 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9513 active: false,
9514 dataIndex: index,
9515 parsed: undefined,
9516 raw: undefined,
9517 element,
9518 index,
9519 mode: 'default',
9520 type: 'data'
9521 });
9522 }
9523 function clearStacks(meta, items) {
9524 const datasetIndex = meta.controller.index;
9525 const axis = meta.vScale && meta.vScale.axis;
9526 if (!axis) {
9527 return;
9528 }
9529 items = items || meta._parsed;
9530 for (const parsed of items){
9531 const stacks = parsed._stacks;
9532 if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {
9533 return;
9534 }
9535 delete stacks[axis][datasetIndex];
9536 if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) {
9537 delete stacks[axis]._visualValues[datasetIndex];
9538 }
9539 }
9540 }
9541 const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none';
9542 const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached);
9543 const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && {
9544 keys: getSortedDatasetIndices(chart, true),
9545 values: null
9546 };
9547 class DatasetController {
9548 static defaults = {};
9549 static datasetElementType = null;
9550 static dataElementType = null;
9551 constructor(chart, datasetIndex){
9552 this.chart = chart;
9553 this._ctx = chart.ctx;
9554 this.index = datasetIndex;
9555 this._cachedDataOpts = {};
9556 this._cachedMeta = this.getMeta();
9557 this._type = this._cachedMeta.type;
9558 this.options = undefined;
9559 this._parsing = false;
9560 this._data = undefined;
9561 this._objectData = undefined;
9562 this._sharedOptions = undefined;
9563 this._drawStart = undefined;
9564 this._drawCount = undefined;
9565 this.enableOptionSharing = false;
9566 this.supportsDecimation = false;
9567 this.$context = undefined;
9568 this._syncList = [];
9569 this.datasetElementType = new.target.datasetElementType;
9570 this.dataElementType = new.target.dataElementType;
9571 this.initialize();
9572 }
9573 initialize() {
9574 const meta = this._cachedMeta;
9575 this.configure();
9576 this.linkScales();
9577 meta._stacked = isStacked(meta.vScale, meta);
9578 this.addElements();
9579 if (this.options.fill && !this.chart.isPluginEnabled('filler')) {
9580 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");
9581 }
9582 }
9583 updateIndex(datasetIndex) {
9584 if (this.index !== datasetIndex) {
9585 clearStacks(this._cachedMeta);
9586 }
9587 this.index = datasetIndex;
9588 }
9589 linkScales() {
9590 const chart = this.chart;
9591 const meta = this._cachedMeta;
9592 const dataset = this.getDataset();
9593 const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y;
9594 const xid = meta.xAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.xAxisID, getFirstScaleId(chart, 'x'));
9595 const yid = meta.yAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.yAxisID, getFirstScaleId(chart, 'y'));
9596 const rid = meta.rAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.rAxisID, getFirstScaleId(chart, 'r'));
9597 const indexAxis = meta.indexAxis;
9598 const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
9599 const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
9600 meta.xScale = this.getScaleForId(xid);
9601 meta.yScale = this.getScaleForId(yid);
9602 meta.rScale = this.getScaleForId(rid);
9603 meta.iScale = this.getScaleForId(iid);
9604 meta.vScale = this.getScaleForId(vid);
9605 }
9606 getDataset() {
9607 return this.chart.data.datasets[this.index];
9608 }
9609 getMeta() {
9610 return this.chart.getDatasetMeta(this.index);
9611 }
9612 getScaleForId(scaleID) {
9613 return this.chart.scales[scaleID];
9614 }
9615 _getOtherScale(scale) {
9616 const meta = this._cachedMeta;
9617 return scale === meta.iScale ? meta.vScale : meta.iScale;
9618 }
9619 reset() {
9620 this._update('reset');
9621 }
9622 _destroy() {
9623 const meta = this._cachedMeta;
9624 if (this._data) {
9625 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(this._data, this);
9626 }
9627 if (meta._stacked) {
9628 clearStacks(meta);
9629 }
9630 }
9631 _dataCheck() {
9632 const dataset = this.getDataset();
9633 const data = dataset.data || (dataset.data = []);
9634 const _data = this._data;
9635 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data)) {
9636 const meta = this._cachedMeta;
9637 this._data = convertObjectDataToArray(data, meta);
9638 } else if (_data !== data) {
9639 if (_data) {
9640 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(_data, this);
9641 const meta = this._cachedMeta;
9642 clearStacks(meta);
9643 meta._parsed = [];
9644 }
9645 if (data && Object.isExtensible(data)) {
9646 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.l)(data, this);
9647 }
9648 this._syncList = [];
9649 this._data = data;
9650 }
9651 }
9652 addElements() {
9653 const meta = this._cachedMeta;
9654 this._dataCheck();
9655 if (this.datasetElementType) {
9656 meta.dataset = new this.datasetElementType();
9657 }
9658 }
9659 buildOrUpdateElements(resetNewElements) {
9660 const meta = this._cachedMeta;
9661 const dataset = this.getDataset();
9662 let stackChanged = false;
9663 this._dataCheck();
9664 const oldStacked = meta._stacked;
9665 meta._stacked = isStacked(meta.vScale, meta);
9666 if (meta.stack !== dataset.stack) {
9667 stackChanged = true;
9668 clearStacks(meta);
9669 meta.stack = dataset.stack;
9670 }
9671 this._resyncElements(resetNewElements);
9672 if (stackChanged || oldStacked !== meta._stacked) {
9673 updateStacks(this, meta._parsed);
9674 meta._stacked = isStacked(meta.vScale, meta);
9675 }
9676 }
9677 configure() {
9678 const config = this.chart.config;
9679 const scopeKeys = config.datasetScopeKeys(this._type);
9680 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
9681 this.options = config.createResolver(scopes, this.getContext());
9682 this._parsing = this.options.parsing;
9683 this._cachedDataOpts = {};
9684 }
9685 parse(start, count) {
9686 const { _cachedMeta: meta , _data: data } = this;
9687 const { iScale , _stacked } = meta;
9688 const iAxis = iScale.axis;
9689 let sorted = start === 0 && count === data.length ? true : meta._sorted;
9690 let prev = start > 0 && meta._parsed[start - 1];
9691 let i, cur, parsed;
9692 if (this._parsing === false) {
9693 meta._parsed = data;
9694 meta._sorted = true;
9695 parsed = data;
9696 } else {
9697 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(data[start])) {
9698 parsed = this.parseArrayData(meta, data, start, count);
9699 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
9700 parsed = this.parseObjectData(meta, data, start, count);
9701 } else {
9702 parsed = this.parsePrimitiveData(meta, data, start, count);
9703 }
9704 const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];
9705 for(i = 0; i < count; ++i){
9706 meta._parsed[i + start] = cur = parsed[i];
9707 if (sorted) {
9708 if (isNotInOrderComparedToPrev()) {
9709 sorted = false;
9710 }
9711 prev = cur;
9712 }
9713 }
9714 meta._sorted = sorted;
9715 }
9716 if (_stacked) {
9717 updateStacks(this, parsed);
9718 }
9719 }
9720 parsePrimitiveData(meta, data, start, count) {
9721 const { iScale , vScale } = meta;
9722 const iAxis = iScale.axis;
9723 const vAxis = vScale.axis;
9724 const labels = iScale.getLabels();
9725 const singleScale = iScale === vScale;
9726 const parsed = new Array(count);
9727 let i, ilen, index;
9728 for(i = 0, ilen = count; i < ilen; ++i){
9729 index = i + start;
9730 parsed[i] = {
9731 [iAxis]: singleScale || iScale.parse(labels[index], index),
9732 [vAxis]: vScale.parse(data[index], index)
9733 };
9734 }
9735 return parsed;
9736 }
9737 parseArrayData(meta, data, start, count) {
9738 const { xScale , yScale } = meta;
9739 const parsed = new Array(count);
9740 let i, ilen, index, item;
9741 for(i = 0, ilen = count; i < ilen; ++i){
9742 index = i + start;
9743 item = data[index];
9744 parsed[i] = {
9745 x: xScale.parse(item[0], index),
9746 y: yScale.parse(item[1], index)
9747 };
9748 }
9749 return parsed;
9750 }
9751 parseObjectData(meta, data, start, count) {
9752 const { xScale , yScale } = meta;
9753 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
9754 const parsed = new Array(count);
9755 let i, ilen, index, item;
9756 for(i = 0, ilen = count; i < ilen; ++i){
9757 index = i + start;
9758 item = data[index];
9759 parsed[i] = {
9760 x: xScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, xAxisKey), index),
9761 y: yScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, yAxisKey), index)
9762 };
9763 }
9764 return parsed;
9765 }
9766 getParsed(index) {
9767 return this._cachedMeta._parsed[index];
9768 }
9769 getDataElement(index) {
9770 return this._cachedMeta.data[index];
9771 }
9772 applyStack(scale, parsed, mode) {
9773 const chart = this.chart;
9774 const meta = this._cachedMeta;
9775 const value = parsed[scale.axis];
9776 const stack = {
9777 keys: getSortedDatasetIndices(chart, true),
9778 values: parsed._stacks[scale.axis]._visualValues
9779 };
9780 return applyStack(stack, value, meta.index, {
9781 mode
9782 });
9783 }
9784 updateRangeFromParsed(range, scale, parsed, stack) {
9785 const parsedValue = parsed[scale.axis];
9786 let value = parsedValue === null ? NaN : parsedValue;
9787 const values = stack && parsed._stacks[scale.axis];
9788 if (stack && values) {
9789 stack.values = values;
9790 value = applyStack(stack, parsedValue, this._cachedMeta.index);
9791 }
9792 range.min = Math.min(range.min, value);
9793 range.max = Math.max(range.max, value);
9794 }
9795 getMinMax(scale, canStack) {
9796 const meta = this._cachedMeta;
9797 const _parsed = meta._parsed;
9798 const sorted = meta._sorted && scale === meta.iScale;
9799 const ilen = _parsed.length;
9800 const otherScale = this._getOtherScale(scale);
9801 const stack = createStack(canStack, meta, this.chart);
9802 const range = {
9803 min: Number.POSITIVE_INFINITY,
9804 max: Number.NEGATIVE_INFINITY
9805 };
9806 const { min: otherMin , max: otherMax } = getUserBounds(otherScale);
9807 let i, parsed;
9808 function _skip() {
9809 parsed = _parsed[i];
9810 const otherValue = parsed[otherScale.axis];
9811 return !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
9812 }
9813 for(i = 0; i < ilen; ++i){
9814 if (_skip()) {
9815 continue;
9816 }
9817 this.updateRangeFromParsed(range, scale, parsed, stack);
9818 if (sorted) {
9819 break;
9820 }
9821 }
9822 if (sorted) {
9823 for(i = ilen - 1; i >= 0; --i){
9824 if (_skip()) {
9825 continue;
9826 }
9827 this.updateRangeFromParsed(range, scale, parsed, stack);
9828 break;
9829 }
9830 }
9831 return range;
9832 }
9833 getAllParsedValues(scale) {
9834 const parsed = this._cachedMeta._parsed;
9835 const values = [];
9836 let i, ilen, value;
9837 for(i = 0, ilen = parsed.length; i < ilen; ++i){
9838 value = parsed[i][scale.axis];
9839 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
9840 values.push(value);
9841 }
9842 }
9843 return values;
9844 }
9845 getMaxOverflow() {
9846 return false;
9847 }
9848 getLabelAndValue(index) {
9849 const meta = this._cachedMeta;
9850 const iScale = meta.iScale;
9851 const vScale = meta.vScale;
9852 const parsed = this.getParsed(index);
9853 return {
9854 label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
9855 value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
9856 };
9857 }
9858 _update(mode) {
9859 const meta = this._cachedMeta;
9860 this.update(mode || 'default');
9861 meta._clip = toClip((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
9862 }
9863 update(mode) {}
9864 draw() {
9865 const ctx = this._ctx;
9866 const chart = this.chart;
9867 const meta = this._cachedMeta;
9868 const elements = meta.data || [];
9869 const area = chart.chartArea;
9870 const active = [];
9871 const start = this._drawStart || 0;
9872 const count = this._drawCount || elements.length - start;
9873 const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
9874 let i;
9875 if (meta.dataset) {
9876 meta.dataset.draw(ctx, area, start, count);
9877 }
9878 for(i = start; i < start + count; ++i){
9879 const element = elements[i];
9880 if (element.hidden) {
9881 continue;
9882 }
9883 if (element.active && drawActiveElementsOnTop) {
9884 active.push(element);
9885 } else {
9886 element.draw(ctx, area);
9887 }
9888 }
9889 for(i = 0; i < active.length; ++i){
9890 active[i].draw(ctx, area);
9891 }
9892 }
9893 getStyle(index, active) {
9894 const mode = active ? 'active' : 'default';
9895 return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);
9896 }
9897 getContext(index, active, mode) {
9898 const dataset = this.getDataset();
9899 let context;
9900 if (index >= 0 && index < this._cachedMeta.data.length) {
9901 const element = this._cachedMeta.data[index];
9902 context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));
9903 context.parsed = this.getParsed(index);
9904 context.raw = dataset.data[index];
9905 context.index = context.dataIndex = index;
9906 } else {
9907 context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));
9908 context.dataset = dataset;
9909 context.index = context.datasetIndex = this.index;
9910 }
9911 context.active = !!active;
9912 context.mode = mode;
9913 return context;
9914 }
9915 resolveDatasetElementOptions(mode) {
9916 return this._resolveElementOptions(this.datasetElementType.id, mode);
9917 }
9918 resolveDataElementOptions(index, mode) {
9919 return this._resolveElementOptions(this.dataElementType.id, mode, index);
9920 }
9921 _resolveElementOptions(elementType, mode = 'default', index) {
9922 const active = mode === 'active';
9923 const cache = this._cachedDataOpts;
9924 const cacheKey = elementType + '-' + mode;
9925 const cached = cache[cacheKey];
9926 const sharing = this.enableOptionSharing && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(index);
9927 if (cached) {
9928 return cloneIfNotShared(cached, sharing);
9929 }
9930 const config = this.chart.config;
9931 const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
9932 const prefixes = active ? [
9933 `${elementType}Hover`,
9934 'hover',
9935 elementType,
9936 ''
9937 ] : [
9938 elementType,
9939 ''
9940 ];
9941 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
9942 const names = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.elements[elementType]);
9943 const context = ()=>this.getContext(index, active, mode);
9944 const values = config.resolveNamedOptions(scopes, names, context, prefixes);
9945 if (values.$shared) {
9946 values.$shared = sharing;
9947 cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
9948 }
9949 return values;
9950 }
9951 _resolveAnimations(index, transition, active) {
9952 const chart = this.chart;
9953 const cache = this._cachedDataOpts;
9954 const cacheKey = `animation-${transition}`;
9955 const cached = cache[cacheKey];
9956 if (cached) {
9957 return cached;
9958 }
9959 let options;
9960 if (chart.options.animation !== false) {
9961 const config = this.chart.config;
9962 const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
9963 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
9964 options = config.createResolver(scopes, this.getContext(index, active, transition));
9965 }
9966 const animations = new Animations(chart, options && options.animations);
9967 if (options && options._cacheable) {
9968 cache[cacheKey] = Object.freeze(animations);
9969 }
9970 return animations;
9971 }
9972 getSharedOptions(options) {
9973 if (!options.$shared) {
9974 return;
9975 }
9976 return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
9977 }
9978 includeOptions(mode, sharedOptions) {
9979 return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
9980 }
9981 _getSharedOptions(start, mode) {
9982 const firstOpts = this.resolveDataElementOptions(start, mode);
9983 const previouslySharedOptions = this._sharedOptions;
9984 const sharedOptions = this.getSharedOptions(firstOpts);
9985 const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;
9986 this.updateSharedOptions(sharedOptions, mode, firstOpts);
9987 return {
9988 sharedOptions,
9989 includeOptions
9990 };
9991 }
9992 updateElement(element, index, properties, mode) {
9993 if (isDirectUpdateMode(mode)) {
9994 Object.assign(element, properties);
9995 } else {
9996 this._resolveAnimations(index, mode).update(element, properties);
9997 }
9998 }
9999 updateSharedOptions(sharedOptions, mode, newOptions) {
10000 if (sharedOptions && !isDirectUpdateMode(mode)) {
10001 this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);
10002 }
10003 }
10004 _setStyle(element, index, mode, active) {
10005 element.active = active;
10006 const options = this.getStyle(index, active);
10007 this._resolveAnimations(index, mode, active).update(element, {
10008 options: !active && this.getSharedOptions(options) || options
10009 });
10010 }
10011 removeHoverStyle(element, datasetIndex, index) {
10012 this._setStyle(element, index, 'active', false);
10013 }
10014 setHoverStyle(element, datasetIndex, index) {
10015 this._setStyle(element, index, 'active', true);
10016 }
10017 _removeDatasetHoverStyle() {
10018 const element = this._cachedMeta.dataset;
10019 if (element) {
10020 this._setStyle(element, undefined, 'active', false);
10021 }
10022 }
10023 _setDatasetHoverStyle() {
10024 const element = this._cachedMeta.dataset;
10025 if (element) {
10026 this._setStyle(element, undefined, 'active', true);
10027 }
10028 }
10029 _resyncElements(resetNewElements) {
10030 const data = this._data;
10031 const elements = this._cachedMeta.data;
10032 for (const [method, arg1, arg2] of this._syncList){
10033 this[method](arg1, arg2);
10034 }
10035 this._syncList = [];
10036 const numMeta = elements.length;
10037 const numData = data.length;
10038 const count = Math.min(numData, numMeta);
10039 if (count) {
10040 this.parse(0, count);
10041 }
10042 if (numData > numMeta) {
10043 this._insertElements(numMeta, numData - numMeta, resetNewElements);
10044 } else if (numData < numMeta) {
10045 this._removeElements(numData, numMeta - numData);
10046 }
10047 }
10048 _insertElements(start, count, resetNewElements = true) {
10049 const meta = this._cachedMeta;
10050 const data = meta.data;
10051 const end = start + count;
10052 let i;
10053 const move = (arr)=>{
10054 arr.length += count;
10055 for(i = arr.length - 1; i >= end; i--){
10056 arr[i] = arr[i - count];
10057 }
10058 };
10059 move(data);
10060 for(i = start; i < end; ++i){
10061 data[i] = new this.dataElementType();
10062 }
10063 if (this._parsing) {
10064 move(meta._parsed);
10065 }
10066 this.parse(start, count);
10067 if (resetNewElements) {
10068 this.updateElements(data, start, count, 'reset');
10069 }
10070 }
10071 updateElements(element, start, count, mode) {}
10072 _removeElements(start, count) {
10073 const meta = this._cachedMeta;
10074 if (this._parsing) {
10075 const removed = meta._parsed.splice(start, count);
10076 if (meta._stacked) {
10077 clearStacks(meta, removed);
10078 }
10079 }
10080 meta.data.splice(start, count);
10081 }
10082 _sync(args) {
10083 if (this._parsing) {
10084 this._syncList.push(args);
10085 } else {
10086 const [method, arg1, arg2] = args;
10087 this[method](arg1, arg2);
10088 }
10089 this.chart._dataChanges.push([
10090 this.index,
10091 ...args
10092 ]);
10093 }
10094 _onDataPush() {
10095 const count = arguments.length;
10096 this._sync([
10097 '_insertElements',
10098 this.getDataset().data.length - count,
10099 count
10100 ]);
10101 }
10102 _onDataPop() {
10103 this._sync([
10104 '_removeElements',
10105 this._cachedMeta.data.length - 1,
10106 1
10107 ]);
10108 }
10109 _onDataShift() {
10110 this._sync([
10111 '_removeElements',
10112 0,
10113 1
10114 ]);
10115 }
10116 _onDataSplice(start, count) {
10117 if (count) {
10118 this._sync([
10119 '_removeElements',
10120 start,
10121 count
10122 ]);
10123 }
10124 const newCount = arguments.length - 2;
10125 if (newCount) {
10126 this._sync([
10127 '_insertElements',
10128 start,
10129 newCount
10130 ]);
10131 }
10132 }
10133 _onDataUnshift() {
10134 this._sync([
10135 '_insertElements',
10136 0,
10137 arguments.length
10138 ]);
10139 }
10140 }
10141
10142 function getAllScaleValues(scale, type) {
10143 if (!scale._cache.$bar) {
10144 const visibleMetas = scale.getMatchingVisibleMetas(type);
10145 let values = [];
10146 for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){
10147 values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));
10148 }
10149 scale._cache.$bar = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort((a, b)=>a - b));
10150 }
10151 return scale._cache.$bar;
10152 }
10153 function computeMinSampleSize(meta) {
10154 const scale = meta.iScale;
10155 const values = getAllScaleValues(scale, meta.type);
10156 let min = scale._length;
10157 let i, ilen, curr, prev;
10158 const updateMinAndPrev = ()=>{
10159 if (curr === 32767 || curr === -32768) {
10160 return;
10161 }
10162 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(prev)) {
10163 min = Math.min(min, Math.abs(curr - prev) || min);
10164 }
10165 prev = curr;
10166 };
10167 for(i = 0, ilen = values.length; i < ilen; ++i){
10168 curr = scale.getPixelForValue(values[i]);
10169 updateMinAndPrev();
10170 }
10171 prev = undefined;
10172 for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){
10173 curr = scale.getPixelForTick(i);
10174 updateMinAndPrev();
10175 }
10176 return min;
10177 }
10178 function computeFitCategoryTraits(index, ruler, options, stackCount) {
10179 const thickness = options.barThickness;
10180 let size, ratio;
10181 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(thickness)) {
10182 size = ruler.min * options.categoryPercentage;
10183 ratio = options.barPercentage;
10184 } else {
10185 size = thickness * stackCount;
10186 ratio = 1;
10187 }
10188 return {
10189 chunk: size / stackCount,
10190 ratio,
10191 start: ruler.pixels[index] - size / 2
10192 };
10193 }
10194 function computeFlexCategoryTraits(index, ruler, options, stackCount) {
10195 const pixels = ruler.pixels;
10196 const curr = pixels[index];
10197 let prev = index > 0 ? pixels[index - 1] : null;
10198 let next = index < pixels.length - 1 ? pixels[index + 1] : null;
10199 const percent = options.categoryPercentage;
10200 if (prev === null) {
10201 prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
10202 }
10203 if (next === null) {
10204 next = curr + curr - prev;
10205 }
10206 const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
10207 const size = Math.abs(next - prev) / 2 * percent;
10208 return {
10209 chunk: size / stackCount,
10210 ratio: options.barPercentage,
10211 start
10212 };
10213 }
10214 function parseFloatBar(entry, item, vScale, i) {
10215 const startValue = vScale.parse(entry[0], i);
10216 const endValue = vScale.parse(entry[1], i);
10217 const min = Math.min(startValue, endValue);
10218 const max = Math.max(startValue, endValue);
10219 let barStart = min;
10220 let barEnd = max;
10221 if (Math.abs(min) > Math.abs(max)) {
10222 barStart = max;
10223 barEnd = min;
10224 }
10225 item[vScale.axis] = barEnd;
10226 item._custom = {
10227 barStart,
10228 barEnd,
10229 start: startValue,
10230 end: endValue,
10231 min,
10232 max
10233 };
10234 }
10235 function parseValue(entry, item, vScale, i) {
10236 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(entry)) {
10237 parseFloatBar(entry, item, vScale, i);
10238 } else {
10239 item[vScale.axis] = vScale.parse(entry, i);
10240 }
10241 return item;
10242 }
10243 function parseArrayOrPrimitive(meta, data, start, count) {
10244 const iScale = meta.iScale;
10245 const vScale = meta.vScale;
10246 const labels = iScale.getLabels();
10247 const singleScale = iScale === vScale;
10248 const parsed = [];
10249 let i, ilen, item, entry;
10250 for(i = start, ilen = start + count; i < ilen; ++i){
10251 entry = data[i];
10252 item = {};
10253 item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
10254 parsed.push(parseValue(entry, item, vScale, i));
10255 }
10256 return parsed;
10257 }
10258 function isFloatBar(custom) {
10259 return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
10260 }
10261 function barSign(size, vScale, actualBase) {
10262 if (size !== 0) {
10263 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size);
10264 }
10265 return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
10266 }
10267 function borderProps(properties) {
10268 let reverse, start, end, top, bottom;
10269 if (properties.horizontal) {
10270 reverse = properties.base > properties.x;
10271 start = 'left';
10272 end = 'right';
10273 } else {
10274 reverse = properties.base < properties.y;
10275 start = 'bottom';
10276 end = 'top';
10277 }
10278 if (reverse) {
10279 top = 'end';
10280 bottom = 'start';
10281 } else {
10282 top = 'start';
10283 bottom = 'end';
10284 }
10285 return {
10286 start,
10287 end,
10288 reverse,
10289 top,
10290 bottom
10291 };
10292 }
10293 function setBorderSkipped(properties, options, stack, index) {
10294 let edge = options.borderSkipped;
10295 const res = {};
10296 if (!edge) {
10297 properties.borderSkipped = res;
10298 return;
10299 }
10300 if (edge === true) {
10301 properties.borderSkipped = {
10302 top: true,
10303 right: true,
10304 bottom: true,
10305 left: true
10306 };
10307 return;
10308 }
10309 const { start , end , reverse , top , bottom } = borderProps(properties);
10310 if (edge === 'middle' && stack) {
10311 properties.enableBorderRadius = true;
10312 if ((stack._top || 0) === index) {
10313 edge = top;
10314 } else if ((stack._bottom || 0) === index) {
10315 edge = bottom;
10316 } else {
10317 res[parseEdge(bottom, start, end, reverse)] = true;
10318 edge = top;
10319 }
10320 }
10321 res[parseEdge(edge, start, end, reverse)] = true;
10322 properties.borderSkipped = res;
10323 }
10324 function parseEdge(edge, a, b, reverse) {
10325 if (reverse) {
10326 edge = swap(edge, a, b);
10327 edge = startEnd(edge, b, a);
10328 } else {
10329 edge = startEnd(edge, a, b);
10330 }
10331 return edge;
10332 }
10333 function swap(orig, v1, v2) {
10334 return orig === v1 ? v2 : orig === v2 ? v1 : orig;
10335 }
10336 function startEnd(v, start, end) {
10337 return v === 'start' ? start : v === 'end' ? end : v;
10338 }
10339 function setInflateAmount(properties, { inflateAmount }, ratio) {
10340 properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount;
10341 }
10342 class BarController extends DatasetController {
10343 static id = 'bar';
10344 static defaults = {
10345 datasetElementType: false,
10346 dataElementType: 'bar',
10347 categoryPercentage: 0.8,
10348 barPercentage: 0.9,
10349 grouped: true,
10350 animations: {
10351 numbers: {
10352 type: 'number',
10353 properties: [
10354 'x',
10355 'y',
10356 'base',
10357 'width',
10358 'height'
10359 ]
10360 }
10361 }
10362 };
10363 static overrides = {
10364 scales: {
10365 _index_: {
10366 type: 'category',
10367 offset: true,
10368 grid: {
10369 offset: true
10370 }
10371 },
10372 _value_: {
10373 type: 'linear',
10374 beginAtZero: true
10375 }
10376 }
10377 };
10378 parsePrimitiveData(meta, data, start, count) {
10379 return parseArrayOrPrimitive(meta, data, start, count);
10380 }
10381 parseArrayData(meta, data, start, count) {
10382 return parseArrayOrPrimitive(meta, data, start, count);
10383 }
10384 parseObjectData(meta, data, start, count) {
10385 const { iScale , vScale } = meta;
10386 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
10387 const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
10388 const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
10389 const parsed = [];
10390 let i, ilen, item, obj;
10391 for(i = start, ilen = start + count; i < ilen; ++i){
10392 obj = data[i];
10393 item = {};
10394 item[iScale.axis] = iScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, iAxisKey), i);
10395 parsed.push(parseValue((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, vAxisKey), item, vScale, i));
10396 }
10397 return parsed;
10398 }
10399 updateRangeFromParsed(range, scale, parsed, stack) {
10400 super.updateRangeFromParsed(range, scale, parsed, stack);
10401 const custom = parsed._custom;
10402 if (custom && scale === this._cachedMeta.vScale) {
10403 range.min = Math.min(range.min, custom.min);
10404 range.max = Math.max(range.max, custom.max);
10405 }
10406 }
10407 getMaxOverflow() {
10408 return 0;
10409 }
10410 getLabelAndValue(index) {
10411 const meta = this._cachedMeta;
10412 const { iScale , vScale } = meta;
10413 const parsed = this.getParsed(index);
10414 const custom = parsed._custom;
10415 const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]);
10416 return {
10417 label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
10418 value
10419 };
10420 }
10421 initialize() {
10422 this.enableOptionSharing = true;
10423 super.initialize();
10424 const meta = this._cachedMeta;
10425 meta.stack = this.getDataset().stack;
10426 }
10427 update(mode) {
10428 const meta = this._cachedMeta;
10429 this.updateElements(meta.data, 0, meta.data.length, mode);
10430 }
10431 updateElements(bars, start, count, mode) {
10432 const reset = mode === 'reset';
10433 const { index , _cachedMeta: { vScale } } = this;
10434 const base = vScale.getBasePixel();
10435 const horizontal = vScale.isHorizontal();
10436 const ruler = this._getRuler();
10437 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10438 for(let i = start; i < start + count; i++){
10439 const parsed = this.getParsed(i);
10440 const vpixels = reset || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vScale.axis]) ? {
10441 base,
10442 head: base
10443 } : this._calculateBarValuePixels(i);
10444 const ipixels = this._calculateBarIndexPixels(i, ruler);
10445 const stack = (parsed._stacks || {})[vScale.axis];
10446 const properties = {
10447 horizontal,
10448 base: vpixels.base,
10449 enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,
10450 x: horizontal ? vpixels.head : ipixels.center,
10451 y: horizontal ? ipixels.center : vpixels.head,
10452 height: horizontal ? ipixels.size : Math.abs(vpixels.size),
10453 width: horizontal ? Math.abs(vpixels.size) : ipixels.size
10454 };
10455 if (includeOptions) {
10456 properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);
10457 }
10458 const options = properties.options || bars[i].options;
10459 setBorderSkipped(properties, options, stack, index);
10460 setInflateAmount(properties, options, ruler.ratio);
10461 this.updateElement(bars[i], i, properties, mode);
10462 }
10463 }
10464 _getStacks(last, dataIndex) {
10465 const { iScale } = this._cachedMeta;
10466 const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped);
10467 const stacked = iScale.options.stacked;
10468 const stacks = [];
10469 const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);
10470 const iScaleValue = currentParsed && currentParsed[iScale.axis];
10471 const skipNull = (meta)=>{
10472 const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue);
10473 const val = parsed && parsed[meta.vScale.axis];
10474 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(val) || isNaN(val)) {
10475 return true;
10476 }
10477 };
10478 for (const meta of metasets){
10479 if (dataIndex !== undefined && skipNull(meta)) {
10480 continue;
10481 }
10482 if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) {
10483 stacks.push(meta.stack);
10484 }
10485 if (meta.index === last) {
10486 break;
10487 }
10488 }
10489 if (!stacks.length) {
10490 stacks.push(undefined);
10491 }
10492 return stacks;
10493 }
10494 _getStackCount(index) {
10495 return this._getStacks(undefined, index).length;
10496 }
10497 _getAxisCount() {
10498 return this._getAxis().length;
10499 }
10500 getFirstScaleIdForIndexAxis() {
10501 const scales = this.chart.scales;
10502 const indexScaleId = this.chart.options.indexAxis;
10503 return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift();
10504 }
10505 _getAxis() {
10506 const axis = {};
10507 const firstScaleAxisId = this.getFirstScaleIdForIndexAxis();
10508 for (const dataset of this.chart.data.datasets){
10509 axis[(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true;
10510 }
10511 return Object.keys(axis);
10512 }
10513 _getStackIndex(datasetIndex, name, dataIndex) {
10514 const stacks = this._getStacks(datasetIndex, dataIndex);
10515 const index = name !== undefined ? stacks.indexOf(name) : -1;
10516 return index === -1 ? stacks.length - 1 : index;
10517 }
10518 _getRuler() {
10519 const opts = this.options;
10520 const meta = this._cachedMeta;
10521 const iScale = meta.iScale;
10522 const pixels = [];
10523 let i, ilen;
10524 for(i = 0, ilen = meta.data.length; i < ilen; ++i){
10525 pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));
10526 }
10527 const barThickness = opts.barThickness;
10528 const min = barThickness || computeMinSampleSize(meta);
10529 return {
10530 min,
10531 pixels,
10532 start: iScale._startPixel,
10533 end: iScale._endPixel,
10534 stackCount: this._getStackCount(),
10535 scale: iScale,
10536 grouped: opts.grouped,
10537 ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
10538 };
10539 }
10540 _calculateBarValuePixels(index) {
10541 const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this;
10542 const actualBase = baseValue || 0;
10543 const parsed = this.getParsed(index);
10544 const custom = parsed._custom;
10545 const floating = isFloatBar(custom);
10546 let value = parsed[vScale.axis];
10547 let start = 0;
10548 let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
10549 let head, size;
10550 if (length !== value) {
10551 start = length - value;
10552 length = value;
10553 }
10554 if (floating) {
10555 value = custom.barStart;
10556 length = custom.barEnd - custom.barStart;
10557 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)) {
10558 start = 0;
10559 }
10560 start += value;
10561 }
10562 const startValue = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(baseValue) && !floating ? baseValue : start;
10563 let base = vScale.getPixelForValue(startValue);
10564 if (this.chart.getDataVisibility(index)) {
10565 head = vScale.getPixelForValue(start + length);
10566 } else {
10567 head = base;
10568 }
10569 size = head - base;
10570 if (Math.abs(size) < minBarLength) {
10571 size = barSign(size, vScale, actualBase) * minBarLength;
10572 if (value === actualBase) {
10573 base -= size / 2;
10574 }
10575 const startPixel = vScale.getPixelForDecimal(0);
10576 const endPixel = vScale.getPixelForDecimal(1);
10577 const min = Math.min(startPixel, endPixel);
10578 const max = Math.max(startPixel, endPixel);
10579 base = Math.max(Math.min(base, max), min);
10580 head = base + size;
10581 if (_stacked && !floating) {
10582 parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);
10583 }
10584 }
10585 if (base === vScale.getPixelForValue(actualBase)) {
10586 const halfGrid = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size) * vScale.getLineWidthForValue(actualBase) / 2;
10587 base += halfGrid;
10588 size -= halfGrid;
10589 }
10590 return {
10591 size,
10592 base,
10593 head,
10594 center: head + size / 2
10595 };
10596 }
10597 _calculateBarIndexPixels(index, ruler) {
10598 const scale = ruler.scale;
10599 const options = this.options;
10600 const skipNull = options.skipNull;
10601 const maxBarThickness = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.maxBarThickness, Infinity);
10602 let center, size;
10603 const axisCount = this._getAxisCount();
10604 if (ruler.grouped) {
10605 const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
10606 const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount);
10607 const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID;
10608 const axisNumber = this._getAxis().indexOf((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(axisID, this.getFirstScaleIdForIndexAxis()));
10609 const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber;
10610 center = range.start + range.chunk * stackIndex + range.chunk / 2;
10611 size = Math.min(maxBarThickness, range.chunk * range.ratio);
10612 } else {
10613 center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
10614 size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
10615 }
10616 return {
10617 base: center - size / 2,
10618 head: center + size / 2,
10619 center,
10620 size
10621 };
10622 }
10623 draw() {
10624 const meta = this._cachedMeta;
10625 const vScale = meta.vScale;
10626 const rects = meta.data;
10627 const ilen = rects.length;
10628 let i = 0;
10629 for(; i < ilen; ++i){
10630 if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) {
10631 rects[i].draw(this._ctx);
10632 }
10633 }
10634 }
10635 }
10636
10637 class BubbleController extends DatasetController {
10638 static id = 'bubble';
10639 static defaults = {
10640 datasetElementType: false,
10641 dataElementType: 'point',
10642 animations: {
10643 numbers: {
10644 type: 'number',
10645 properties: [
10646 'x',
10647 'y',
10648 'borderWidth',
10649 'radius'
10650 ]
10651 }
10652 }
10653 };
10654 static overrides = {
10655 scales: {
10656 x: {
10657 type: 'linear'
10658 },
10659 y: {
10660 type: 'linear'
10661 }
10662 }
10663 };
10664 initialize() {
10665 this.enableOptionSharing = true;
10666 super.initialize();
10667 }
10668 parsePrimitiveData(meta, data, start, count) {
10669 const parsed = super.parsePrimitiveData(meta, data, start, count);
10670 for(let i = 0; i < parsed.length; i++){
10671 parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;
10672 }
10673 return parsed;
10674 }
10675 parseArrayData(meta, data, start, count) {
10676 const parsed = super.parseArrayData(meta, data, start, count);
10677 for(let i = 0; i < parsed.length; i++){
10678 const item = data[start + i];
10679 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item[2], this.resolveDataElementOptions(i + start).radius);
10680 }
10681 return parsed;
10682 }
10683 parseObjectData(meta, data, start, count) {
10684 const parsed = super.parseObjectData(meta, data, start, count);
10685 for(let i = 0; i < parsed.length; i++){
10686 const item = data[start + i];
10687 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);
10688 }
10689 return parsed;
10690 }
10691 getMaxOverflow() {
10692 const data = this._cachedMeta.data;
10693 let max = 0;
10694 for(let i = data.length - 1; i >= 0; --i){
10695 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
10696 }
10697 return max > 0 && max;
10698 }
10699 getLabelAndValue(index) {
10700 const meta = this._cachedMeta;
10701 const labels = this.chart.data.labels || [];
10702 const { xScale , yScale } = meta;
10703 const parsed = this.getParsed(index);
10704 const x = xScale.getLabelForValue(parsed.x);
10705 const y = yScale.getLabelForValue(parsed.y);
10706 const r = parsed._custom;
10707 return {
10708 label: labels[index] || '',
10709 value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
10710 };
10711 }
10712 update(mode) {
10713 const points = this._cachedMeta.data;
10714 this.updateElements(points, 0, points.length, mode);
10715 }
10716 updateElements(points, start, count, mode) {
10717 const reset = mode === 'reset';
10718 const { iScale , vScale } = this._cachedMeta;
10719 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10720 const iAxis = iScale.axis;
10721 const vAxis = vScale.axis;
10722 for(let i = start; i < start + count; i++){
10723 const point = points[i];
10724 const parsed = !reset && this.getParsed(i);
10725 const properties = {};
10726 const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);
10727 const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);
10728 properties.skip = isNaN(iPixel) || isNaN(vPixel);
10729 if (includeOptions) {
10730 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
10731 if (reset) {
10732 properties.options.radius = 0;
10733 }
10734 }
10735 this.updateElement(point, i, properties, mode);
10736 }
10737 }
10738 resolveDataElementOptions(index, mode) {
10739 const parsed = this.getParsed(index);
10740 let values = super.resolveDataElementOptions(index, mode);
10741 if (values.$shared) {
10742 values = Object.assign({}, values, {
10743 $shared: false
10744 });
10745 }
10746 const radius = values.radius;
10747 if (mode !== 'active') {
10748 values.radius = 0;
10749 }
10750 values.radius += (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(parsed && parsed._custom, radius);
10751 return values;
10752 }
10753 }
10754
10755 function getRatioAndOffset(rotation, circumference, cutout) {
10756 let ratioX = 1;
10757 let ratioY = 1;
10758 let offsetX = 0;
10759 let offsetY = 0;
10760 if (circumference < _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) {
10761 const startAngle = rotation;
10762 const endAngle = startAngle + circumference;
10763 const startX = Math.cos(startAngle);
10764 const startY = Math.sin(startAngle);
10765 const endX = Math.cos(endAngle);
10766 const endY = Math.sin(endAngle);
10767 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);
10768 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);
10769 const maxX = calcMax(0, startX, endX);
10770 const maxY = calcMax(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10771 const minX = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, startX, endX);
10772 const minY = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10773 ratioX = (maxX - minX) / 2;
10774 ratioY = (maxY - minY) / 2;
10775 offsetX = -(maxX + minX) / 2;
10776 offsetY = -(maxY + minY) / 2;
10777 }
10778 return {
10779 ratioX,
10780 ratioY,
10781 offsetX,
10782 offsetY
10783 };
10784 }
10785 class DoughnutController extends DatasetController {
10786 static id = 'doughnut';
10787 static defaults = {
10788 datasetElementType: false,
10789 dataElementType: 'arc',
10790 animation: {
10791 animateRotate: true,
10792 animateScale: false
10793 },
10794 animations: {
10795 numbers: {
10796 type: 'number',
10797 properties: [
10798 'circumference',
10799 'endAngle',
10800 'innerRadius',
10801 'outerRadius',
10802 'startAngle',
10803 'x',
10804 'y',
10805 'offset',
10806 'borderWidth',
10807 'spacing'
10808 ]
10809 }
10810 },
10811 cutout: '50%',
10812 rotation: 0,
10813 circumference: 360,
10814 radius: '100%',
10815 spacing: 0,
10816 indexAxis: 'r'
10817 };
10818 static descriptors = {
10819 _scriptable: (name)=>name !== 'spacing',
10820 _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash')
10821 };
10822 static overrides = {
10823 aspectRatio: 1,
10824 plugins: {
10825 legend: {
10826 labels: {
10827 generateLabels (chart) {
10828 const data = chart.data;
10829 const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
10830 if (data.labels.length && data.datasets.length) {
10831 return data.labels.map((label, i)=>{
10832 const meta = chart.getDatasetMeta(0);
10833 const style = meta.controller.getStyle(i);
10834 return {
10835 text: label,
10836 fillStyle: style.backgroundColor,
10837 fontColor: color,
10838 hidden: !chart.getDataVisibility(i),
10839 lineDash: style.borderDash,
10840 lineDashOffset: style.borderDashOffset,
10841 lineJoin: style.borderJoinStyle,
10842 lineWidth: style.borderWidth,
10843 strokeStyle: style.borderColor,
10844 textAlign: textAlign,
10845 pointStyle: pointStyle,
10846 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
10847 index: i
10848 };
10849 });
10850 }
10851 return [];
10852 }
10853 },
10854 onClick (e, legendItem, legend) {
10855 legend.chart.toggleDataVisibility(legendItem.index);
10856 legend.chart.update();
10857 }
10858 }
10859 }
10860 };
10861 constructor(chart, datasetIndex){
10862 super(chart, datasetIndex);
10863 this.enableOptionSharing = true;
10864 this.innerRadius = undefined;
10865 this.outerRadius = undefined;
10866 this.offsetX = undefined;
10867 this.offsetY = undefined;
10868 }
10869 linkScales() {}
10870 parse(start, count) {
10871 const data = this.getDataset().data;
10872 const meta = this._cachedMeta;
10873 if (this._parsing === false) {
10874 meta._parsed = data;
10875 } else {
10876 let getter = (i)=>+data[i];
10877 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
10878 const { key ='value' } = this._parsing;
10879 getter = (i)=>+(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(data[i], key);
10880 }
10881 let i, ilen;
10882 for(i = start, ilen = start + count; i < ilen; ++i){
10883 meta._parsed[i] = getter(i);
10884 }
10885 }
10886 }
10887 _getRotation() {
10888 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.rotation - 90);
10889 }
10890 _getCircumference() {
10891 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.circumference);
10892 }
10893 _getRotationExtents() {
10894 let min = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
10895 let max = -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
10896 for(let i = 0; i < this.chart.data.datasets.length; ++i){
10897 if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) {
10898 const controller = this.chart.getDatasetMeta(i).controller;
10899 const rotation = controller._getRotation();
10900 const circumference = controller._getCircumference();
10901 min = Math.min(min, rotation);
10902 max = Math.max(max, rotation + circumference);
10903 }
10904 }
10905 return {
10906 rotation: min,
10907 circumference: max - min
10908 };
10909 }
10910 update(mode) {
10911 const chart = this.chart;
10912 const { chartArea } = chart;
10913 const meta = this._cachedMeta;
10914 const arcs = meta.data;
10915 const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
10916 const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
10917 const cutout = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.m)(this.options.cutout, maxSize), 1);
10918 const chartWeight = this._getRingWeight(this.index);
10919 const { circumference , rotation } = this._getRotationExtents();
10920 const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout);
10921 const maxWidth = (chartArea.width - spacing) / ratioX;
10922 const maxHeight = (chartArea.height - spacing) / ratioY;
10923 const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
10924 const outerRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.n)(this.options.radius, maxRadius);
10925 const innerRadius = Math.max(outerRadius * cutout, 0);
10926 const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
10927 this.offsetX = offsetX * outerRadius;
10928 this.offsetY = offsetY * outerRadius;
10929 meta.total = this.calculateTotal();
10930 this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
10931 this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
10932 this.updateElements(arcs, 0, arcs.length, mode);
10933 }
10934 _circumference(i, reset) {
10935 const opts = this.options;
10936 const meta = this._cachedMeta;
10937 const circumference = this._getCircumference();
10938 if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
10939 return 0;
10940 }
10941 return this.calculateCircumference(meta._parsed[i] * circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
10942 }
10943 updateElements(arcs, start, count, mode) {
10944 const reset = mode === 'reset';
10945 const chart = this.chart;
10946 const chartArea = chart.chartArea;
10947 const opts = chart.options;
10948 const animationOpts = opts.animation;
10949 const centerX = (chartArea.left + chartArea.right) / 2;
10950 const centerY = (chartArea.top + chartArea.bottom) / 2;
10951 const animateScale = reset && animationOpts.animateScale;
10952 const innerRadius = animateScale ? 0 : this.innerRadius;
10953 const outerRadius = animateScale ? 0 : this.outerRadius;
10954 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10955 let startAngle = this._getRotation();
10956 let i;
10957 for(i = 0; i < start; ++i){
10958 startAngle += this._circumference(i, reset);
10959 }
10960 for(i = start; i < start + count; ++i){
10961 const circumference = this._circumference(i, reset);
10962 const arc = arcs[i];
10963 const properties = {
10964 x: centerX + this.offsetX,
10965 y: centerY + this.offsetY,
10966 startAngle,
10967 endAngle: startAngle + circumference,
10968 circumference,
10969 outerRadius,
10970 innerRadius
10971 };
10972 if (includeOptions) {
10973 properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);
10974 }
10975 startAngle += circumference;
10976 this.updateElement(arc, i, properties, mode);
10977 }
10978 }
10979 calculateTotal() {
10980 const meta = this._cachedMeta;
10981 const metaData = meta.data;
10982 let total = 0;
10983 let i;
10984 for(i = 0; i < metaData.length; i++){
10985 const value = meta._parsed[i];
10986 if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
10987 total += Math.abs(value);
10988 }
10989 }
10990 return total;
10991 }
10992 calculateCircumference(value) {
10993 const total = this._cachedMeta.total;
10994 if (total > 0 && !isNaN(value)) {
10995 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T * (Math.abs(value) / total);
10996 }
10997 return 0;
10998 }
10999 getLabelAndValue(index) {
11000 const meta = this._cachedMeta;
11001 const chart = this.chart;
11002 const labels = chart.data.labels || [];
11003 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index], chart.options.locale);
11004 return {
11005 label: labels[index] || '',
11006 value
11007 };
11008 }
11009 getMaxBorderWidth(arcs) {
11010 let max = 0;
11011 const chart = this.chart;
11012 let i, ilen, meta, controller, options;
11013 if (!arcs) {
11014 for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){
11015 if (chart.isDatasetVisible(i)) {
11016 meta = chart.getDatasetMeta(i);
11017 arcs = meta.data;
11018 controller = meta.controller;
11019 break;
11020 }
11021 }
11022 }
11023 if (!arcs) {
11024 return 0;
11025 }
11026 for(i = 0, ilen = arcs.length; i < ilen; ++i){
11027 options = controller.resolveDataElementOptions(i);
11028 if (options.borderAlign !== 'inner') {
11029 max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
11030 }
11031 }
11032 return max;
11033 }
11034 getMaxOffset(arcs) {
11035 let max = 0;
11036 for(let i = 0, ilen = arcs.length; i < ilen; ++i){
11037 const options = this.resolveDataElementOptions(i);
11038 max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
11039 }
11040 return max;
11041 }
11042 _getRingWeightOffset(datasetIndex) {
11043 let ringWeightOffset = 0;
11044 for(let i = 0; i < datasetIndex; ++i){
11045 if (this.chart.isDatasetVisible(i)) {
11046 ringWeightOffset += this._getRingWeight(i);
11047 }
11048 }
11049 return ringWeightOffset;
11050 }
11051 _getRingWeight(datasetIndex) {
11052 return Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.data.datasets[datasetIndex].weight, 1), 0);
11053 }
11054 _getVisibleDatasetWeightTotal() {
11055 return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
11056 }
11057 }
11058
11059 class LineController extends DatasetController {
11060 static id = 'line';
11061 static defaults = {
11062 datasetElementType: 'line',
11063 dataElementType: 'point',
11064 showLine: true,
11065 spanGaps: false
11066 };
11067 static overrides = {
11068 scales: {
11069 _index_: {
11070 type: 'category'
11071 },
11072 _value_: {
11073 type: 'linear'
11074 }
11075 }
11076 };
11077 initialize() {
11078 this.enableOptionSharing = true;
11079 this.supportsDecimation = true;
11080 super.initialize();
11081 }
11082 update(mode) {
11083 const meta = this._cachedMeta;
11084 const { dataset: line , data: points = [] , _dataset } = meta;
11085 const animationsDisabled = this.chart._animationsDisabled;
11086 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11087 this._drawStart = start;
11088 this._drawCount = count;
11089 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11090 start = 0;
11091 count = points.length;
11092 }
11093 line._chart = this.chart;
11094 line._datasetIndex = this.index;
11095 line._decimated = !!_dataset._decimated;
11096 line.points = points;
11097 const options = this.resolveDatasetElementOptions(mode);
11098 if (!this.options.showLine) {
11099 options.borderWidth = 0;
11100 }
11101 options.segment = this.options.segment;
11102 this.updateElement(line, undefined, {
11103 animated: !animationsDisabled,
11104 options
11105 }, mode);
11106 this.updateElements(points, start, count, mode);
11107 }
11108 updateElements(points, start, count, mode) {
11109 const reset = mode === 'reset';
11110 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11111 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11112 const iAxis = iScale.axis;
11113 const vAxis = vScale.axis;
11114 const { spanGaps , segment } = this.options;
11115 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11116 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11117 const end = start + count;
11118 const pointsCount = points.length;
11119 let prevParsed = start > 0 && this.getParsed(start - 1);
11120 for(let i = 0; i < pointsCount; ++i){
11121 const point = points[i];
11122 const properties = directUpdate ? point : {};
11123 if (i < start || i >= end) {
11124 properties.skip = true;
11125 continue;
11126 }
11127 const parsed = this.getParsed(i);
11128 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11129 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11130 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11131 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11132 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11133 if (segment) {
11134 properties.parsed = parsed;
11135 properties.raw = _dataset.data[i];
11136 }
11137 if (includeOptions) {
11138 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11139 }
11140 if (!directUpdate) {
11141 this.updateElement(point, i, properties, mode);
11142 }
11143 prevParsed = parsed;
11144 }
11145 }
11146 getMaxOverflow() {
11147 const meta = this._cachedMeta;
11148 const dataset = meta.dataset;
11149 const border = dataset.options && dataset.options.borderWidth || 0;
11150 const data = meta.data || [];
11151 if (!data.length) {
11152 return border;
11153 }
11154 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11155 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11156 return Math.max(border, firstPoint, lastPoint) / 2;
11157 }
11158 draw() {
11159 const meta = this._cachedMeta;
11160 meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);
11161 super.draw();
11162 }
11163 }
11164
11165 class PolarAreaController extends DatasetController {
11166 static id = 'polarArea';
11167 static defaults = {
11168 dataElementType: 'arc',
11169 animation: {
11170 animateRotate: true,
11171 animateScale: true
11172 },
11173 animations: {
11174 numbers: {
11175 type: 'number',
11176 properties: [
11177 'x',
11178 'y',
11179 'startAngle',
11180 'endAngle',
11181 'innerRadius',
11182 'outerRadius'
11183 ]
11184 }
11185 },
11186 indexAxis: 'r',
11187 startAngle: 0
11188 };
11189 static overrides = {
11190 aspectRatio: 1,
11191 plugins: {
11192 legend: {
11193 labels: {
11194 generateLabels (chart) {
11195 const data = chart.data;
11196 if (data.labels.length && data.datasets.length) {
11197 const { labels: { pointStyle , color } } = chart.legend.options;
11198 return data.labels.map((label, i)=>{
11199 const meta = chart.getDatasetMeta(0);
11200 const style = meta.controller.getStyle(i);
11201 return {
11202 text: label,
11203 fillStyle: style.backgroundColor,
11204 strokeStyle: style.borderColor,
11205 fontColor: color,
11206 lineWidth: style.borderWidth,
11207 pointStyle: pointStyle,
11208 hidden: !chart.getDataVisibility(i),
11209 index: i
11210 };
11211 });
11212 }
11213 return [];
11214 }
11215 },
11216 onClick (e, legendItem, legend) {
11217 legend.chart.toggleDataVisibility(legendItem.index);
11218 legend.chart.update();
11219 }
11220 }
11221 },
11222 scales: {
11223 r: {
11224 type: 'radialLinear',
11225 angleLines: {
11226 display: false
11227 },
11228 beginAtZero: true,
11229 grid: {
11230 circular: true
11231 },
11232 pointLabels: {
11233 display: false
11234 },
11235 startAngle: 0
11236 }
11237 }
11238 };
11239 constructor(chart, datasetIndex){
11240 super(chart, datasetIndex);
11241 this.innerRadius = undefined;
11242 this.outerRadius = undefined;
11243 }
11244 getLabelAndValue(index) {
11245 const meta = this._cachedMeta;
11246 const chart = this.chart;
11247 const labels = chart.data.labels || [];
11248 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index].r, chart.options.locale);
11249 return {
11250 label: labels[index] || '',
11251 value
11252 };
11253 }
11254 parseObjectData(meta, data, start, count) {
11255 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11256 }
11257 update(mode) {
11258 const arcs = this._cachedMeta.data;
11259 this._updateRadius();
11260 this.updateElements(arcs, 0, arcs.length, mode);
11261 }
11262 getMinMax() {
11263 const meta = this._cachedMeta;
11264 const range = {
11265 min: Number.POSITIVE_INFINITY,
11266 max: Number.NEGATIVE_INFINITY
11267 };
11268 meta.data.forEach((element, index)=>{
11269 const parsed = this.getParsed(index).r;
11270 if (!isNaN(parsed) && this.chart.getDataVisibility(index)) {
11271 if (parsed < range.min) {
11272 range.min = parsed;
11273 }
11274 if (parsed > range.max) {
11275 range.max = parsed;
11276 }
11277 }
11278 });
11279 return range;
11280 }
11281 _updateRadius() {
11282 const chart = this.chart;
11283 const chartArea = chart.chartArea;
11284 const opts = chart.options;
11285 const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
11286 const outerRadius = Math.max(minSize / 2, 0);
11287 const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0);
11288 const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
11289 this.outerRadius = outerRadius - radiusLength * this.index;
11290 this.innerRadius = this.outerRadius - radiusLength;
11291 }
11292 updateElements(arcs, start, count, mode) {
11293 const reset = mode === 'reset';
11294 const chart = this.chart;
11295 const opts = chart.options;
11296 const animationOpts = opts.animation;
11297 const scale = this._cachedMeta.rScale;
11298 const centerX = scale.xCenter;
11299 const centerY = scale.yCenter;
11300 const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P;
11301 let angle = datasetStartAngle;
11302 let i;
11303 const defaultAngle = 360 / this.countVisibleElements();
11304 for(i = 0; i < start; ++i){
11305 angle += this._computeAngle(i, mode, defaultAngle);
11306 }
11307 for(i = start; i < start + count; i++){
11308 const arc = arcs[i];
11309 let startAngle = angle;
11310 let endAngle = angle + this._computeAngle(i, mode, defaultAngle);
11311 let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0;
11312 angle = endAngle;
11313 if (reset) {
11314 if (animationOpts.animateScale) {
11315 outerRadius = 0;
11316 }
11317 if (animationOpts.animateRotate) {
11318 startAngle = endAngle = datasetStartAngle;
11319 }
11320 }
11321 const properties = {
11322 x: centerX,
11323 y: centerY,
11324 innerRadius: 0,
11325 outerRadius,
11326 startAngle,
11327 endAngle,
11328 options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)
11329 };
11330 this.updateElement(arc, i, properties, mode);
11331 }
11332 }
11333 countVisibleElements() {
11334 const meta = this._cachedMeta;
11335 let count = 0;
11336 meta.data.forEach((element, index)=>{
11337 if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) {
11338 count++;
11339 }
11340 });
11341 return count;
11342 }
11343 _computeAngle(index, mode, defaultAngle) {
11344 return this.chart.getDataVisibility(index) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0;
11345 }
11346 }
11347
11348 class PieController extends DoughnutController {
11349 static id = 'pie';
11350 static defaults = {
11351 cutout: 0,
11352 rotation: 0,
11353 circumference: 360,
11354 radius: '100%'
11355 };
11356 }
11357
11358 class RadarController extends DatasetController {
11359 static id = 'radar';
11360 static defaults = {
11361 datasetElementType: 'line',
11362 dataElementType: 'point',
11363 indexAxis: 'r',
11364 showLine: true,
11365 elements: {
11366 line: {
11367 fill: 'start'
11368 }
11369 }
11370 };
11371 static overrides = {
11372 aspectRatio: 1,
11373 scales: {
11374 r: {
11375 type: 'radialLinear'
11376 }
11377 }
11378 };
11379 getLabelAndValue(index) {
11380 const vScale = this._cachedMeta.vScale;
11381 const parsed = this.getParsed(index);
11382 return {
11383 label: vScale.getLabels()[index],
11384 value: '' + vScale.getLabelForValue(parsed[vScale.axis])
11385 };
11386 }
11387 parseObjectData(meta, data, start, count) {
11388 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11389 }
11390 update(mode) {
11391 const meta = this._cachedMeta;
11392 const line = meta.dataset;
11393 const points = meta.data || [];
11394 const labels = meta.iScale.getLabels();
11395 line.points = points;
11396 if (mode !== 'resize') {
11397 const options = this.resolveDatasetElementOptions(mode);
11398 if (!this.options.showLine) {
11399 options.borderWidth = 0;
11400 }
11401 const properties = {
11402 _loop: true,
11403 _fullLoop: labels.length === points.length,
11404 options
11405 };
11406 this.updateElement(line, undefined, properties, mode);
11407 }
11408 this.updateElements(points, 0, points.length, mode);
11409 }
11410 updateElements(points, start, count, mode) {
11411 const scale = this._cachedMeta.rScale;
11412 const reset = mode === 'reset';
11413 for(let i = start; i < start + count; i++){
11414 const point = points[i];
11415 const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11416 const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r);
11417 const x = reset ? scale.xCenter : pointPosition.x;
11418 const y = reset ? scale.yCenter : pointPosition.y;
11419 const properties = {
11420 x,
11421 y,
11422 angle: pointPosition.angle,
11423 skip: isNaN(x) || isNaN(y),
11424 options
11425 };
11426 this.updateElement(point, i, properties, mode);
11427 }
11428 }
11429 }
11430
11431 class ScatterController extends DatasetController {
11432 static id = 'scatter';
11433 static defaults = {
11434 datasetElementType: false,
11435 dataElementType: 'point',
11436 showLine: false,
11437 fill: false
11438 };
11439 static overrides = {
11440 interaction: {
11441 mode: 'point'
11442 },
11443 scales: {
11444 x: {
11445 type: 'linear'
11446 },
11447 y: {
11448 type: 'linear'
11449 }
11450 }
11451 };
11452 getLabelAndValue(index) {
11453 const meta = this._cachedMeta;
11454 const labels = this.chart.data.labels || [];
11455 const { xScale , yScale } = meta;
11456 const parsed = this.getParsed(index);
11457 const x = xScale.getLabelForValue(parsed.x);
11458 const y = yScale.getLabelForValue(parsed.y);
11459 return {
11460 label: labels[index] || '',
11461 value: '(' + x + ', ' + y + ')'
11462 };
11463 }
11464 update(mode) {
11465 const meta = this._cachedMeta;
11466 const { data: points = [] } = meta;
11467 const animationsDisabled = this.chart._animationsDisabled;
11468 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11469 this._drawStart = start;
11470 this._drawCount = count;
11471 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11472 start = 0;
11473 count = points.length;
11474 }
11475 if (this.options.showLine) {
11476 if (!this.datasetElementType) {
11477 this.addElements();
11478 }
11479 const { dataset: line , _dataset } = meta;
11480 line._chart = this.chart;
11481 line._datasetIndex = this.index;
11482 line._decimated = !!_dataset._decimated;
11483 line.points = points;
11484 const options = this.resolveDatasetElementOptions(mode);
11485 options.segment = this.options.segment;
11486 this.updateElement(line, undefined, {
11487 animated: !animationsDisabled,
11488 options
11489 }, mode);
11490 } else if (this.datasetElementType) {
11491 delete meta.dataset;
11492 this.datasetElementType = false;
11493 }
11494 this.updateElements(points, start, count, mode);
11495 }
11496 addElements() {
11497 const { showLine } = this.options;
11498 if (!this.datasetElementType && showLine) {
11499 this.datasetElementType = this.chart.registry.getElement('line');
11500 }
11501 super.addElements();
11502 }
11503 updateElements(points, start, count, mode) {
11504 const reset = mode === 'reset';
11505 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11506 const firstOpts = this.resolveDataElementOptions(start, mode);
11507 const sharedOptions = this.getSharedOptions(firstOpts);
11508 const includeOptions = this.includeOptions(mode, sharedOptions);
11509 const iAxis = iScale.axis;
11510 const vAxis = vScale.axis;
11511 const { spanGaps , segment } = this.options;
11512 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11513 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11514 let prevParsed = start > 0 && this.getParsed(start - 1);
11515 for(let i = start; i < start + count; ++i){
11516 const point = points[i];
11517 const parsed = this.getParsed(i);
11518 const properties = directUpdate ? point : {};
11519 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11520 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11521 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11522 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11523 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11524 if (segment) {
11525 properties.parsed = parsed;
11526 properties.raw = _dataset.data[i];
11527 }
11528 if (includeOptions) {
11529 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11530 }
11531 if (!directUpdate) {
11532 this.updateElement(point, i, properties, mode);
11533 }
11534 prevParsed = parsed;
11535 }
11536 this.updateSharedOptions(sharedOptions, mode, firstOpts);
11537 }
11538 getMaxOverflow() {
11539 const meta = this._cachedMeta;
11540 const data = meta.data || [];
11541 if (!this.options.showLine) {
11542 let max = 0;
11543 for(let i = data.length - 1; i >= 0; --i){
11544 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
11545 }
11546 return max > 0 && max;
11547 }
11548 const dataset = meta.dataset;
11549 const border = dataset.options && dataset.options.borderWidth || 0;
11550 if (!data.length) {
11551 return border;
11552 }
11553 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11554 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11555 return Math.max(border, firstPoint, lastPoint) / 2;
11556 }
11557 }
11558
11559 var controllers = /*#__PURE__*/Object.freeze({
11560 __proto__: null,
11561 BarController: BarController,
11562 BubbleController: BubbleController,
11563 DoughnutController: DoughnutController,
11564 LineController: LineController,
11565 PieController: PieController,
11566 PolarAreaController: PolarAreaController,
11567 RadarController: RadarController,
11568 ScatterController: ScatterController
11569 });
11570
11571 /**
11572 * @namespace Chart._adapters
11573 * @since 2.8.0
11574 * @private
11575 */ function abstract() {
11576 throw new Error('This method is not implemented: Check that a complete date adapter is provided.');
11577 }
11578 /**
11579 * Date adapter (current used by the time scale)
11580 * @namespace Chart._adapters._date
11581 * @memberof Chart._adapters
11582 * @private
11583 */ class DateAdapterBase {
11584 /**
11585 * Override default date adapter methods.
11586 * Accepts type parameter to define options type.
11587 * @example
11588 * Chart._adapters._date.override<{myAdapterOption: string}>({
11589 * init() {
11590 * console.log(this.options.myAdapterOption);
11591 * }
11592 * })
11593 */ static override(members) {
11594 Object.assign(DateAdapterBase.prototype, members);
11595 }
11596 options;
11597 constructor(options){
11598 this.options = options || {};
11599 }
11600 // eslint-disable-next-line @typescript-eslint/no-empty-function
11601 init() {}
11602 formats() {
11603 return abstract();
11604 }
11605 parse() {
11606 return abstract();
11607 }
11608 format() {
11609 return abstract();
11610 }
11611 add() {
11612 return abstract();
11613 }
11614 diff() {
11615 return abstract();
11616 }
11617 startOf() {
11618 return abstract();
11619 }
11620 endOf() {
11621 return abstract();
11622 }
11623 }
11624 var adapters = {
11625 _date: DateAdapterBase
11626 };
11627
11628 function binarySearch(metaset, axis, value, intersect) {
11629 const { controller , data , _sorted } = metaset;
11630 const iScale = controller._cachedMeta.iScale;
11631 const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null;
11632 if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
11633 const lookupMethod = iScale._reversePixels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.A : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B;
11634 if (!intersect) {
11635 const result = lookupMethod(data, axis, value);
11636 if (spanGaps) {
11637 const { vScale } = controller._cachedMeta;
11638 const { _parsed } = metaset;
11639 const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11640 result.lo -= Math.max(0, distanceToDefinedLo);
11641 const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11642 result.hi += Math.max(0, distanceToDefinedHi);
11643 }
11644 return result;
11645 } else if (controller._sharedOptions) {
11646 const el = data[0];
11647 const range = typeof el.getRange === 'function' && el.getRange(axis);
11648 if (range) {
11649 const start = lookupMethod(data, axis, value - range);
11650 const end = lookupMethod(data, axis, value + range);
11651 return {
11652 lo: start.lo,
11653 hi: end.hi
11654 };
11655 }
11656 }
11657 }
11658 return {
11659 lo: 0,
11660 hi: data.length - 1
11661 };
11662 }
11663 function evaluateInteractionItems(chart, axis, position, handler, intersect) {
11664 const metasets = chart.getSortedVisibleDatasetMetas();
11665 const value = position[axis];
11666 for(let i = 0, ilen = metasets.length; i < ilen; ++i){
11667 const { index , data } = metasets[i];
11668 const { lo , hi } = binarySearch(metasets[i], axis, value, intersect);
11669 for(let j = lo; j <= hi; ++j){
11670 const element = data[j];
11671 if (!element.skip) {
11672 handler(element, index, j);
11673 }
11674 }
11675 }
11676 }
11677 function getDistanceMetricForAxis(axis) {
11678 const useX = axis.indexOf('x') !== -1;
11679 const useY = axis.indexOf('y') !== -1;
11680 return function(pt1, pt2) {
11681 const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
11682 const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
11683 return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
11684 };
11685 }
11686 function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {
11687 const items = [];
11688 if (!includeInvisible && !chart.isPointInArea(position)) {
11689 return items;
11690 }
11691 const evaluationFunc = function(element, datasetIndex, index) {
11692 if (!includeInvisible && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(element, chart.chartArea, 0)) {
11693 return;
11694 }
11695 if (element.inRange(position.x, position.y, useFinalPosition)) {
11696 items.push({
11697 element,
11698 datasetIndex,
11699 index
11700 });
11701 }
11702 };
11703 evaluateInteractionItems(chart, axis, position, evaluationFunc, true);
11704 return items;
11705 }
11706 function getNearestRadialItems(chart, position, axis, useFinalPosition) {
11707 let items = [];
11708 function evaluationFunc(element, datasetIndex, index) {
11709 const { startAngle , endAngle } = element.getProps([
11710 'startAngle',
11711 'endAngle'
11712 ], useFinalPosition);
11713 const { angle } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(element, {
11714 x: position.x,
11715 y: position.y
11716 });
11717 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle)) {
11718 items.push({
11719 element,
11720 datasetIndex,
11721 index
11722 });
11723 }
11724 }
11725 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11726 return items;
11727 }
11728 function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11729 let items = [];
11730 const distanceMetric = getDistanceMetricForAxis(axis);
11731 let minDistance = Number.POSITIVE_INFINITY;
11732 function evaluationFunc(element, datasetIndex, index) {
11733 const inRange = element.inRange(position.x, position.y, useFinalPosition);
11734 if (intersect && !inRange) {
11735 return;
11736 }
11737 const center = element.getCenterPoint(useFinalPosition);
11738 const pointInArea = !!includeInvisible || chart.isPointInArea(center);
11739 if (!pointInArea && !inRange) {
11740 return;
11741 }
11742 const distance = distanceMetric(position, center);
11743 if (distance < minDistance) {
11744 items = [
11745 {
11746 element,
11747 datasetIndex,
11748 index
11749 }
11750 ];
11751 minDistance = distance;
11752 } else if (distance === minDistance) {
11753 items.push({
11754 element,
11755 datasetIndex,
11756 index
11757 });
11758 }
11759 }
11760 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11761 return items;
11762 }
11763 function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11764 if (!includeInvisible && !chart.isPointInArea(position)) {
11765 return [];
11766 }
11767 return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);
11768 }
11769 function getAxisItems(chart, position, axis, intersect, useFinalPosition) {
11770 const items = [];
11771 const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
11772 let intersectsItem = false;
11773 evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{
11774 if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {
11775 items.push({
11776 element,
11777 datasetIndex,
11778 index
11779 });
11780 intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);
11781 }
11782 });
11783 if (intersect && !intersectsItem) {
11784 return [];
11785 }
11786 return items;
11787 }
11788 var Interaction = {
11789 evaluateInteractionItems,
11790 modes: {
11791 index (chart, e, options, useFinalPosition) {
11792 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11793 const axis = options.axis || 'x';
11794 const includeInvisible = options.includeInvisible || false;
11795 const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11796 const elements = [];
11797 if (!items.length) {
11798 return [];
11799 }
11800 chart.getSortedVisibleDatasetMetas().forEach((meta)=>{
11801 const index = items[0].index;
11802 const element = meta.data[index];
11803 if (element && !element.skip) {
11804 elements.push({
11805 element,
11806 datasetIndex: meta.index,
11807 index
11808 });
11809 }
11810 });
11811 return elements;
11812 },
11813 dataset (chart, e, options, useFinalPosition) {
11814 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11815 const axis = options.axis || 'xy';
11816 const includeInvisible = options.includeInvisible || false;
11817 let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11818 if (items.length > 0) {
11819 const datasetIndex = items[0].datasetIndex;
11820 const data = chart.getDatasetMeta(datasetIndex).data;
11821 items = [];
11822 for(let i = 0; i < data.length; ++i){
11823 items.push({
11824 element: data[i],
11825 datasetIndex,
11826 index: i
11827 });
11828 }
11829 }
11830 return items;
11831 },
11832 point (chart, e, options, useFinalPosition) {
11833 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11834 const axis = options.axis || 'xy';
11835 const includeInvisible = options.includeInvisible || false;
11836 return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);
11837 },
11838 nearest (chart, e, options, useFinalPosition) {
11839 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11840 const axis = options.axis || 'xy';
11841 const includeInvisible = options.includeInvisible || false;
11842 return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);
11843 },
11844 x (chart, e, options, useFinalPosition) {
11845 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11846 return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition);
11847 },
11848 y (chart, e, options, useFinalPosition) {
11849 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11850 return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition);
11851 }
11852 }
11853 };
11854
11855 const STATIC_POSITIONS = [
11856 'left',
11857 'top',
11858 'right',
11859 'bottom'
11860 ];
11861 function filterByPosition(array, position) {
11862 return array.filter((v)=>v.pos === position);
11863 }
11864 function filterDynamicPositionByAxis(array, axis) {
11865 return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
11866 }
11867 function sortByWeight(array, reverse) {
11868 return array.sort((a, b)=>{
11869 const v0 = reverse ? b : a;
11870 const v1 = reverse ? a : b;
11871 return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;
11872 });
11873 }
11874 function wrapBoxes(boxes) {
11875 const layoutBoxes = [];
11876 let i, ilen, box, pos, stack, stackWeight;
11877 for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){
11878 box = boxes[i];
11879 ({ position: pos , options: { stack , stackWeight =1 } } = box);
11880 layoutBoxes.push({
11881 index: i,
11882 box,
11883 pos,
11884 horizontal: box.isHorizontal(),
11885 weight: box.weight,
11886 stack: stack && pos + stack,
11887 stackWeight
11888 });
11889 }
11890 return layoutBoxes;
11891 }
11892 function buildStacks(layouts) {
11893 const stacks = {};
11894 for (const wrap of layouts){
11895 const { stack , pos , stackWeight } = wrap;
11896 if (!stack || !STATIC_POSITIONS.includes(pos)) {
11897 continue;
11898 }
11899 const _stack = stacks[stack] || (stacks[stack] = {
11900 count: 0,
11901 placed: 0,
11902 weight: 0,
11903 size: 0
11904 });
11905 _stack.count++;
11906 _stack.weight += stackWeight;
11907 }
11908 return stacks;
11909 }
11910 function setLayoutDims(layouts, params) {
11911 const stacks = buildStacks(layouts);
11912 const { vBoxMaxWidth , hBoxMaxHeight } = params;
11913 let i, ilen, layout;
11914 for(i = 0, ilen = layouts.length; i < ilen; ++i){
11915 layout = layouts[i];
11916 const { fullSize } = layout.box;
11917 const stack = stacks[layout.stack];
11918 const factor = stack && layout.stackWeight / stack.weight;
11919 if (layout.horizontal) {
11920 layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
11921 layout.height = hBoxMaxHeight;
11922 } else {
11923 layout.width = vBoxMaxWidth;
11924 layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
11925 }
11926 }
11927 return stacks;
11928 }
11929 function buildLayoutBoxes(boxes) {
11930 const layoutBoxes = wrapBoxes(boxes);
11931 const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true);
11932 const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
11933 const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
11934 const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
11935 const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
11936 const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
11937 const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
11938 return {
11939 fullSize,
11940 leftAndTop: left.concat(top),
11941 rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
11942 chartArea: filterByPosition(layoutBoxes, 'chartArea'),
11943 vertical: left.concat(right).concat(centerVertical),
11944 horizontal: top.concat(bottom).concat(centerHorizontal)
11945 };
11946 }
11947 function getCombinedMax(maxPadding, chartArea, a, b) {
11948 return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
11949 }
11950 function updateMaxPadding(maxPadding, boxPadding) {
11951 maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
11952 maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
11953 maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
11954 maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
11955 }
11956 function updateDims(chartArea, params, layout, stacks) {
11957 const { pos , box } = layout;
11958 const maxPadding = chartArea.maxPadding;
11959 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(pos)) {
11960 if (layout.size) {
11961 chartArea[pos] -= layout.size;
11962 }
11963 const stack = stacks[layout.stack] || {
11964 size: 0,
11965 count: 1
11966 };
11967 stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
11968 layout.size = stack.size / stack.count;
11969 chartArea[pos] += layout.size;
11970 }
11971 if (box.getPadding) {
11972 updateMaxPadding(maxPadding, box.getPadding());
11973 }
11974 const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
11975 const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
11976 const widthChanged = newWidth !== chartArea.w;
11977 const heightChanged = newHeight !== chartArea.h;
11978 chartArea.w = newWidth;
11979 chartArea.h = newHeight;
11980 return layout.horizontal ? {
11981 same: widthChanged,
11982 other: heightChanged
11983 } : {
11984 same: heightChanged,
11985 other: widthChanged
11986 };
11987 }
11988 function handleMaxPadding(chartArea) {
11989 const maxPadding = chartArea.maxPadding;
11990 function updatePos(pos) {
11991 const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
11992 chartArea[pos] += change;
11993 return change;
11994 }
11995 chartArea.y += updatePos('top');
11996 chartArea.x += updatePos('left');
11997 updatePos('right');
11998 updatePos('bottom');
11999 }
12000 function getMargins(horizontal, chartArea) {
12001 const maxPadding = chartArea.maxPadding;
12002 function marginForPositions(positions) {
12003 const margin = {
12004 left: 0,
12005 top: 0,
12006 right: 0,
12007 bottom: 0
12008 };
12009 positions.forEach((pos)=>{
12010 margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
12011 });
12012 return margin;
12013 }
12014 return horizontal ? marginForPositions([
12015 'left',
12016 'right'
12017 ]) : marginForPositions([
12018 'top',
12019 'bottom'
12020 ]);
12021 }
12022 function fitBoxes(boxes, chartArea, params, stacks) {
12023 const refitBoxes = [];
12024 let i, ilen, layout, box, refit, changed;
12025 for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){
12026 layout = boxes[i];
12027 box = layout.box;
12028 box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));
12029 const { same , other } = updateDims(chartArea, params, layout, stacks);
12030 refit |= same && refitBoxes.length;
12031 changed = changed || other;
12032 if (!box.fullSize) {
12033 refitBoxes.push(layout);
12034 }
12035 }
12036 return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
12037 }
12038 function setBoxDims(box, left, top, width, height) {
12039 box.top = top;
12040 box.left = left;
12041 box.right = left + width;
12042 box.bottom = top + height;
12043 box.width = width;
12044 box.height = height;
12045 }
12046 function placeBoxes(boxes, chartArea, params, stacks) {
12047 const userPadding = params.padding;
12048 let { x , y } = chartArea;
12049 for (const layout of boxes){
12050 const box = layout.box;
12051 const stack = stacks[layout.stack] || {
12052 count: 1,
12053 placed: 0,
12054 weight: 1
12055 };
12056 const weight = layout.stackWeight / stack.weight || 1;
12057 if (layout.horizontal) {
12058 const width = chartArea.w * weight;
12059 const height = stack.size || box.height;
12060 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12061 y = stack.start;
12062 }
12063 if (box.fullSize) {
12064 setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);
12065 } else {
12066 setBoxDims(box, chartArea.left + stack.placed, y, width, height);
12067 }
12068 stack.start = y;
12069 stack.placed += width;
12070 y = box.bottom;
12071 } else {
12072 const height = chartArea.h * weight;
12073 const width = stack.size || box.width;
12074 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12075 x = stack.start;
12076 }
12077 if (box.fullSize) {
12078 setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
12079 } else {
12080 setBoxDims(box, x, chartArea.top + stack.placed, width, height);
12081 }
12082 stack.start = x;
12083 stack.placed += height;
12084 x = box.right;
12085 }
12086 }
12087 chartArea.x = x;
12088 chartArea.y = y;
12089 }
12090 var layouts = {
12091 addBox (chart, item) {
12092 if (!chart.boxes) {
12093 chart.boxes = [];
12094 }
12095 item.fullSize = item.fullSize || false;
12096 item.position = item.position || 'top';
12097 item.weight = item.weight || 0;
12098 item._layers = item._layers || function() {
12099 return [
12100 {
12101 z: 0,
12102 draw (chartArea) {
12103 item.draw(chartArea);
12104 }
12105 }
12106 ];
12107 };
12108 chart.boxes.push(item);
12109 },
12110 removeBox (chart, layoutItem) {
12111 const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
12112 if (index !== -1) {
12113 chart.boxes.splice(index, 1);
12114 }
12115 },
12116 configure (chart, item, options) {
12117 item.fullSize = options.fullSize;
12118 item.position = options.position;
12119 item.weight = options.weight;
12120 },
12121 update (chart, width, height, minPadding) {
12122 if (!chart) {
12123 return;
12124 }
12125 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(chart.options.layout.padding);
12126 const availableWidth = Math.max(width - padding.width, 0);
12127 const availableHeight = Math.max(height - padding.height, 0);
12128 const boxes = buildLayoutBoxes(chart.boxes);
12129 const verticalBoxes = boxes.vertical;
12130 const horizontalBoxes = boxes.horizontal;
12131 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(chart.boxes, (box)=>{
12132 if (typeof box.beforeLayout === 'function') {
12133 box.beforeLayout();
12134 }
12135 });
12136 const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
12137 const params = Object.freeze({
12138 outerWidth: width,
12139 outerHeight: height,
12140 padding,
12141 availableWidth,
12142 availableHeight,
12143 vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
12144 hBoxMaxHeight: availableHeight / 2
12145 });
12146 const maxPadding = Object.assign({}, padding);
12147 updateMaxPadding(maxPadding, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(minPadding));
12148 const chartArea = Object.assign({
12149 maxPadding,
12150 w: availableWidth,
12151 h: availableHeight,
12152 x: padding.left,
12153 y: padding.top
12154 }, padding);
12155 const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
12156 fitBoxes(boxes.fullSize, chartArea, params, stacks);
12157 fitBoxes(verticalBoxes, chartArea, params, stacks);
12158 if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
12159 fitBoxes(verticalBoxes, chartArea, params, stacks);
12160 }
12161 handleMaxPadding(chartArea);
12162 placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
12163 chartArea.x += chartArea.w;
12164 chartArea.y += chartArea.h;
12165 placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
12166 chart.chartArea = {
12167 left: chartArea.left,
12168 top: chartArea.top,
12169 right: chartArea.left + chartArea.w,
12170 bottom: chartArea.top + chartArea.h,
12171 height: chartArea.h,
12172 width: chartArea.w
12173 };
12174 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(boxes.chartArea, (layout)=>{
12175 const box = layout.box;
12176 Object.assign(box, chart.chartArea);
12177 box.update(chartArea.w, chartArea.h, {
12178 left: 0,
12179 top: 0,
12180 right: 0,
12181 bottom: 0
12182 });
12183 });
12184 }
12185 };
12186
12187 class BasePlatform {
12188 acquireContext(canvas, aspectRatio) {}
12189 releaseContext(context) {
12190 return false;
12191 }
12192 addEventListener(chart, type, listener) {}
12193 removeEventListener(chart, type, listener) {}
12194 getDevicePixelRatio() {
12195 return 1;
12196 }
12197 getMaximumSize(element, width, height, aspectRatio) {
12198 width = Math.max(0, width || element.width);
12199 height = height || element.height;
12200 return {
12201 width,
12202 height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
12203 };
12204 }
12205 isAttached(canvas) {
12206 return true;
12207 }
12208 updateConfig(config) {
12209 }
12210 }
12211
12212 class BasicPlatform extends BasePlatform {
12213 acquireContext(item) {
12214 return item && item.getContext && item.getContext('2d') || null;
12215 }
12216 updateConfig(config) {
12217 config.options.animation = false;
12218 }
12219 }
12220
12221 const EXPANDO_KEY = '$chartjs';
12222 const EVENT_TYPES = {
12223 touchstart: 'mousedown',
12224 touchmove: 'mousemove',
12225 touchend: 'mouseup',
12226 pointerenter: 'mouseenter',
12227 pointerdown: 'mousedown',
12228 pointermove: 'mousemove',
12229 pointerup: 'mouseup',
12230 pointerleave: 'mouseout',
12231 pointerout: 'mouseout'
12232 };
12233 const isNullOrEmpty = (value)=>value === null || value === '';
12234 function initCanvas(canvas, aspectRatio) {
12235 const style = canvas.style;
12236 const renderHeight = canvas.getAttribute('height');
12237 const renderWidth = canvas.getAttribute('width');
12238 canvas[EXPANDO_KEY] = {
12239 initial: {
12240 height: renderHeight,
12241 width: renderWidth,
12242 style: {
12243 display: style.display,
12244 height: style.height,
12245 width: style.width
12246 }
12247 }
12248 };
12249 style.display = style.display || 'block';
12250 style.boxSizing = style.boxSizing || 'border-box';
12251 if (isNullOrEmpty(renderWidth)) {
12252 const displayWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'width');
12253 if (displayWidth !== undefined) {
12254 canvas.width = displayWidth;
12255 }
12256 }
12257 if (isNullOrEmpty(renderHeight)) {
12258 if (canvas.style.height === '') {
12259 canvas.height = canvas.width / (aspectRatio || 2);
12260 } else {
12261 const displayHeight = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'height');
12262 if (displayHeight !== undefined) {
12263 canvas.height = displayHeight;
12264 }
12265 }
12266 }
12267 return canvas;
12268 }
12269 const eventListenerOptions = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.K ? {
12270 passive: true
12271 } : false;
12272 function addListener(node, type, listener) {
12273 if (node) {
12274 node.addEventListener(type, listener, eventListenerOptions);
12275 }
12276 }
12277 function removeListener(chart, type, listener) {
12278 if (chart && chart.canvas) {
12279 chart.canvas.removeEventListener(type, listener, eventListenerOptions);
12280 }
12281 }
12282 function fromNativeEvent(event, chart) {
12283 const type = EVENT_TYPES[event.type] || event.type;
12284 const { x , y } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(event, chart);
12285 return {
12286 type,
12287 chart,
12288 native: event,
12289 x: x !== undefined ? x : null,
12290 y: y !== undefined ? y : null
12291 };
12292 }
12293 function nodeListContains(nodeList, canvas) {
12294 for (const node of nodeList){
12295 if (node === canvas || node.contains(canvas)) {
12296 return true;
12297 }
12298 }
12299 }
12300 function createAttachObserver(chart, type, listener) {
12301 const canvas = chart.canvas;
12302 const observer = new MutationObserver((entries)=>{
12303 let trigger = false;
12304 for (const entry of entries){
12305 trigger = trigger || nodeListContains(entry.addedNodes, canvas);
12306 trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
12307 }
12308 if (trigger) {
12309 listener();
12310 }
12311 });
12312 observer.observe(document, {
12313 childList: true,
12314 subtree: true
12315 });
12316 return observer;
12317 }
12318 function createDetachObserver(chart, type, listener) {
12319 const canvas = chart.canvas;
12320 const observer = new MutationObserver((entries)=>{
12321 let trigger = false;
12322 for (const entry of entries){
12323 trigger = trigger || nodeListContains(entry.removedNodes, canvas);
12324 trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
12325 }
12326 if (trigger) {
12327 listener();
12328 }
12329 });
12330 observer.observe(document, {
12331 childList: true,
12332 subtree: true
12333 });
12334 return observer;
12335 }
12336 const drpListeningCharts = new Map();
12337 let oldDevicePixelRatio = 0;
12338 function onWindowResize() {
12339 const dpr = window.devicePixelRatio;
12340 if (dpr === oldDevicePixelRatio) {
12341 return;
12342 }
12343 oldDevicePixelRatio = dpr;
12344 drpListeningCharts.forEach((resize, chart)=>{
12345 if (chart.currentDevicePixelRatio !== dpr) {
12346 resize();
12347 }
12348 });
12349 }
12350 function listenDevicePixelRatioChanges(chart, resize) {
12351 if (!drpListeningCharts.size) {
12352 window.addEventListener('resize', onWindowResize);
12353 }
12354 drpListeningCharts.set(chart, resize);
12355 }
12356 function unlistenDevicePixelRatioChanges(chart) {
12357 drpListeningCharts.delete(chart);
12358 if (!drpListeningCharts.size) {
12359 window.removeEventListener('resize', onWindowResize);
12360 }
12361 }
12362 function createResizeObserver(chart, type, listener) {
12363 const canvas = chart.canvas;
12364 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12365 if (!container) {
12366 return;
12367 }
12368 const resize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((width, height)=>{
12369 const w = container.clientWidth;
12370 listener(width, height);
12371 if (w < container.clientWidth) {
12372 listener();
12373 }
12374 }, window);
12375 const observer = new ResizeObserver((entries)=>{
12376 const entry = entries[0];
12377 const width = entry.contentRect.width;
12378 const height = entry.contentRect.height;
12379 if (width === 0 && height === 0) {
12380 return;
12381 }
12382 resize(width, height);
12383 });
12384 observer.observe(container);
12385 listenDevicePixelRatioChanges(chart, resize);
12386 return observer;
12387 }
12388 function releaseObserver(chart, type, observer) {
12389 if (observer) {
12390 observer.disconnect();
12391 }
12392 if (type === 'resize') {
12393 unlistenDevicePixelRatioChanges(chart);
12394 }
12395 }
12396 function createProxyAndListen(chart, type, listener) {
12397 const canvas = chart.canvas;
12398 const proxy = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((event)=>{
12399 if (chart.ctx !== null) {
12400 listener(fromNativeEvent(event, chart));
12401 }
12402 }, chart);
12403 addListener(canvas, type, proxy);
12404 return proxy;
12405 }
12406 class DomPlatform extends BasePlatform {
12407 acquireContext(canvas, aspectRatio) {
12408 const context = canvas && canvas.getContext && canvas.getContext('2d');
12409 if (context && context.canvas === canvas) {
12410 initCanvas(canvas, aspectRatio);
12411 return context;
12412 }
12413 return null;
12414 }
12415 releaseContext(context) {
12416 const canvas = context.canvas;
12417 if (!canvas[EXPANDO_KEY]) {
12418 return false;
12419 }
12420 const initial = canvas[EXPANDO_KEY].initial;
12421 [
12422 'height',
12423 'width'
12424 ].forEach((prop)=>{
12425 const value = initial[prop];
12426 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
12427 canvas.removeAttribute(prop);
12428 } else {
12429 canvas.setAttribute(prop, value);
12430 }
12431 });
12432 const style = initial.style || {};
12433 Object.keys(style).forEach((key)=>{
12434 canvas.style[key] = style[key];
12435 });
12436 canvas.width = canvas.width;
12437 delete canvas[EXPANDO_KEY];
12438 return true;
12439 }
12440 addEventListener(chart, type, listener) {
12441 this.removeEventListener(chart, type);
12442 const proxies = chart.$proxies || (chart.$proxies = {});
12443 const handlers = {
12444 attach: createAttachObserver,
12445 detach: createDetachObserver,
12446 resize: createResizeObserver
12447 };
12448 const handler = handlers[type] || createProxyAndListen;
12449 proxies[type] = handler(chart, type, listener);
12450 }
12451 removeEventListener(chart, type) {
12452 const proxies = chart.$proxies || (chart.$proxies = {});
12453 const proxy = proxies[type];
12454 if (!proxy) {
12455 return;
12456 }
12457 const handlers = {
12458 attach: releaseObserver,
12459 detach: releaseObserver,
12460 resize: releaseObserver
12461 };
12462 const handler = handlers[type] || removeListener;
12463 handler(chart, type, proxy);
12464 proxies[type] = undefined;
12465 }
12466 getDevicePixelRatio() {
12467 return window.devicePixelRatio;
12468 }
12469 getMaximumSize(canvas, width, height, aspectRatio) {
12470 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.G)(canvas, width, height, aspectRatio);
12471 }
12472 isAttached(canvas) {
12473 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12474 return !!(container && container.isConnected);
12475 }
12476 }
12477
12478 function _detectPlatform(canvas) {
12479 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
12480 return BasicPlatform;
12481 }
12482 return DomPlatform;
12483 }
12484
12485 class Element {
12486 static defaults = {};
12487 static defaultRoutes = undefined;
12488 x;
12489 y;
12490 active = false;
12491 options;
12492 $animations;
12493 tooltipPosition(useFinalPosition) {
12494 const { x , y } = this.getProps([
12495 'x',
12496 'y'
12497 ], useFinalPosition);
12498 return {
12499 x,
12500 y
12501 };
12502 }
12503 hasValue() {
12504 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);
12505 }
12506 getProps(props, final) {
12507 const anims = this.$animations;
12508 if (!final || !anims) {
12509 // let's not create an object, if not needed
12510 return this;
12511 }
12512 const ret = {};
12513 props.forEach((prop)=>{
12514 ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
12515 });
12516 return ret;
12517 }
12518 }
12519
12520 function autoSkip(scale, ticks) {
12521 const tickOpts = scale.options.ticks;
12522 const determinedMaxTicks = determineMaxTicks(scale);
12523 const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);
12524 const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
12525 const numMajorIndices = majorIndices.length;
12526 const first = majorIndices[0];
12527 const last = majorIndices[numMajorIndices - 1];
12528 const newTicks = [];
12529 if (numMajorIndices > ticksLimit) {
12530 skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
12531 return newTicks;
12532 }
12533 const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
12534 if (numMajorIndices > 0) {
12535 let i, ilen;
12536 const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
12537 skip(ticks, newTicks, spacing, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
12538 for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){
12539 skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
12540 }
12541 skip(ticks, newTicks, spacing, last, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
12542 return newTicks;
12543 }
12544 skip(ticks, newTicks, spacing);
12545 return newTicks;
12546 }
12547 function determineMaxTicks(scale) {
12548 const offset = scale.options.offset;
12549 const tickLength = scale._tickSize();
12550 const maxScale = scale._length / tickLength + (offset ? 0 : 1);
12551 const maxChart = scale._maxLength / tickLength;
12552 return Math.floor(Math.min(maxScale, maxChart));
12553 }
12554 function calculateSpacing(majorIndices, ticks, ticksLimit) {
12555 const evenMajorSpacing = getEvenSpacing(majorIndices);
12556 const spacing = ticks.length / ticksLimit;
12557 if (!evenMajorSpacing) {
12558 return Math.max(spacing, 1);
12559 }
12560 const factors = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.N)(evenMajorSpacing);
12561 for(let i = 0, ilen = factors.length - 1; i < ilen; i++){
12562 const factor = factors[i];
12563 if (factor > spacing) {
12564 return factor;
12565 }
12566 }
12567 return Math.max(spacing, 1);
12568 }
12569 function getMajorIndices(ticks) {
12570 const result = [];
12571 let i, ilen;
12572 for(i = 0, ilen = ticks.length; i < ilen; i++){
12573 if (ticks[i].major) {
12574 result.push(i);
12575 }
12576 }
12577 return result;
12578 }
12579 function skipMajors(ticks, newTicks, majorIndices, spacing) {
12580 let count = 0;
12581 let next = majorIndices[0];
12582 let i;
12583 spacing = Math.ceil(spacing);
12584 for(i = 0; i < ticks.length; i++){
12585 if (i === next) {
12586 newTicks.push(ticks[i]);
12587 count++;
12588 next = majorIndices[count * spacing];
12589 }
12590 }
12591 }
12592 function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
12593 const start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorStart, 0);
12594 const end = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorEnd, ticks.length), ticks.length);
12595 let count = 0;
12596 let length, i, next;
12597 spacing = Math.ceil(spacing);
12598 if (majorEnd) {
12599 length = majorEnd - majorStart;
12600 spacing = length / Math.floor(length / spacing);
12601 }
12602 next = start;
12603 while(next < 0){
12604 count++;
12605 next = Math.round(start + count * spacing);
12606 }
12607 for(i = Math.max(start, 0); i < end; i++){
12608 if (i === next) {
12609 newTicks.push(ticks[i]);
12610 count++;
12611 next = Math.round(start + count * spacing);
12612 }
12613 }
12614 }
12615 function getEvenSpacing(arr) {
12616 const len = arr.length;
12617 let i, diff;
12618 if (len < 2) {
12619 return false;
12620 }
12621 for(diff = arr[0], i = 1; i < len; ++i){
12622 if (arr[i] - arr[i - 1] !== diff) {
12623 return false;
12624 }
12625 }
12626 return diff;
12627 }
12628
12629 const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align;
12630 const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
12631 const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength);
12632 function sample(arr, numItems) {
12633 const result = [];
12634 const increment = arr.length / numItems;
12635 const len = arr.length;
12636 let i = 0;
12637 for(; i < len; i += increment){
12638 result.push(arr[Math.floor(i)]);
12639 }
12640 return result;
12641 }
12642 function getPixelForGridLine(scale, index, offsetGridLines) {
12643 const length = scale.ticks.length;
12644 const validIndex = Math.min(index, length - 1);
12645 const start = scale._startPixel;
12646 const end = scale._endPixel;
12647 const epsilon = 1e-6;
12648 let lineValue = scale.getPixelForTick(validIndex);
12649 let offset;
12650 if (offsetGridLines) {
12651 if (length === 1) {
12652 offset = Math.max(lineValue - start, end - lineValue);
12653 } else if (index === 0) {
12654 offset = (scale.getPixelForTick(1) - lineValue) / 2;
12655 } else {
12656 offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
12657 }
12658 lineValue += validIndex < index ? offset : -offset;
12659 if (lineValue < start - epsilon || lineValue > end + epsilon) {
12660 return;
12661 }
12662 }
12663 return lineValue;
12664 }
12665 function garbageCollect(caches, length) {
12666 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(caches, (cache)=>{
12667 const gc = cache.gc;
12668 const gcLen = gc.length / 2;
12669 let i;
12670 if (gcLen > length) {
12671 for(i = 0; i < gcLen; ++i){
12672 delete cache.data[gc[i]];
12673 }
12674 gc.splice(0, gcLen);
12675 }
12676 });
12677 }
12678 function getTickMarkLength(options) {
12679 return options.drawTicks ? options.tickLength : 0;
12680 }
12681 function getTitleHeight(options, fallback) {
12682 if (!options.display) {
12683 return 0;
12684 }
12685 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.font, fallback);
12686 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
12687 const lines = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(options.text) ? options.text.length : 1;
12688 return lines * font.lineHeight + padding.height;
12689 }
12690 function createScaleContext(parent, scale) {
12691 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12692 scale,
12693 type: 'scale'
12694 });
12695 }
12696 function createTickContext(parent, index, tick) {
12697 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12698 tick,
12699 index,
12700 type: 'tick'
12701 });
12702 }
12703 function titleAlign(align, position, reverse) {
12704 let ret = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(align);
12705 if (reverse && position !== 'right' || !reverse && position === 'right') {
12706 ret = reverseAlign(ret);
12707 }
12708 return ret;
12709 }
12710 function titleArgs(scale, offset, position, align) {
12711 const { top , left , bottom , right , chart } = scale;
12712 const { chartArea , scales } = chart;
12713 let rotation = 0;
12714 let maxWidth, titleX, titleY;
12715 const height = bottom - top;
12716 const width = right - left;
12717 if (scale.isHorizontal()) {
12718 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
12719 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12720 const positionAxisID = Object.keys(position)[0];
12721 const value = position[positionAxisID];
12722 titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
12723 } else if (position === 'center') {
12724 titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
12725 } else {
12726 titleY = offsetFromEdge(scale, position, offset);
12727 }
12728 maxWidth = right - left;
12729 } else {
12730 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12731 const positionAxisID = Object.keys(position)[0];
12732 const value = position[positionAxisID];
12733 titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
12734 } else if (position === 'center') {
12735 titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
12736 } else {
12737 titleX = offsetFromEdge(scale, position, offset);
12738 }
12739 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
12740 rotation = position === 'left' ? -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H;
12741 }
12742 return {
12743 titleX,
12744 titleY,
12745 maxWidth,
12746 rotation
12747 };
12748 }
12749 class Scale extends Element {
12750 constructor(cfg){
12751 super();
12752 this.id = cfg.id;
12753 this.type = cfg.type;
12754 this.options = undefined;
12755 this.ctx = cfg.ctx;
12756 this.chart = cfg.chart;
12757 this.top = undefined;
12758 this.bottom = undefined;
12759 this.left = undefined;
12760 this.right = undefined;
12761 this.width = undefined;
12762 this.height = undefined;
12763 this._margins = {
12764 left: 0,
12765 right: 0,
12766 top: 0,
12767 bottom: 0
12768 };
12769 this.maxWidth = undefined;
12770 this.maxHeight = undefined;
12771 this.paddingTop = undefined;
12772 this.paddingBottom = undefined;
12773 this.paddingLeft = undefined;
12774 this.paddingRight = undefined;
12775 this.axis = undefined;
12776 this.labelRotation = undefined;
12777 this.min = undefined;
12778 this.max = undefined;
12779 this._range = undefined;
12780 this.ticks = [];
12781 this._gridLineItems = null;
12782 this._labelItems = null;
12783 this._labelSizes = null;
12784 this._length = 0;
12785 this._maxLength = 0;
12786 this._longestTextCache = {};
12787 this._startPixel = undefined;
12788 this._endPixel = undefined;
12789 this._reversePixels = false;
12790 this._userMax = undefined;
12791 this._userMin = undefined;
12792 this._suggestedMax = undefined;
12793 this._suggestedMin = undefined;
12794 this._ticksLength = 0;
12795 this._borderValue = 0;
12796 this._cache = {};
12797 this._dataLimitsCached = false;
12798 this.$context = undefined;
12799 }
12800 init(options) {
12801 this.options = options.setContext(this.getContext());
12802 this.axis = options.axis;
12803 this._userMin = this.parse(options.min);
12804 this._userMax = this.parse(options.max);
12805 this._suggestedMin = this.parse(options.suggestedMin);
12806 this._suggestedMax = this.parse(options.suggestedMax);
12807 }
12808 parse(raw, index) {
12809 return raw;
12810 }
12811 getUserBounds() {
12812 let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this;
12813 _userMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, Number.POSITIVE_INFINITY);
12814 _userMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, Number.NEGATIVE_INFINITY);
12815 _suggestedMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMin, Number.POSITIVE_INFINITY);
12816 _suggestedMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMax, Number.NEGATIVE_INFINITY);
12817 return {
12818 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, _suggestedMin),
12819 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, _suggestedMax),
12820 minDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMin),
12821 maxDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMax)
12822 };
12823 }
12824 getMinMax(canStack) {
12825 let { min , max , minDefined , maxDefined } = this.getUserBounds();
12826 let range;
12827 if (minDefined && maxDefined) {
12828 return {
12829 min,
12830 max
12831 };
12832 }
12833 const metas = this.getMatchingVisibleMetas();
12834 for(let i = 0, ilen = metas.length; i < ilen; ++i){
12835 range = metas[i].controller.getMinMax(this, canStack);
12836 if (!minDefined) {
12837 min = Math.min(min, range.min);
12838 }
12839 if (!maxDefined) {
12840 max = Math.max(max, range.max);
12841 }
12842 }
12843 min = maxDefined && min > max ? max : min;
12844 max = minDefined && min > max ? min : max;
12845 return {
12846 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, min)),
12847 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, max))
12848 };
12849 }
12850 getPadding() {
12851 return {
12852 left: this.paddingLeft || 0,
12853 top: this.paddingTop || 0,
12854 right: this.paddingRight || 0,
12855 bottom: this.paddingBottom || 0
12856 };
12857 }
12858 getTicks() {
12859 return this.ticks;
12860 }
12861 getLabels() {
12862 const data = this.chart.data;
12863 return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
12864 }
12865 getLabelItems(chartArea = this.chart.chartArea) {
12866 const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
12867 return items;
12868 }
12869 beforeLayout() {
12870 this._cache = {};
12871 this._dataLimitsCached = false;
12872 }
12873 beforeUpdate() {
12874 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeUpdate, [
12875 this
12876 ]);
12877 }
12878 update(maxWidth, maxHeight, margins) {
12879 const { beginAtZero , grace , ticks: tickOpts } = this.options;
12880 const sampleSize = tickOpts.sampleSize;
12881 this.beforeUpdate();
12882 this.maxWidth = maxWidth;
12883 this.maxHeight = maxHeight;
12884 this._margins = margins = Object.assign({
12885 left: 0,
12886 right: 0,
12887 top: 0,
12888 bottom: 0
12889 }, margins);
12890 this.ticks = null;
12891 this._labelSizes = null;
12892 this._gridLineItems = null;
12893 this._labelItems = null;
12894 this.beforeSetDimensions();
12895 this.setDimensions();
12896 this.afterSetDimensions();
12897 this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;
12898 if (!this._dataLimitsCached) {
12899 this.beforeDataLimits();
12900 this.determineDataLimits();
12901 this.afterDataLimits();
12902 this._range = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.R)(this, grace, beginAtZero);
12903 this._dataLimitsCached = true;
12904 }
12905 this.beforeBuildTicks();
12906 this.ticks = this.buildTicks() || [];
12907 this.afterBuildTicks();
12908 const samplingEnabled = sampleSize < this.ticks.length;
12909 this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
12910 this.configure();
12911 this.beforeCalculateLabelRotation();
12912 this.calculateLabelRotation();
12913 this.afterCalculateLabelRotation();
12914 if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
12915 this.ticks = autoSkip(this, this.ticks);
12916 this._labelSizes = null;
12917 this.afterAutoSkip();
12918 }
12919 if (samplingEnabled) {
12920 this._convertTicksToLabels(this.ticks);
12921 }
12922 this.beforeFit();
12923 this.fit();
12924 this.afterFit();
12925 this.afterUpdate();
12926 }
12927 configure() {
12928 let reversePixels = this.options.reverse;
12929 let startPixel, endPixel;
12930 if (this.isHorizontal()) {
12931 startPixel = this.left;
12932 endPixel = this.right;
12933 } else {
12934 startPixel = this.top;
12935 endPixel = this.bottom;
12936 reversePixels = !reversePixels;
12937 }
12938 this._startPixel = startPixel;
12939 this._endPixel = endPixel;
12940 this._reversePixels = reversePixels;
12941 this._length = endPixel - startPixel;
12942 this._alignToPixels = this.options.alignToPixels;
12943 }
12944 afterUpdate() {
12945 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterUpdate, [
12946 this
12947 ]);
12948 }
12949 beforeSetDimensions() {
12950 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeSetDimensions, [
12951 this
12952 ]);
12953 }
12954 setDimensions() {
12955 if (this.isHorizontal()) {
12956 this.width = this.maxWidth;
12957 this.left = 0;
12958 this.right = this.width;
12959 } else {
12960 this.height = this.maxHeight;
12961 this.top = 0;
12962 this.bottom = this.height;
12963 }
12964 this.paddingLeft = 0;
12965 this.paddingTop = 0;
12966 this.paddingRight = 0;
12967 this.paddingBottom = 0;
12968 }
12969 afterSetDimensions() {
12970 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterSetDimensions, [
12971 this
12972 ]);
12973 }
12974 _callHooks(name) {
12975 this.chart.notifyPlugins(name, this.getContext());
12976 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options[name], [
12977 this
12978 ]);
12979 }
12980 beforeDataLimits() {
12981 this._callHooks('beforeDataLimits');
12982 }
12983 determineDataLimits() {}
12984 afterDataLimits() {
12985 this._callHooks('afterDataLimits');
12986 }
12987 beforeBuildTicks() {
12988 this._callHooks('beforeBuildTicks');
12989 }
12990 buildTicks() {
12991 return [];
12992 }
12993 afterBuildTicks() {
12994 this._callHooks('afterBuildTicks');
12995 }
12996 beforeTickToLabelConversion() {
12997 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeTickToLabelConversion, [
12998 this
12999 ]);
13000 }
13001 generateTickLabels(ticks) {
13002 const tickOpts = this.options.ticks;
13003 let i, ilen, tick;
13004 for(i = 0, ilen = ticks.length; i < ilen; i++){
13005 tick = ticks[i];
13006 tick.label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(tickOpts.callback, [
13007 tick.value,
13008 i,
13009 ticks
13010 ], this);
13011 }
13012 }
13013 afterTickToLabelConversion() {
13014 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterTickToLabelConversion, [
13015 this
13016 ]);
13017 }
13018 beforeCalculateLabelRotation() {
13019 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeCalculateLabelRotation, [
13020 this
13021 ]);
13022 }
13023 calculateLabelRotation() {
13024 const options = this.options;
13025 const tickOpts = options.ticks;
13026 const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);
13027 const minRotation = tickOpts.minRotation || 0;
13028 const maxRotation = tickOpts.maxRotation;
13029 let labelRotation = minRotation;
13030 let tickWidth, maxHeight, maxLabelDiagonal;
13031 if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
13032 this.labelRotation = minRotation;
13033 return;
13034 }
13035 const labelSizes = this._getLabelSizes();
13036 const maxLabelWidth = labelSizes.widest.width;
13037 const maxLabelHeight = labelSizes.highest.height;
13038 const maxWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(this.chart.width - maxLabelWidth, 0, this.maxWidth);
13039 tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
13040 if (maxLabelWidth + 6 > tickWidth) {
13041 tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
13042 maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
13043 maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
13044 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))));
13045 labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
13046 }
13047 this.labelRotation = labelRotation;
13048 }
13049 afterCalculateLabelRotation() {
13050 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterCalculateLabelRotation, [
13051 this
13052 ]);
13053 }
13054 afterAutoSkip() {}
13055 beforeFit() {
13056 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeFit, [
13057 this
13058 ]);
13059 }
13060 fit() {
13061 const minSize = {
13062 width: 0,
13063 height: 0
13064 };
13065 const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this;
13066 const display = this._isVisible();
13067 const isHorizontal = this.isHorizontal();
13068 if (display) {
13069 const titleHeight = getTitleHeight(titleOpts, chart.options.font);
13070 if (isHorizontal) {
13071 minSize.width = this.maxWidth;
13072 minSize.height = getTickMarkLength(gridOpts) + titleHeight;
13073 } else {
13074 minSize.height = this.maxHeight;
13075 minSize.width = getTickMarkLength(gridOpts) + titleHeight;
13076 }
13077 if (tickOpts.display && this.ticks.length) {
13078 const { first , last , widest , highest } = this._getLabelSizes();
13079 const tickPadding = tickOpts.padding * 2;
13080 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13081 const cos = Math.cos(angleRadians);
13082 const sin = Math.sin(angleRadians);
13083 if (isHorizontal) {
13084 const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
13085 minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
13086 } else {
13087 const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
13088 minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
13089 }
13090 this._calculatePadding(first, last, sin, cos);
13091 }
13092 }
13093 this._handleMargins();
13094 if (isHorizontal) {
13095 this.width = this._length = chart.width - this._margins.left - this._margins.right;
13096 this.height = minSize.height;
13097 } else {
13098 this.width = minSize.width;
13099 this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
13100 }
13101 }
13102 _calculatePadding(first, last, sin, cos) {
13103 const { ticks: { align , padding } , position } = this.options;
13104 const isRotated = this.labelRotation !== 0;
13105 const labelsBelowTicks = position !== 'top' && this.axis === 'x';
13106 if (this.isHorizontal()) {
13107 const offsetLeft = this.getPixelForTick(0) - this.left;
13108 const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
13109 let paddingLeft = 0;
13110 let paddingRight = 0;
13111 if (isRotated) {
13112 if (labelsBelowTicks) {
13113 paddingLeft = cos * first.width;
13114 paddingRight = sin * last.height;
13115 } else {
13116 paddingLeft = sin * first.height;
13117 paddingRight = cos * last.width;
13118 }
13119 } else if (align === 'start') {
13120 paddingRight = last.width;
13121 } else if (align === 'end') {
13122 paddingLeft = first.width;
13123 } else if (align !== 'inner') {
13124 paddingLeft = first.width / 2;
13125 paddingRight = last.width / 2;
13126 }
13127 this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
13128 this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
13129 } else {
13130 let paddingTop = last.height / 2;
13131 let paddingBottom = first.height / 2;
13132 if (align === 'start') {
13133 paddingTop = 0;
13134 paddingBottom = first.height;
13135 } else if (align === 'end') {
13136 paddingTop = last.height;
13137 paddingBottom = 0;
13138 }
13139 this.paddingTop = paddingTop + padding;
13140 this.paddingBottom = paddingBottom + padding;
13141 }
13142 }
13143 _handleMargins() {
13144 if (this._margins) {
13145 this._margins.left = Math.max(this.paddingLeft, this._margins.left);
13146 this._margins.top = Math.max(this.paddingTop, this._margins.top);
13147 this._margins.right = Math.max(this.paddingRight, this._margins.right);
13148 this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
13149 }
13150 }
13151 afterFit() {
13152 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterFit, [
13153 this
13154 ]);
13155 }
13156 isHorizontal() {
13157 const { axis , position } = this.options;
13158 return position === 'top' || position === 'bottom' || axis === 'x';
13159 }
13160 isFullSize() {
13161 return this.options.fullSize;
13162 }
13163 _convertTicksToLabels(ticks) {
13164 this.beforeTickToLabelConversion();
13165 this.generateTickLabels(ticks);
13166 let i, ilen;
13167 for(i = 0, ilen = ticks.length; i < ilen; i++){
13168 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(ticks[i].label)) {
13169 ticks.splice(i, 1);
13170 ilen--;
13171 i--;
13172 }
13173 }
13174 this.afterTickToLabelConversion();
13175 }
13176 _getLabelSizes() {
13177 let labelSizes = this._labelSizes;
13178 if (!labelSizes) {
13179 const sampleSize = this.options.ticks.sampleSize;
13180 let ticks = this.ticks;
13181 if (sampleSize < ticks.length) {
13182 ticks = sample(ticks, sampleSize);
13183 }
13184 this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);
13185 }
13186 return labelSizes;
13187 }
13188 _computeLabelSizes(ticks, length, maxTicksLimit) {
13189 const { ctx , _longestTextCache: caches } = this;
13190 const widths = [];
13191 const heights = [];
13192 const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));
13193 let widestLabelSize = 0;
13194 let highestLabelSize = 0;
13195 let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
13196 for(i = 0; i < length; i += increment){
13197 label = ticks[i].label;
13198 tickFont = this._resolveTickFontOptions(i);
13199 ctx.font = fontString = tickFont.string;
13200 cache = caches[fontString] = caches[fontString] || {
13201 data: {},
13202 gc: []
13203 };
13204 lineHeight = tickFont.lineHeight;
13205 width = height = 0;
13206 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(label) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13207 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, label);
13208 height = lineHeight;
13209 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13210 for(j = 0, jlen = label.length; j < jlen; ++j){
13211 nestedLabel = label[j];
13212 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(nestedLabel) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(nestedLabel)) {
13213 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, nestedLabel);
13214 height += lineHeight;
13215 }
13216 }
13217 }
13218 widths.push(width);
13219 heights.push(height);
13220 widestLabelSize = Math.max(width, widestLabelSize);
13221 highestLabelSize = Math.max(height, highestLabelSize);
13222 }
13223 garbageCollect(caches, length);
13224 const widest = widths.indexOf(widestLabelSize);
13225 const highest = heights.indexOf(highestLabelSize);
13226 const valueAt = (idx)=>({
13227 width: widths[idx] || 0,
13228 height: heights[idx] || 0
13229 });
13230 return {
13231 first: valueAt(0),
13232 last: valueAt(length - 1),
13233 widest: valueAt(widest),
13234 highest: valueAt(highest),
13235 widths,
13236 heights
13237 };
13238 }
13239 getLabelForValue(value) {
13240 return value;
13241 }
13242 getPixelForValue(value, index) {
13243 return NaN;
13244 }
13245 getValueForPixel(pixel) {}
13246 getPixelForTick(index) {
13247 const ticks = this.ticks;
13248 if (index < 0 || index > ticks.length - 1) {
13249 return null;
13250 }
13251 return this.getPixelForValue(ticks[index].value);
13252 }
13253 getPixelForDecimal(decimal) {
13254 if (this._reversePixels) {
13255 decimal = 1 - decimal;
13256 }
13257 const pixel = this._startPixel + decimal * this._length;
13258 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);
13259 }
13260 getDecimalForPixel(pixel) {
13261 const decimal = (pixel - this._startPixel) / this._length;
13262 return this._reversePixels ? 1 - decimal : decimal;
13263 }
13264 getBasePixel() {
13265 return this.getPixelForValue(this.getBaseValue());
13266 }
13267 getBaseValue() {
13268 const { min , max } = this;
13269 return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;
13270 }
13271 getContext(index) {
13272 const ticks = this.ticks || [];
13273 if (index >= 0 && index < ticks.length) {
13274 const tick = ticks[index];
13275 return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));
13276 }
13277 return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));
13278 }
13279 _tickSize() {
13280 const optionTicks = this.options.ticks;
13281 const rot = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13282 const cos = Math.abs(Math.cos(rot));
13283 const sin = Math.abs(Math.sin(rot));
13284 const labelSizes = this._getLabelSizes();
13285 const padding = optionTicks.autoSkipPadding || 0;
13286 const w = labelSizes ? labelSizes.widest.width + padding : 0;
13287 const h = labelSizes ? labelSizes.highest.height + padding : 0;
13288 return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin;
13289 }
13290 _isVisible() {
13291 const display = this.options.display;
13292 if (display !== 'auto') {
13293 return !!display;
13294 }
13295 return this.getMatchingVisibleMetas().length > 0;
13296 }
13297 _computeGridLineItems(chartArea) {
13298 const axis = this.axis;
13299 const chart = this.chart;
13300 const options = this.options;
13301 const { grid , position , border } = options;
13302 const offset = grid.offset;
13303 const isHorizontal = this.isHorizontal();
13304 const ticks = this.ticks;
13305 const ticksLength = ticks.length + (offset ? 1 : 0);
13306 const tl = getTickMarkLength(grid);
13307 const items = [];
13308 const borderOpts = border.setContext(this.getContext());
13309 const axisWidth = borderOpts.display ? borderOpts.width : 0;
13310 const axisHalfWidth = axisWidth / 2;
13311 const alignBorderValue = function(pixel) {
13312 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, pixel, axisWidth);
13313 };
13314 let borderValue, i, lineValue, alignedLineValue;
13315 let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
13316 if (position === 'top') {
13317 borderValue = alignBorderValue(this.bottom);
13318 ty1 = this.bottom - tl;
13319 ty2 = borderValue - axisHalfWidth;
13320 y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
13321 y2 = chartArea.bottom;
13322 } else if (position === 'bottom') {
13323 borderValue = alignBorderValue(this.top);
13324 y1 = chartArea.top;
13325 y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
13326 ty1 = borderValue + axisHalfWidth;
13327 ty2 = this.top + tl;
13328 } else if (position === 'left') {
13329 borderValue = alignBorderValue(this.right);
13330 tx1 = this.right - tl;
13331 tx2 = borderValue - axisHalfWidth;
13332 x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
13333 x2 = chartArea.right;
13334 } else if (position === 'right') {
13335 borderValue = alignBorderValue(this.left);
13336 x1 = chartArea.left;
13337 x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
13338 tx1 = borderValue + axisHalfWidth;
13339 tx2 = this.left + tl;
13340 } else if (axis === 'x') {
13341 if (position === 'center') {
13342 borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
13343 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13344 const positionAxisID = Object.keys(position)[0];
13345 const value = position[positionAxisID];
13346 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13347 }
13348 y1 = chartArea.top;
13349 y2 = chartArea.bottom;
13350 ty1 = borderValue + axisHalfWidth;
13351 ty2 = ty1 + tl;
13352 } else if (axis === 'y') {
13353 if (position === 'center') {
13354 borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
13355 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13356 const positionAxisID = Object.keys(position)[0];
13357 const value = position[positionAxisID];
13358 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13359 }
13360 tx1 = borderValue - axisHalfWidth;
13361 tx2 = tx1 - tl;
13362 x1 = chartArea.left;
13363 x2 = chartArea.right;
13364 }
13365 const limit = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.maxTicksLimit, ticksLength);
13366 const step = Math.max(1, Math.ceil(ticksLength / limit));
13367 for(i = 0; i < ticksLength; i += step){
13368 const context = this.getContext(i);
13369 const optsAtIndex = grid.setContext(context);
13370 const optsAtIndexBorder = border.setContext(context);
13371 const lineWidth = optsAtIndex.lineWidth;
13372 const lineColor = optsAtIndex.color;
13373 const borderDash = optsAtIndexBorder.dash || [];
13374 const borderDashOffset = optsAtIndexBorder.dashOffset;
13375 const tickWidth = optsAtIndex.tickWidth;
13376 const tickColor = optsAtIndex.tickColor;
13377 const tickBorderDash = optsAtIndex.tickBorderDash || [];
13378 const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
13379 lineValue = getPixelForGridLine(this, i, offset);
13380 if (lineValue === undefined) {
13381 continue;
13382 }
13383 alignedLineValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, lineValue, lineWidth);
13384 if (isHorizontal) {
13385 tx1 = tx2 = x1 = x2 = alignedLineValue;
13386 } else {
13387 ty1 = ty2 = y1 = y2 = alignedLineValue;
13388 }
13389 items.push({
13390 tx1,
13391 ty1,
13392 tx2,
13393 ty2,
13394 x1,
13395 y1,
13396 x2,
13397 y2,
13398 width: lineWidth,
13399 color: lineColor,
13400 borderDash,
13401 borderDashOffset,
13402 tickWidth,
13403 tickColor,
13404 tickBorderDash,
13405 tickBorderDashOffset
13406 });
13407 }
13408 this._ticksLength = ticksLength;
13409 this._borderValue = borderValue;
13410 return items;
13411 }
13412 _computeLabelItems(chartArea) {
13413 const axis = this.axis;
13414 const options = this.options;
13415 const { position , ticks: optionTicks } = options;
13416 const isHorizontal = this.isHorizontal();
13417 const ticks = this.ticks;
13418 const { align , crossAlign , padding , mirror } = optionTicks;
13419 const tl = getTickMarkLength(options.grid);
13420 const tickAndPadding = tl + padding;
13421 const hTickAndPadding = mirror ? -padding : tickAndPadding;
13422 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13423 const items = [];
13424 let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
13425 let textBaseline = 'middle';
13426 if (position === 'top') {
13427 y = this.bottom - hTickAndPadding;
13428 textAlign = this._getXAxisLabelAlignment();
13429 } else if (position === 'bottom') {
13430 y = this.top + hTickAndPadding;
13431 textAlign = this._getXAxisLabelAlignment();
13432 } else if (position === 'left') {
13433 const ret = this._getYAxisLabelAlignment(tl);
13434 textAlign = ret.textAlign;
13435 x = ret.x;
13436 } else if (position === 'right') {
13437 const ret = this._getYAxisLabelAlignment(tl);
13438 textAlign = ret.textAlign;
13439 x = ret.x;
13440 } else if (axis === 'x') {
13441 if (position === 'center') {
13442 y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;
13443 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13444 const positionAxisID = Object.keys(position)[0];
13445 const value = position[positionAxisID];
13446 y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
13447 }
13448 textAlign = this._getXAxisLabelAlignment();
13449 } else if (axis === 'y') {
13450 if (position === 'center') {
13451 x = (chartArea.left + chartArea.right) / 2 - tickAndPadding;
13452 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13453 const positionAxisID = Object.keys(position)[0];
13454 const value = position[positionAxisID];
13455 x = this.chart.scales[positionAxisID].getPixelForValue(value);
13456 }
13457 textAlign = this._getYAxisLabelAlignment(tl).textAlign;
13458 }
13459 if (axis === 'y') {
13460 if (align === 'start') {
13461 textBaseline = 'top';
13462 } else if (align === 'end') {
13463 textBaseline = 'bottom';
13464 }
13465 }
13466 const labelSizes = this._getLabelSizes();
13467 for(i = 0, ilen = ticks.length; i < ilen; ++i){
13468 tick = ticks[i];
13469 label = tick.label;
13470 const optsAtIndex = optionTicks.setContext(this.getContext(i));
13471 pixel = this.getPixelForTick(i) + optionTicks.labelOffset;
13472 font = this._resolveTickFontOptions(i);
13473 lineHeight = font.lineHeight;
13474 lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label.length : 1;
13475 const halfCount = lineCount / 2;
13476 const color = optsAtIndex.color;
13477 const strokeColor = optsAtIndex.textStrokeColor;
13478 const strokeWidth = optsAtIndex.textStrokeWidth;
13479 let tickTextAlign = textAlign;
13480 if (isHorizontal) {
13481 x = pixel;
13482 if (textAlign === 'inner') {
13483 if (i === ilen - 1) {
13484 tickTextAlign = !this.options.reverse ? 'right' : 'left';
13485 } else if (i === 0) {
13486 tickTextAlign = !this.options.reverse ? 'left' : 'right';
13487 } else {
13488 tickTextAlign = 'center';
13489 }
13490 }
13491 if (position === 'top') {
13492 if (crossAlign === 'near' || rotation !== 0) {
13493 textOffset = -lineCount * lineHeight + lineHeight / 2;
13494 } else if (crossAlign === 'center') {
13495 textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
13496 } else {
13497 textOffset = -labelSizes.highest.height + lineHeight / 2;
13498 }
13499 } else {
13500 if (crossAlign === 'near' || rotation !== 0) {
13501 textOffset = lineHeight / 2;
13502 } else if (crossAlign === 'center') {
13503 textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
13504 } else {
13505 textOffset = labelSizes.highest.height - lineCount * lineHeight;
13506 }
13507 }
13508 if (mirror) {
13509 textOffset *= -1;
13510 }
13511 if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {
13512 x += lineHeight / 2 * Math.sin(rotation);
13513 }
13514 } else {
13515 y = pixel;
13516 textOffset = (1 - lineCount) * lineHeight / 2;
13517 }
13518 let backdrop;
13519 if (optsAtIndex.showLabelBackdrop) {
13520 const labelPadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
13521 const height = labelSizes.heights[i];
13522 const width = labelSizes.widths[i];
13523 let top = textOffset - labelPadding.top;
13524 let left = 0 - labelPadding.left;
13525 switch(textBaseline){
13526 case 'middle':
13527 top -= height / 2;
13528 break;
13529 case 'bottom':
13530 top -= height;
13531 break;
13532 }
13533 switch(textAlign){
13534 case 'center':
13535 left -= width / 2;
13536 break;
13537 case 'right':
13538 left -= width;
13539 break;
13540 case 'inner':
13541 if (i === ilen - 1) {
13542 left -= width;
13543 } else if (i > 0) {
13544 left -= width / 2;
13545 }
13546 break;
13547 }
13548 backdrop = {
13549 left,
13550 top,
13551 width: width + labelPadding.width,
13552 height: height + labelPadding.height,
13553 color: optsAtIndex.backdropColor
13554 };
13555 }
13556 items.push({
13557 label,
13558 font,
13559 textOffset,
13560 options: {
13561 rotation,
13562 color,
13563 strokeColor,
13564 strokeWidth,
13565 textAlign: tickTextAlign,
13566 textBaseline,
13567 translation: [
13568 x,
13569 y
13570 ],
13571 backdrop
13572 }
13573 });
13574 }
13575 return items;
13576 }
13577 _getXAxisLabelAlignment() {
13578 const { position , ticks } = this.options;
13579 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13580 if (rotation) {
13581 return position === 'top' ? 'left' : 'right';
13582 }
13583 let align = 'center';
13584 if (ticks.align === 'start') {
13585 align = 'left';
13586 } else if (ticks.align === 'end') {
13587 align = 'right';
13588 } else if (ticks.align === 'inner') {
13589 align = 'inner';
13590 }
13591 return align;
13592 }
13593 _getYAxisLabelAlignment(tl) {
13594 const { position , ticks: { crossAlign , mirror , padding } } = this.options;
13595 const labelSizes = this._getLabelSizes();
13596 const tickAndPadding = tl + padding;
13597 const widest = labelSizes.widest.width;
13598 let textAlign;
13599 let x;
13600 if (position === 'left') {
13601 if (mirror) {
13602 x = this.right + padding;
13603 if (crossAlign === 'near') {
13604 textAlign = 'left';
13605 } else if (crossAlign === 'center') {
13606 textAlign = 'center';
13607 x += widest / 2;
13608 } else {
13609 textAlign = 'right';
13610 x += widest;
13611 }
13612 } else {
13613 x = this.right - tickAndPadding;
13614 if (crossAlign === 'near') {
13615 textAlign = 'right';
13616 } else if (crossAlign === 'center') {
13617 textAlign = 'center';
13618 x -= widest / 2;
13619 } else {
13620 textAlign = 'left';
13621 x = this.left;
13622 }
13623 }
13624 } else if (position === 'right') {
13625 if (mirror) {
13626 x = this.left + padding;
13627 if (crossAlign === 'near') {
13628 textAlign = 'right';
13629 } else if (crossAlign === 'center') {
13630 textAlign = 'center';
13631 x -= widest / 2;
13632 } else {
13633 textAlign = 'left';
13634 x -= widest;
13635 }
13636 } else {
13637 x = this.left + tickAndPadding;
13638 if (crossAlign === 'near') {
13639 textAlign = 'left';
13640 } else if (crossAlign === 'center') {
13641 textAlign = 'center';
13642 x += widest / 2;
13643 } else {
13644 textAlign = 'right';
13645 x = this.right;
13646 }
13647 }
13648 } else {
13649 textAlign = 'right';
13650 }
13651 return {
13652 textAlign,
13653 x
13654 };
13655 }
13656 _computeLabelArea() {
13657 if (this.options.ticks.mirror) {
13658 return;
13659 }
13660 const chart = this.chart;
13661 const position = this.options.position;
13662 if (position === 'left' || position === 'right') {
13663 return {
13664 top: 0,
13665 left: this.left,
13666 bottom: chart.height,
13667 right: this.right
13668 };
13669 }
13670 if (position === 'top' || position === 'bottom') {
13671 return {
13672 top: this.top,
13673 left: 0,
13674 bottom: this.bottom,
13675 right: chart.width
13676 };
13677 }
13678 }
13679 drawBackground() {
13680 const { ctx , options: { backgroundColor } , left , top , width , height } = this;
13681 if (backgroundColor) {
13682 ctx.save();
13683 ctx.fillStyle = backgroundColor;
13684 ctx.fillRect(left, top, width, height);
13685 ctx.restore();
13686 }
13687 }
13688 getLineWidthForValue(value) {
13689 const grid = this.options.grid;
13690 if (!this._isVisible() || !grid.display) {
13691 return 0;
13692 }
13693 const ticks = this.ticks;
13694 const index = ticks.findIndex((t)=>t.value === value);
13695 if (index >= 0) {
13696 const opts = grid.setContext(this.getContext(index));
13697 return opts.lineWidth;
13698 }
13699 return 0;
13700 }
13701 drawGrid(chartArea) {
13702 const grid = this.options.grid;
13703 const ctx = this.ctx;
13704 const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
13705 let i, ilen;
13706 const drawLine = (p1, p2, style)=>{
13707 if (!style.width || !style.color) {
13708 return;
13709 }
13710 ctx.save();
13711 ctx.lineWidth = style.width;
13712 ctx.strokeStyle = style.color;
13713 ctx.setLineDash(style.borderDash || []);
13714 ctx.lineDashOffset = style.borderDashOffset;
13715 ctx.beginPath();
13716 ctx.moveTo(p1.x, p1.y);
13717 ctx.lineTo(p2.x, p2.y);
13718 ctx.stroke();
13719 ctx.restore();
13720 };
13721 if (grid.display) {
13722 for(i = 0, ilen = items.length; i < ilen; ++i){
13723 const item = items[i];
13724 if (grid.drawOnChartArea) {
13725 drawLine({
13726 x: item.x1,
13727 y: item.y1
13728 }, {
13729 x: item.x2,
13730 y: item.y2
13731 }, item);
13732 }
13733 if (grid.drawTicks) {
13734 drawLine({
13735 x: item.tx1,
13736 y: item.ty1
13737 }, {
13738 x: item.tx2,
13739 y: item.ty2
13740 }, {
13741 color: item.tickColor,
13742 width: item.tickWidth,
13743 borderDash: item.tickBorderDash,
13744 borderDashOffset: item.tickBorderDashOffset
13745 });
13746 }
13747 }
13748 }
13749 }
13750 drawBorder() {
13751 const { chart , ctx , options: { border , grid } } = this;
13752 const borderOpts = border.setContext(this.getContext());
13753 const axisWidth = border.display ? borderOpts.width : 0;
13754 if (!axisWidth) {
13755 return;
13756 }
13757 const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
13758 const borderValue = this._borderValue;
13759 let x1, x2, y1, y2;
13760 if (this.isHorizontal()) {
13761 x1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.left, axisWidth) - axisWidth / 2;
13762 x2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.right, lastLineWidth) + lastLineWidth / 2;
13763 y1 = y2 = borderValue;
13764 } else {
13765 y1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.top, axisWidth) - axisWidth / 2;
13766 y2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
13767 x1 = x2 = borderValue;
13768 }
13769 ctx.save();
13770 ctx.lineWidth = borderOpts.width;
13771 ctx.strokeStyle = borderOpts.color;
13772 ctx.beginPath();
13773 ctx.moveTo(x1, y1);
13774 ctx.lineTo(x2, y2);
13775 ctx.stroke();
13776 ctx.restore();
13777 }
13778 drawLabels(chartArea) {
13779 const optionTicks = this.options.ticks;
13780 if (!optionTicks.display) {
13781 return;
13782 }
13783 const ctx = this.ctx;
13784 const area = this._computeLabelArea();
13785 if (area) {
13786 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
13787 }
13788 const items = this.getLabelItems(chartArea);
13789 for (const item of items){
13790 const renderTextOptions = item.options;
13791 const tickFont = item.font;
13792 const label = item.label;
13793 const y = item.textOffset;
13794 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, label, 0, y, tickFont, renderTextOptions);
13795 }
13796 if (area) {
13797 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
13798 }
13799 }
13800 drawTitle() {
13801 const { ctx , options: { position , title , reverse } } = this;
13802 if (!title.display) {
13803 return;
13804 }
13805 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(title.font);
13806 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(title.padding);
13807 const align = title.align;
13808 let offset = font.lineHeight / 2;
13809 if (position === 'bottom' || position === 'center' || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13810 offset += padding.bottom;
13811 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(title.text)) {
13812 offset += font.lineHeight * (title.text.length - 1);
13813 }
13814 } else {
13815 offset += padding.top;
13816 }
13817 const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align);
13818 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, title.text, 0, 0, font, {
13819 color: title.color,
13820 maxWidth,
13821 rotation,
13822 textAlign: titleAlign(align, position, reverse),
13823 textBaseline: 'middle',
13824 translation: [
13825 titleX,
13826 titleY
13827 ]
13828 });
13829 }
13830 draw(chartArea) {
13831 if (!this._isVisible()) {
13832 return;
13833 }
13834 this.drawBackground();
13835 this.drawGrid(chartArea);
13836 this.drawBorder();
13837 this.drawTitle();
13838 this.drawLabels(chartArea);
13839 }
13840 _layers() {
13841 const opts = this.options;
13842 const tz = opts.ticks && opts.ticks.z || 0;
13843 const gz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.grid && opts.grid.z, -1);
13844 const bz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.border && opts.border.z, 0);
13845 if (!this._isVisible() || this.draw !== Scale.prototype.draw) {
13846 return [
13847 {
13848 z: tz,
13849 draw: (chartArea)=>{
13850 this.draw(chartArea);
13851 }
13852 }
13853 ];
13854 }
13855 return [
13856 {
13857 z: gz,
13858 draw: (chartArea)=>{
13859 this.drawBackground();
13860 this.drawGrid(chartArea);
13861 this.drawTitle();
13862 }
13863 },
13864 {
13865 z: bz,
13866 draw: ()=>{
13867 this.drawBorder();
13868 }
13869 },
13870 {
13871 z: tz,
13872 draw: (chartArea)=>{
13873 this.drawLabels(chartArea);
13874 }
13875 }
13876 ];
13877 }
13878 getMatchingVisibleMetas(type) {
13879 const metas = this.chart.getSortedVisibleDatasetMetas();
13880 const axisID = this.axis + 'AxisID';
13881 const result = [];
13882 let i, ilen;
13883 for(i = 0, ilen = metas.length; i < ilen; ++i){
13884 const meta = metas[i];
13885 if (meta[axisID] === this.id && (!type || meta.type === type)) {
13886 result.push(meta);
13887 }
13888 }
13889 return result;
13890 }
13891 _resolveTickFontOptions(index) {
13892 const opts = this.options.ticks.setContext(this.getContext(index));
13893 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
13894 }
13895 _maxDigits() {
13896 const fontSize = this._resolveTickFontOptions(0).lineHeight;
13897 return (this.isHorizontal() ? this.width : this.height) / fontSize;
13898 }
13899 }
13900
13901 class TypedRegistry {
13902 constructor(type, scope, override){
13903 this.type = type;
13904 this.scope = scope;
13905 this.override = override;
13906 this.items = Object.create(null);
13907 }
13908 isForType(type) {
13909 return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
13910 }
13911 register(item) {
13912 const proto = Object.getPrototypeOf(item);
13913 let parentScope;
13914 if (isIChartComponent(proto)) {
13915 parentScope = this.register(proto);
13916 }
13917 const items = this.items;
13918 const id = item.id;
13919 const scope = this.scope + '.' + id;
13920 if (!id) {
13921 throw new Error('class does not have id: ' + item);
13922 }
13923 if (id in items) {
13924 return scope;
13925 }
13926 items[id] = item;
13927 registerDefaults(item, scope, parentScope);
13928 if (this.override) {
13929 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.override(item.id, item.overrides);
13930 }
13931 return scope;
13932 }
13933 get(id) {
13934 return this.items[id];
13935 }
13936 unregister(item) {
13937 const items = this.items;
13938 const id = item.id;
13939 const scope = this.scope;
13940 if (id in items) {
13941 delete items[id];
13942 }
13943 if (scope && id in _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope]) {
13944 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope][id];
13945 if (this.override) {
13946 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[id];
13947 }
13948 }
13949 }
13950 }
13951 function registerDefaults(item, scope, parentScope) {
13952 const itemDefaults = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a4)(Object.create(null), [
13953 parentScope ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(parentScope) : {},
13954 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(scope),
13955 item.defaults
13956 ]);
13957 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.set(scope, itemDefaults);
13958 if (item.defaultRoutes) {
13959 routeDefaults(scope, item.defaultRoutes);
13960 }
13961 if (item.descriptors) {
13962 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.describe(scope, item.descriptors);
13963 }
13964 }
13965 function routeDefaults(scope, routes) {
13966 Object.keys(routes).forEach((property)=>{
13967 const propertyParts = property.split('.');
13968 const sourceName = propertyParts.pop();
13969 const sourceScope = [
13970 scope
13971 ].concat(propertyParts).join('.');
13972 const parts = routes[property].split('.');
13973 const targetName = parts.pop();
13974 const targetScope = parts.join('.');
13975 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.route(sourceScope, sourceName, targetScope, targetName);
13976 });
13977 }
13978 function isIChartComponent(proto) {
13979 return 'id' in proto && 'defaults' in proto;
13980 }
13981
13982 class Registry {
13983 constructor(){
13984 this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
13985 this.elements = new TypedRegistry(Element, 'elements');
13986 this.plugins = new TypedRegistry(Object, 'plugins');
13987 this.scales = new TypedRegistry(Scale, 'scales');
13988 this._typedRegistries = [
13989 this.controllers,
13990 this.scales,
13991 this.elements
13992 ];
13993 }
13994 add(...args) {
13995 this._each('register', args);
13996 }
13997 remove(...args) {
13998 this._each('unregister', args);
13999 }
14000 addControllers(...args) {
14001 this._each('register', args, this.controllers);
14002 }
14003 addElements(...args) {
14004 this._each('register', args, this.elements);
14005 }
14006 addPlugins(...args) {
14007 this._each('register', args, this.plugins);
14008 }
14009 addScales(...args) {
14010 this._each('register', args, this.scales);
14011 }
14012 getController(id) {
14013 return this._get(id, this.controllers, 'controller');
14014 }
14015 getElement(id) {
14016 return this._get(id, this.elements, 'element');
14017 }
14018 getPlugin(id) {
14019 return this._get(id, this.plugins, 'plugin');
14020 }
14021 getScale(id) {
14022 return this._get(id, this.scales, 'scale');
14023 }
14024 removeControllers(...args) {
14025 this._each('unregister', args, this.controllers);
14026 }
14027 removeElements(...args) {
14028 this._each('unregister', args, this.elements);
14029 }
14030 removePlugins(...args) {
14031 this._each('unregister', args, this.plugins);
14032 }
14033 removeScales(...args) {
14034 this._each('unregister', args, this.scales);
14035 }
14036 _each(method, args, typedRegistry) {
14037 [
14038 ...args
14039 ].forEach((arg)=>{
14040 const reg = typedRegistry || this._getRegistryForType(arg);
14041 if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {
14042 this._exec(method, reg, arg);
14043 } else {
14044 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(arg, (item)=>{
14045 const itemReg = typedRegistry || this._getRegistryForType(item);
14046 this._exec(method, itemReg, item);
14047 });
14048 }
14049 });
14050 }
14051 _exec(method, registry, component) {
14052 const camelMethod = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a5)(method);
14053 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['before' + camelMethod], [], component);
14054 registry[method](component);
14055 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['after' + camelMethod], [], component);
14056 }
14057 _getRegistryForType(type) {
14058 for(let i = 0; i < this._typedRegistries.length; i++){
14059 const reg = this._typedRegistries[i];
14060 if (reg.isForType(type)) {
14061 return reg;
14062 }
14063 }
14064 return this.plugins;
14065 }
14066 _get(id, typedRegistry, type) {
14067 const item = typedRegistry.get(id);
14068 if (item === undefined) {
14069 throw new Error('"' + id + '" is not a registered ' + type + '.');
14070 }
14071 return item;
14072 }
14073 }
14074 var registry = /* #__PURE__ */ new Registry();
14075
14076 class PluginService {
14077 constructor(){
14078 this._init = undefined;
14079 }
14080 notify(chart, hook, args, filter) {
14081 if (hook === 'beforeInit') {
14082 this._init = this._createDescriptors(chart, true);
14083 this._notify(this._init, chart, 'install');
14084 }
14085 if (this._init === undefined) {
14086 return;
14087 }
14088 const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
14089 const result = this._notify(descriptors, chart, hook, args);
14090 if (hook === 'afterDestroy') {
14091 this._notify(descriptors, chart, 'stop');
14092 this._notify(this._init, chart, 'uninstall');
14093 this._init = undefined;
14094 }
14095 return result;
14096 }
14097 _notify(descriptors, chart, hook, args) {
14098 args = args || {};
14099 for (const descriptor of descriptors){
14100 const plugin = descriptor.plugin;
14101 const method = plugin[hook];
14102 const params = [
14103 chart,
14104 args,
14105 descriptor.options
14106 ];
14107 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(method, params, plugin) === false && args.cancelable) {
14108 return false;
14109 }
14110 }
14111 return true;
14112 }
14113 invalidate() {
14114 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(this._cache)) {
14115 this._oldCache = this._cache;
14116 this._cache = undefined;
14117 }
14118 }
14119 _descriptors(chart) {
14120 if (this._cache) {
14121 return this._cache;
14122 }
14123 const descriptors = this._cache = this._createDescriptors(chart);
14124 this._notifyStateChanges(chart);
14125 return descriptors;
14126 }
14127 _createDescriptors(chart, all) {
14128 const config = chart && chart.config;
14129 const options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(config.options && config.options.plugins, {});
14130 const plugins = allPlugins(config);
14131 return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
14132 }
14133 _notifyStateChanges(chart) {
14134 const previousDescriptors = this._oldCache || [];
14135 const descriptors = this._cache;
14136 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id));
14137 this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
14138 this._notify(diff(descriptors, previousDescriptors), chart, 'start');
14139 }
14140 }
14141 function allPlugins(config) {
14142 const localIds = {};
14143 const plugins = [];
14144 const keys = Object.keys(registry.plugins.items);
14145 for(let i = 0; i < keys.length; i++){
14146 plugins.push(registry.getPlugin(keys[i]));
14147 }
14148 const local = config.plugins || [];
14149 for(let i = 0; i < local.length; i++){
14150 const plugin = local[i];
14151 if (plugins.indexOf(plugin) === -1) {
14152 plugins.push(plugin);
14153 localIds[plugin.id] = true;
14154 }
14155 }
14156 return {
14157 plugins,
14158 localIds
14159 };
14160 }
14161 function getOpts(options, all) {
14162 if (!all && options === false) {
14163 return null;
14164 }
14165 if (options === true) {
14166 return {};
14167 }
14168 return options;
14169 }
14170 function createDescriptors(chart, { plugins , localIds }, options, all) {
14171 const result = [];
14172 const context = chart.getContext();
14173 for (const plugin of plugins){
14174 const id = plugin.id;
14175 const opts = getOpts(options[id], all);
14176 if (opts === null) {
14177 continue;
14178 }
14179 result.push({
14180 plugin,
14181 options: pluginOpts(chart.config, {
14182 plugin,
14183 local: localIds[id]
14184 }, opts, context)
14185 });
14186 }
14187 return result;
14188 }
14189 function pluginOpts(config, { plugin , local }, opts, context) {
14190 const keys = config.pluginScopeKeys(plugin);
14191 const scopes = config.getOptionScopes(opts, keys);
14192 if (local && plugin.defaults) {
14193 scopes.push(plugin.defaults);
14194 }
14195 return config.createResolver(scopes, context, [
14196 ''
14197 ], {
14198 scriptable: false,
14199 indexable: false,
14200 allKeys: true
14201 });
14202 }
14203
14204 function getIndexAxis(type, options) {
14205 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {};
14206 const datasetOptions = (options.datasets || {})[type] || {};
14207 return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
14208 }
14209 function getAxisFromDefaultScaleID(id, indexAxis) {
14210 let axis = id;
14211 if (id === '_index_') {
14212 axis = indexAxis;
14213 } else if (id === '_value_') {
14214 axis = indexAxis === 'x' ? 'y' : 'x';
14215 }
14216 return axis;
14217 }
14218 function getDefaultScaleIDFromAxis(axis, indexAxis) {
14219 return axis === indexAxis ? '_index_' : '_value_';
14220 }
14221 function idMatchesAxis(id) {
14222 if (id === 'x' || id === 'y' || id === 'r') {
14223 return id;
14224 }
14225 }
14226 function axisFromPosition(position) {
14227 if (position === 'top' || position === 'bottom') {
14228 return 'x';
14229 }
14230 if (position === 'left' || position === 'right') {
14231 return 'y';
14232 }
14233 }
14234 function determineAxis(id, ...scaleOptions) {
14235 if (idMatchesAxis(id)) {
14236 return id;
14237 }
14238 for (const opts of scaleOptions){
14239 const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());
14240 if (axis) {
14241 return axis;
14242 }
14243 }
14244 throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
14245 }
14246 function getAxisFromDataset(id, axis, dataset) {
14247 if (dataset[axis + 'AxisID'] === id) {
14248 return {
14249 axis
14250 };
14251 }
14252 }
14253 function retrieveAxisFromDatasets(id, config) {
14254 if (config.data && config.data.datasets) {
14255 const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id);
14256 if (boundDs.length) {
14257 return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);
14258 }
14259 }
14260 return {};
14261 }
14262 function mergeScaleConfig(config, options) {
14263 const chartDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[config.type] || {
14264 scales: {}
14265 };
14266 const configScales = options.scales || {};
14267 const chartIndexAxis = getIndexAxis(config.type, options);
14268 const scales = Object.create(null);
14269 Object.keys(configScales).forEach((id)=>{
14270 const scaleConf = configScales[id];
14271 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(scaleConf)) {
14272 return console.error(`Invalid scale configuration for scale: ${id}`);
14273 }
14274 if (scaleConf._proxy) {
14275 return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
14276 }
14277 const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scaleConf.type]);
14278 const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
14279 const defaultScaleOptions = chartDefaults.scales || {};
14280 scales[id] = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(Object.create(null), [
14281 {
14282 axis
14283 },
14284 scaleConf,
14285 defaultScaleOptions[axis],
14286 defaultScaleOptions[defaultId]
14287 ]);
14288 });
14289 config.data.datasets.forEach((dataset)=>{
14290 const type = dataset.type || config.type;
14291 const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
14292 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {};
14293 const defaultScaleOptions = datasetDefaults.scales || {};
14294 Object.keys(defaultScaleOptions).forEach((defaultID)=>{
14295 const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
14296 const id = dataset[axis + 'AxisID'] || axis;
14297 scales[id] = scales[id] || Object.create(null);
14298 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scales[id], [
14299 {
14300 axis
14301 },
14302 configScales[id],
14303 defaultScaleOptions[defaultID]
14304 ]);
14305 });
14306 });
14307 Object.keys(scales).forEach((key)=>{
14308 const scale = scales[key];
14309 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scale, [
14310 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scale.type],
14311 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scale
14312 ]);
14313 });
14314 return scales;
14315 }
14316 function initOptions(config) {
14317 const options = config.options || (config.options = {});
14318 options.plugins = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.plugins, {});
14319 options.scales = mergeScaleConfig(config, options);
14320 }
14321 function initData(data) {
14322 data = data || {};
14323 data.datasets = data.datasets || [];
14324 data.labels = data.labels || [];
14325 return data;
14326 }
14327 function initConfig(config) {
14328 config = config || {};
14329 config.data = initData(config.data);
14330 initOptions(config);
14331 return config;
14332 }
14333 const keyCache = new Map();
14334 const keysCached = new Set();
14335 function cachedKeys(cacheKey, generate) {
14336 let keys = keyCache.get(cacheKey);
14337 if (!keys) {
14338 keys = generate();
14339 keyCache.set(cacheKey, keys);
14340 keysCached.add(keys);
14341 }
14342 return keys;
14343 }
14344 const addIfFound = (set, obj, key)=>{
14345 const opts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, key);
14346 if (opts !== undefined) {
14347 set.add(opts);
14348 }
14349 };
14350 class Config {
14351 constructor(config){
14352 this._config = initConfig(config);
14353 this._scopeCache = new Map();
14354 this._resolverCache = new Map();
14355 }
14356 get platform() {
14357 return this._config.platform;
14358 }
14359 get type() {
14360 return this._config.type;
14361 }
14362 set type(type) {
14363 this._config.type = type;
14364 }
14365 get data() {
14366 return this._config.data;
14367 }
14368 set data(data) {
14369 this._config.data = initData(data);
14370 }
14371 get options() {
14372 return this._config.options;
14373 }
14374 set options(options) {
14375 this._config.options = options;
14376 }
14377 get plugins() {
14378 return this._config.plugins;
14379 }
14380 update() {
14381 const config = this._config;
14382 this.clearCache();
14383 initOptions(config);
14384 }
14385 clearCache() {
14386 this._scopeCache.clear();
14387 this._resolverCache.clear();
14388 }
14389 datasetScopeKeys(datasetType) {
14390 return cachedKeys(datasetType, ()=>[
14391 [
14392 `datasets.${datasetType}`,
14393 ''
14394 ]
14395 ]);
14396 }
14397 datasetAnimationScopeKeys(datasetType, transition) {
14398 return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[
14399 [
14400 `datasets.${datasetType}.transitions.${transition}`,
14401 `transitions.${transition}`
14402 ],
14403 [
14404 `datasets.${datasetType}`,
14405 ''
14406 ]
14407 ]);
14408 }
14409 datasetElementScopeKeys(datasetType, elementType) {
14410 return cachedKeys(`${datasetType}-${elementType}`, ()=>[
14411 [
14412 `datasets.${datasetType}.elements.${elementType}`,
14413 `datasets.${datasetType}`,
14414 `elements.${elementType}`,
14415 ''
14416 ]
14417 ]);
14418 }
14419 pluginScopeKeys(plugin) {
14420 const id = plugin.id;
14421 const type = this.type;
14422 return cachedKeys(`${type}-plugin-${id}`, ()=>[
14423 [
14424 `plugins.${id}`,
14425 ...plugin.additionalOptionScopes || []
14426 ]
14427 ]);
14428 }
14429 _cachedScopes(mainScope, resetCache) {
14430 const _scopeCache = this._scopeCache;
14431 let cache = _scopeCache.get(mainScope);
14432 if (!cache || resetCache) {
14433 cache = new Map();
14434 _scopeCache.set(mainScope, cache);
14435 }
14436 return cache;
14437 }
14438 getOptionScopes(mainScope, keyLists, resetCache) {
14439 const { options , type } = this;
14440 const cache = this._cachedScopes(mainScope, resetCache);
14441 const cached = cache.get(keyLists);
14442 if (cached) {
14443 return cached;
14444 }
14445 const scopes = new Set();
14446 keyLists.forEach((keys)=>{
14447 if (mainScope) {
14448 scopes.add(mainScope);
14449 keys.forEach((key)=>addIfFound(scopes, mainScope, key));
14450 }
14451 keys.forEach((key)=>addIfFound(scopes, options, key));
14452 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, key));
14453 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, key));
14454 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6, key));
14455 });
14456 const array = Array.from(scopes);
14457 if (array.length === 0) {
14458 array.push(Object.create(null));
14459 }
14460 if (keysCached.has(keyLists)) {
14461 cache.set(keyLists, array);
14462 }
14463 return array;
14464 }
14465 chartOptionScopes() {
14466 const { options , type } = this;
14467 return [
14468 options,
14469 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {},
14470 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {},
14471 {
14472 type
14473 },
14474 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d,
14475 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6
14476 ];
14477 }
14478 resolveNamedOptions(scopes, names, context, prefixes = [
14479 ''
14480 ]) {
14481 const result = {
14482 $shared: true
14483 };
14484 const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);
14485 let options = resolver;
14486 if (needContext(resolver, names)) {
14487 result.$shared = false;
14488 context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(context) ? context() : context;
14489 const subResolver = this.createResolver(scopes, context, subPrefixes);
14490 options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, subResolver);
14491 }
14492 for (const prop of names){
14493 result[prop] = options[prop];
14494 }
14495 return result;
14496 }
14497 createResolver(scopes, context, prefixes = [
14498 ''
14499 ], descriptorDefaults) {
14500 const { resolver } = getResolver(this._resolverCache, scopes, prefixes);
14501 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;
14502 }
14503 }
14504 function getResolver(resolverCache, scopes, prefixes) {
14505 let cache = resolverCache.get(scopes);
14506 if (!cache) {
14507 cache = new Map();
14508 resolverCache.set(scopes, cache);
14509 }
14510 const cacheKey = prefixes.join();
14511 let cached = cache.get(cacheKey);
14512 if (!cached) {
14513 const resolver = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a9)(scopes, prefixes);
14514 cached = {
14515 resolver,
14516 subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover'))
14517 };
14518 cache.set(cacheKey, cached);
14519 }
14520 return cached;
14521 }
14522 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]));
14523 function needContext(proxy, names) {
14524 const { isScriptable , isIndexable } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aa)(proxy);
14525 for (const prop of names){
14526 const scriptable = isScriptable(prop);
14527 const indexable = isIndexable(prop);
14528 const value = (indexable || scriptable) && proxy[prop];
14529 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)) {
14530 return true;
14531 }
14532 }
14533 return false;
14534 }
14535
14536 var version = "4.5.1";
14537
14538 const KNOWN_POSITIONS = [
14539 'top',
14540 'bottom',
14541 'left',
14542 'right',
14543 'chartArea'
14544 ];
14545 function positionIsHorizontal(position, axis) {
14546 return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x';
14547 }
14548 function compare2Level(l1, l2) {
14549 return function(a, b) {
14550 return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1];
14551 };
14552 }
14553 function onAnimationsComplete(context) {
14554 const chart = context.chart;
14555 const animationOptions = chart.options.animation;
14556 chart.notifyPlugins('afterRender');
14557 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onComplete, [
14558 context
14559 ], chart);
14560 }
14561 function onAnimationProgress(context) {
14562 const chart = context.chart;
14563 const animationOptions = chart.options.animation;
14564 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onProgress, [
14565 context
14566 ], chart);
14567 }
14568 function getCanvas(item) {
14569 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() && typeof item === 'string') {
14570 item = document.getElementById(item);
14571 } else if (item && item.length) {
14572 item = item[0];
14573 }
14574 if (item && item.canvas) {
14575 item = item.canvas;
14576 }
14577 return item;
14578 }
14579 const instances = {};
14580 const getChart = (key)=>{
14581 const canvas = getCanvas(key);
14582 return Object.values(instances).filter((c)=>c.canvas === canvas).pop();
14583 };
14584 function moveNumericKeys(obj, start, move) {
14585 const keys = Object.keys(obj);
14586 for (const key of keys){
14587 const intKey = +key;
14588 if (intKey >= start) {
14589 const value = obj[key];
14590 delete obj[key];
14591 if (move > 0 || intKey > start) {
14592 obj[intKey + move] = value;
14593 }
14594 }
14595 }
14596 }
14597 function determineLastEvent(e, lastEvent, inChartArea, isClick) {
14598 if (!inChartArea || e.type === 'mouseout') {
14599 return null;
14600 }
14601 if (isClick) {
14602 return lastEvent;
14603 }
14604 return e;
14605 }
14606 class Chart {
14607 static defaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d;
14608 static instances = instances;
14609 static overrides = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3;
14610 static registry = registry;
14611 static version = version;
14612 static getChart = getChart;
14613 static register(...items) {
14614 registry.add(...items);
14615 invalidatePlugins();
14616 }
14617 static unregister(...items) {
14618 registry.remove(...items);
14619 invalidatePlugins();
14620 }
14621 constructor(item, userConfig){
14622 const config = this.config = new Config(userConfig);
14623 const initialCanvas = getCanvas(item);
14624 const existingChart = getChart(initialCanvas);
14625 if (existingChart) {
14626 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.');
14627 }
14628 const options = config.createResolver(config.chartOptionScopes(), this.getContext());
14629 this.platform = new (config.platform || _detectPlatform(initialCanvas))();
14630 this.platform.updateConfig(config);
14631 const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
14632 const canvas = context && context.canvas;
14633 const height = canvas && canvas.height;
14634 const width = canvas && canvas.width;
14635 this.id = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ac)();
14636 this.ctx = context;
14637 this.canvas = canvas;
14638 this.width = width;
14639 this.height = height;
14640 this._options = options;
14641 this._aspectRatio = this.aspectRatio;
14642 this._layers = [];
14643 this._metasets = [];
14644 this._stacks = undefined;
14645 this.boxes = [];
14646 this.currentDevicePixelRatio = undefined;
14647 this.chartArea = undefined;
14648 this._active = [];
14649 this._lastEvent = undefined;
14650 this._listeners = {};
14651 this._responsiveListeners = undefined;
14652 this._sortedMetasets = [];
14653 this.scales = {};
14654 this._plugins = new PluginService();
14655 this.$proxies = {};
14656 this._hiddenIndices = {};
14657 this.attached = false;
14658 this._animationsDisabled = undefined;
14659 this.$context = undefined;
14660 this._doResize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ad)((mode)=>this.update(mode), options.resizeDelay || 0);
14661 this._dataChanges = [];
14662 instances[this.id] = this;
14663 if (!context || !canvas) {
14664 console.error("Failed to create chart: can't acquire context from the given item");
14665 return;
14666 }
14667 animator.listen(this, 'complete', onAnimationsComplete);
14668 animator.listen(this, 'progress', onAnimationProgress);
14669 this._initialize();
14670 if (this.attached) {
14671 this.update();
14672 }
14673 }
14674 get aspectRatio() {
14675 const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this;
14676 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(aspectRatio)) {
14677 return aspectRatio;
14678 }
14679 if (maintainAspectRatio && _aspectRatio) {
14680 return _aspectRatio;
14681 }
14682 return height ? width / height : null;
14683 }
14684 get data() {
14685 return this.config.data;
14686 }
14687 set data(data) {
14688 this.config.data = data;
14689 }
14690 get options() {
14691 return this._options;
14692 }
14693 set options(options) {
14694 this.config.options = options;
14695 }
14696 get registry() {
14697 return registry;
14698 }
14699 _initialize() {
14700 this.notifyPlugins('beforeInit');
14701 if (this.options.responsive) {
14702 this.resize();
14703 } else {
14704 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, this.options.devicePixelRatio);
14705 }
14706 this.bindEvents();
14707 this.notifyPlugins('afterInit');
14708 return this;
14709 }
14710 clear() {
14711 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(this.canvas, this.ctx);
14712 return this;
14713 }
14714 stop() {
14715 animator.stop(this);
14716 return this;
14717 }
14718 resize(width, height) {
14719 if (!animator.running(this)) {
14720 this._resize(width, height);
14721 } else {
14722 this._resizeBeforeDraw = {
14723 width,
14724 height
14725 };
14726 }
14727 }
14728 _resize(width, height) {
14729 const options = this.options;
14730 const canvas = this.canvas;
14731 const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
14732 const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
14733 const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
14734 const mode = this.width ? 'resize' : 'attach';
14735 this.width = newSize.width;
14736 this.height = newSize.height;
14737 this._aspectRatio = this.aspectRatio;
14738 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, newRatio, true)) {
14739 return;
14740 }
14741 this.notifyPlugins('resize', {
14742 size: newSize
14743 });
14744 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onResize, [
14745 this,
14746 newSize
14747 ], this);
14748 if (this.attached) {
14749 if (this._doResize(mode)) {
14750 this.render();
14751 }
14752 }
14753 }
14754 ensureScalesHaveIDs() {
14755 const options = this.options;
14756 const scalesOptions = options.scales || {};
14757 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scalesOptions, (axisOptions, axisID)=>{
14758 axisOptions.id = axisID;
14759 });
14760 }
14761 buildOrUpdateScales() {
14762 const options = this.options;
14763 const scaleOpts = options.scales;
14764 const scales = this.scales;
14765 const updated = Object.keys(scales).reduce((obj, id)=>{
14766 obj[id] = false;
14767 return obj;
14768 }, {});
14769 let items = [];
14770 if (scaleOpts) {
14771 items = items.concat(Object.keys(scaleOpts).map((id)=>{
14772 const scaleOptions = scaleOpts[id];
14773 const axis = determineAxis(id, scaleOptions);
14774 const isRadial = axis === 'r';
14775 const isHorizontal = axis === 'x';
14776 return {
14777 options: scaleOptions,
14778 dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
14779 dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
14780 };
14781 }));
14782 }
14783 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(items, (item)=>{
14784 const scaleOptions = item.options;
14785 const id = scaleOptions.id;
14786 const axis = determineAxis(id, scaleOptions);
14787 const scaleType = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(scaleOptions.type, item.dtype);
14788 if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
14789 scaleOptions.position = item.dposition;
14790 }
14791 updated[id] = true;
14792 let scale = null;
14793 if (id in scales && scales[id].type === scaleType) {
14794 scale = scales[id];
14795 } else {
14796 const scaleClass = registry.getScale(scaleType);
14797 scale = new scaleClass({
14798 id,
14799 type: scaleType,
14800 ctx: this.ctx,
14801 chart: this
14802 });
14803 scales[scale.id] = scale;
14804 }
14805 scale.init(scaleOptions, options);
14806 });
14807 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(updated, (hasUpdated, id)=>{
14808 if (!hasUpdated) {
14809 delete scales[id];
14810 }
14811 });
14812 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scales, (scale)=>{
14813 layouts.configure(this, scale, scale.options);
14814 layouts.addBox(this, scale);
14815 });
14816 }
14817 _updateMetasets() {
14818 const metasets = this._metasets;
14819 const numData = this.data.datasets.length;
14820 const numMeta = metasets.length;
14821 metasets.sort((a, b)=>a.index - b.index);
14822 if (numMeta > numData) {
14823 for(let i = numData; i < numMeta; ++i){
14824 this._destroyDatasetMeta(i);
14825 }
14826 metasets.splice(numData, numMeta - numData);
14827 }
14828 this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
14829 }
14830 _removeUnreferencedMetasets() {
14831 const { _metasets: metasets , data: { datasets } } = this;
14832 if (metasets.length > datasets.length) {
14833 delete this._stacks;
14834 }
14835 metasets.forEach((meta, index)=>{
14836 if (datasets.filter((x)=>x === meta._dataset).length === 0) {
14837 this._destroyDatasetMeta(index);
14838 }
14839 });
14840 }
14841 buildOrUpdateControllers() {
14842 const newControllers = [];
14843 const datasets = this.data.datasets;
14844 let i, ilen;
14845 this._removeUnreferencedMetasets();
14846 for(i = 0, ilen = datasets.length; i < ilen; i++){
14847 const dataset = datasets[i];
14848 let meta = this.getDatasetMeta(i);
14849 const type = dataset.type || this.config.type;
14850 if (meta.type && meta.type !== type) {
14851 this._destroyDatasetMeta(i);
14852 meta = this.getDatasetMeta(i);
14853 }
14854 meta.type = type;
14855 meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
14856 meta.order = dataset.order || 0;
14857 meta.index = i;
14858 meta.label = '' + dataset.label;
14859 meta.visible = this.isDatasetVisible(i);
14860 if (meta.controller) {
14861 meta.controller.updateIndex(i);
14862 meta.controller.linkScales();
14863 } else {
14864 const ControllerClass = registry.getController(type);
14865 const { datasetElementType , dataElementType } = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type];
14866 Object.assign(ControllerClass, {
14867 dataElementType: registry.getElement(dataElementType),
14868 datasetElementType: datasetElementType && registry.getElement(datasetElementType)
14869 });
14870 meta.controller = new ControllerClass(this, i);
14871 newControllers.push(meta.controller);
14872 }
14873 }
14874 this._updateMetasets();
14875 return newControllers;
14876 }
14877 _resetElements() {
14878 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.data.datasets, (dataset, datasetIndex)=>{
14879 this.getDatasetMeta(datasetIndex).controller.reset();
14880 }, this);
14881 }
14882 reset() {
14883 this._resetElements();
14884 this.notifyPlugins('reset');
14885 }
14886 update(mode) {
14887 const config = this.config;
14888 config.update();
14889 const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
14890 const animsDisabled = this._animationsDisabled = !options.animation;
14891 this._updateScales();
14892 this._checkEventBindings();
14893 this._updateHiddenIndices();
14894 this._plugins.invalidate();
14895 if (this.notifyPlugins('beforeUpdate', {
14896 mode,
14897 cancelable: true
14898 }) === false) {
14899 return;
14900 }
14901 const newControllers = this.buildOrUpdateControllers();
14902 this.notifyPlugins('beforeElementsUpdate');
14903 let minPadding = 0;
14904 for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){
14905 const { controller } = this.getDatasetMeta(i);
14906 const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
14907 controller.buildOrUpdateElements(reset);
14908 minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
14909 }
14910 minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
14911 this._updateLayout(minPadding);
14912 if (!animsDisabled) {
14913 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(newControllers, (controller)=>{
14914 controller.reset();
14915 });
14916 }
14917 this._updateDatasets(mode);
14918 this.notifyPlugins('afterUpdate', {
14919 mode
14920 });
14921 this._layers.sort(compare2Level('z', '_idx'));
14922 const { _active , _lastEvent } = this;
14923 if (_lastEvent) {
14924 this._eventHandler(_lastEvent, true);
14925 } else if (_active.length) {
14926 this._updateHoverStyles(_active, _active, true);
14927 }
14928 this.render();
14929 }
14930 _updateScales() {
14931 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.scales, (scale)=>{
14932 layouts.removeBox(this, scale);
14933 });
14934 this.ensureScalesHaveIDs();
14935 this.buildOrUpdateScales();
14936 }
14937 _checkEventBindings() {
14938 const options = this.options;
14939 const existingEvents = new Set(Object.keys(this._listeners));
14940 const newEvents = new Set(options.events);
14941 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
14942 this.unbindEvents();
14943 this.bindEvents();
14944 }
14945 }
14946 _updateHiddenIndices() {
14947 const { _hiddenIndices } = this;
14948 const changes = this._getUniformDataChanges() || [];
14949 for (const { method , start , count } of changes){
14950 const move = method === '_removeElements' ? -count : count;
14951 moveNumericKeys(_hiddenIndices, start, move);
14952 }
14953 }
14954 _getUniformDataChanges() {
14955 const _dataChanges = this._dataChanges;
14956 if (!_dataChanges || !_dataChanges.length) {
14957 return;
14958 }
14959 this._dataChanges = [];
14960 const datasetCount = this.data.datasets.length;
14961 const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(',')));
14962 const changeSet = makeSet(0);
14963 for(let i = 1; i < datasetCount; i++){
14964 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(changeSet, makeSet(i))) {
14965 return;
14966 }
14967 }
14968 return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({
14969 method: a[1],
14970 start: +a[2],
14971 count: +a[3]
14972 }));
14973 }
14974 _updateLayout(minPadding) {
14975 if (this.notifyPlugins('beforeLayout', {
14976 cancelable: true
14977 }) === false) {
14978 return;
14979 }
14980 layouts.update(this, this.width, this.height, minPadding);
14981 const area = this.chartArea;
14982 const noArea = area.width <= 0 || area.height <= 0;
14983 this._layers = [];
14984 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.boxes, (box)=>{
14985 if (noArea && box.position === 'chartArea') {
14986 return;
14987 }
14988 if (box.configure) {
14989 box.configure();
14990 }
14991 this._layers.push(...box._layers());
14992 }, this);
14993 this._layers.forEach((item, index)=>{
14994 item._idx = index;
14995 });
14996 this.notifyPlugins('afterLayout');
14997 }
14998 _updateDatasets(mode) {
14999 if (this.notifyPlugins('beforeDatasetsUpdate', {
15000 mode,
15001 cancelable: true
15002 }) === false) {
15003 return;
15004 }
15005 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15006 this.getDatasetMeta(i).controller.configure();
15007 }
15008 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15009 this._updateDataset(i, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(mode) ? mode({
15010 datasetIndex: i
15011 }) : mode);
15012 }
15013 this.notifyPlugins('afterDatasetsUpdate', {
15014 mode
15015 });
15016 }
15017 _updateDataset(index, mode) {
15018 const meta = this.getDatasetMeta(index);
15019 const args = {
15020 meta,
15021 index,
15022 mode,
15023 cancelable: true
15024 };
15025 if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {
15026 return;
15027 }
15028 meta.controller._update(mode);
15029 args.cancelable = false;
15030 this.notifyPlugins('afterDatasetUpdate', args);
15031 }
15032 render() {
15033 if (this.notifyPlugins('beforeRender', {
15034 cancelable: true
15035 }) === false) {
15036 return;
15037 }
15038 if (animator.has(this)) {
15039 if (this.attached && !animator.running(this)) {
15040 animator.start(this);
15041 }
15042 } else {
15043 this.draw();
15044 onAnimationsComplete({
15045 chart: this
15046 });
15047 }
15048 }
15049 draw() {
15050 let i;
15051 if (this._resizeBeforeDraw) {
15052 const { width , height } = this._resizeBeforeDraw;
15053 this._resizeBeforeDraw = null;
15054 this._resize(width, height);
15055 }
15056 this.clear();
15057 if (this.width <= 0 || this.height <= 0) {
15058 return;
15059 }
15060 if (this.notifyPlugins('beforeDraw', {
15061 cancelable: true
15062 }) === false) {
15063 return;
15064 }
15065 const layers = this._layers;
15066 for(i = 0; i < layers.length && layers[i].z <= 0; ++i){
15067 layers[i].draw(this.chartArea);
15068 }
15069 this._drawDatasets();
15070 for(; i < layers.length; ++i){
15071 layers[i].draw(this.chartArea);
15072 }
15073 this.notifyPlugins('afterDraw');
15074 }
15075 _getSortedDatasetMetas(filterVisible) {
15076 const metasets = this._sortedMetasets;
15077 const result = [];
15078 let i, ilen;
15079 for(i = 0, ilen = metasets.length; i < ilen; ++i){
15080 const meta = metasets[i];
15081 if (!filterVisible || meta.visible) {
15082 result.push(meta);
15083 }
15084 }
15085 return result;
15086 }
15087 getSortedVisibleDatasetMetas() {
15088 return this._getSortedDatasetMetas(true);
15089 }
15090 _drawDatasets() {
15091 if (this.notifyPlugins('beforeDatasetsDraw', {
15092 cancelable: true
15093 }) === false) {
15094 return;
15095 }
15096 const metasets = this.getSortedVisibleDatasetMetas();
15097 for(let i = metasets.length - 1; i >= 0; --i){
15098 this._drawDataset(metasets[i]);
15099 }
15100 this.notifyPlugins('afterDatasetsDraw');
15101 }
15102 _drawDataset(meta) {
15103 const ctx = this.ctx;
15104 const args = {
15105 meta,
15106 index: meta.index,
15107 cancelable: true
15108 };
15109 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(this, meta);
15110 if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
15111 return;
15112 }
15113 if (clip) {
15114 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, clip);
15115 }
15116 meta.controller.draw();
15117 if (clip) {
15118 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
15119 }
15120 args.cancelable = false;
15121 this.notifyPlugins('afterDatasetDraw', args);
15122 }
15123 isPointInArea(point) {
15124 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(point, this.chartArea, this._minPadding);
15125 }
15126 getElementsAtEventForMode(e, mode, options, useFinalPosition) {
15127 const method = Interaction.modes[mode];
15128 if (typeof method === 'function') {
15129 return method(this, e, options, useFinalPosition);
15130 }
15131 return [];
15132 }
15133 getDatasetMeta(datasetIndex) {
15134 const dataset = this.data.datasets[datasetIndex];
15135 const metasets = this._metasets;
15136 let meta = metasets.filter((x)=>x && x._dataset === dataset).pop();
15137 if (!meta) {
15138 meta = {
15139 type: null,
15140 data: [],
15141 dataset: null,
15142 controller: null,
15143 hidden: null,
15144 xAxisID: null,
15145 yAxisID: null,
15146 order: dataset && dataset.order || 0,
15147 index: datasetIndex,
15148 _dataset: dataset,
15149 _parsed: [],
15150 _sorted: false
15151 };
15152 metasets.push(meta);
15153 }
15154 return meta;
15155 }
15156 getContext() {
15157 return this.$context || (this.$context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(null, {
15158 chart: this,
15159 type: 'chart'
15160 }));
15161 }
15162 getVisibleDatasetCount() {
15163 return this.getSortedVisibleDatasetMetas().length;
15164 }
15165 isDatasetVisible(datasetIndex) {
15166 const dataset = this.data.datasets[datasetIndex];
15167 if (!dataset) {
15168 return false;
15169 }
15170 const meta = this.getDatasetMeta(datasetIndex);
15171 return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
15172 }
15173 setDatasetVisibility(datasetIndex, visible) {
15174 const meta = this.getDatasetMeta(datasetIndex);
15175 meta.hidden = !visible;
15176 }
15177 toggleDataVisibility(index) {
15178 this._hiddenIndices[index] = !this._hiddenIndices[index];
15179 }
15180 getDataVisibility(index) {
15181 return !this._hiddenIndices[index];
15182 }
15183 _updateVisibility(datasetIndex, dataIndex, visible) {
15184 const mode = visible ? 'show' : 'hide';
15185 const meta = this.getDatasetMeta(datasetIndex);
15186 const anims = meta.controller._resolveAnimations(undefined, mode);
15187 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(dataIndex)) {
15188 meta.data[dataIndex].hidden = !visible;
15189 this.update();
15190 } else {
15191 this.setDatasetVisibility(datasetIndex, visible);
15192 anims.update(meta, {
15193 visible
15194 });
15195 this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined);
15196 }
15197 }
15198 hide(datasetIndex, dataIndex) {
15199 this._updateVisibility(datasetIndex, dataIndex, false);
15200 }
15201 show(datasetIndex, dataIndex) {
15202 this._updateVisibility(datasetIndex, dataIndex, true);
15203 }
15204 _destroyDatasetMeta(datasetIndex) {
15205 const meta = this._metasets[datasetIndex];
15206 if (meta && meta.controller) {
15207 meta.controller._destroy();
15208 }
15209 delete this._metasets[datasetIndex];
15210 }
15211 _stop() {
15212 let i, ilen;
15213 this.stop();
15214 animator.remove(this);
15215 for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15216 this._destroyDatasetMeta(i);
15217 }
15218 }
15219 destroy() {
15220 this.notifyPlugins('beforeDestroy');
15221 const { canvas , ctx } = this;
15222 this._stop();
15223 this.config.clearCache();
15224 if (canvas) {
15225 this.unbindEvents();
15226 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(canvas, ctx);
15227 this.platform.releaseContext(ctx);
15228 this.canvas = null;
15229 this.ctx = null;
15230 }
15231 delete instances[this.id];
15232 this.notifyPlugins('afterDestroy');
15233 }
15234 toBase64Image(...args) {
15235 return this.canvas.toDataURL(...args);
15236 }
15237 bindEvents() {
15238 this.bindUserEvents();
15239 if (this.options.responsive) {
15240 this.bindResponsiveEvents();
15241 } else {
15242 this.attached = true;
15243 }
15244 }
15245 bindUserEvents() {
15246 const listeners = this._listeners;
15247 const platform = this.platform;
15248 const _add = (type, listener)=>{
15249 platform.addEventListener(this, type, listener);
15250 listeners[type] = listener;
15251 };
15252 const listener = (e, x, y)=>{
15253 e.offsetX = x;
15254 e.offsetY = y;
15255 this._eventHandler(e);
15256 };
15257 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.options.events, (type)=>_add(type, listener));
15258 }
15259 bindResponsiveEvents() {
15260 if (!this._responsiveListeners) {
15261 this._responsiveListeners = {};
15262 }
15263 const listeners = this._responsiveListeners;
15264 const platform = this.platform;
15265 const _add = (type, listener)=>{
15266 platform.addEventListener(this, type, listener);
15267 listeners[type] = listener;
15268 };
15269 const _remove = (type, listener)=>{
15270 if (listeners[type]) {
15271 platform.removeEventListener(this, type, listener);
15272 delete listeners[type];
15273 }
15274 };
15275 const listener = (width, height)=>{
15276 if (this.canvas) {
15277 this.resize(width, height);
15278 }
15279 };
15280 let detached;
15281 const attached = ()=>{
15282 _remove('attach', attached);
15283 this.attached = true;
15284 this.resize();
15285 _add('resize', listener);
15286 _add('detach', detached);
15287 };
15288 detached = ()=>{
15289 this.attached = false;
15290 _remove('resize', listener);
15291 this._stop();
15292 this._resize(0, 0);
15293 _add('attach', attached);
15294 };
15295 if (platform.isAttached(this.canvas)) {
15296 attached();
15297 } else {
15298 detached();
15299 }
15300 }
15301 unbindEvents() {
15302 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._listeners, (listener, type)=>{
15303 this.platform.removeEventListener(this, type, listener);
15304 });
15305 this._listeners = {};
15306 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._responsiveListeners, (listener, type)=>{
15307 this.platform.removeEventListener(this, type, listener);
15308 });
15309 this._responsiveListeners = undefined;
15310 }
15311 updateHoverStyle(items, mode, enabled) {
15312 const prefix = enabled ? 'set' : 'remove';
15313 let meta, item, i, ilen;
15314 if (mode === 'dataset') {
15315 meta = this.getDatasetMeta(items[0].datasetIndex);
15316 meta.controller['_' + prefix + 'DatasetHoverStyle']();
15317 }
15318 for(i = 0, ilen = items.length; i < ilen; ++i){
15319 item = items[i];
15320 const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
15321 if (controller) {
15322 controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
15323 }
15324 }
15325 }
15326 getActiveElements() {
15327 return this._active || [];
15328 }
15329 setActiveElements(activeElements) {
15330 const lastActive = this._active || [];
15331 const active = activeElements.map(({ datasetIndex , index })=>{
15332 const meta = this.getDatasetMeta(datasetIndex);
15333 if (!meta) {
15334 throw new Error('No dataset found at index ' + datasetIndex);
15335 }
15336 return {
15337 datasetIndex,
15338 element: meta.data[index],
15339 index
15340 };
15341 });
15342 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15343 if (changed) {
15344 this._active = active;
15345 this._lastEvent = null;
15346 this._updateHoverStyles(active, lastActive);
15347 }
15348 }
15349 notifyPlugins(hook, args, filter) {
15350 return this._plugins.notify(this, hook, args, filter);
15351 }
15352 isPluginEnabled(pluginId) {
15353 return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1;
15354 }
15355 _updateHoverStyles(active, lastActive, replay) {
15356 const hoverOptions = this.options.hover;
15357 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index));
15358 const deactivated = diff(lastActive, active);
15359 const activated = replay ? active : diff(active, lastActive);
15360 if (deactivated.length) {
15361 this.updateHoverStyle(deactivated, hoverOptions.mode, false);
15362 }
15363 if (activated.length && hoverOptions.mode) {
15364 this.updateHoverStyle(activated, hoverOptions.mode, true);
15365 }
15366 }
15367 _eventHandler(e, replay) {
15368 const args = {
15369 event: e,
15370 replay,
15371 cancelable: true,
15372 inChartArea: this.isPointInArea(e)
15373 };
15374 const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type);
15375 if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
15376 return;
15377 }
15378 const changed = this._handleEvent(e, replay, args.inChartArea);
15379 args.cancelable = false;
15380 this.notifyPlugins('afterEvent', args, eventFilter);
15381 if (changed || args.changed) {
15382 this.render();
15383 }
15384 return this;
15385 }
15386 _handleEvent(e, replay, inChartArea) {
15387 const { _active: lastActive = [] , options } = this;
15388 const useFinalPosition = replay;
15389 const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
15390 const isClick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aj)(e);
15391 const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
15392 if (inChartArea) {
15393 this._lastEvent = null;
15394 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onHover, [
15395 e,
15396 active,
15397 this
15398 ], this);
15399 if (isClick) {
15400 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onClick, [
15401 e,
15402 active,
15403 this
15404 ], this);
15405 }
15406 }
15407 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15408 if (changed || replay) {
15409 this._active = active;
15410 this._updateHoverStyles(active, lastActive, replay);
15411 }
15412 this._lastEvent = lastEvent;
15413 return changed;
15414 }
15415 _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
15416 if (e.type === 'mouseout') {
15417 return [];
15418 }
15419 if (!inChartArea) {
15420 return lastActive;
15421 }
15422 const hoverOptions = this.options.hover;
15423 return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
15424 }
15425 }
15426 function invalidatePlugins() {
15427 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(Chart.instances, (chart)=>chart._plugins.invalidate());
15428 }
15429
15430 function clipSelf(ctx, element, endAngle) {
15431 const { startAngle , x , y , outerRadius , innerRadius , options } = element;
15432 const { borderWidth , borderJoinStyle } = options;
15433 const outerAngleClip = Math.min(borderWidth / outerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15434 ctx.beginPath();
15435 ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2);
15436 if (innerRadius > 0) {
15437 const innerAngleClip = Math.min(borderWidth / innerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15438 ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true);
15439 } else {
15440 const clipWidth = Math.min(borderWidth / 2, outerRadius * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15441 if (borderJoinStyle === 'round') {
15442 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);
15443 } else if (borderJoinStyle === 'bevel') {
15444 const r = 2 * clipWidth * clipWidth;
15445 const endX = -r * Math.cos(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15446 const endY = -r * Math.sin(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15447 const startX = r * Math.cos(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15448 const startY = r * Math.sin(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15449 ctx.lineTo(endX, endY);
15450 ctx.lineTo(startX, startY);
15451 }
15452 }
15453 ctx.closePath();
15454 ctx.moveTo(0, 0);
15455 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
15456 ctx.clip('evenodd');
15457 }
15458 function clipArc(ctx, element, endAngle) {
15459 const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element;
15460 let angleMargin = pixelMargin / outerRadius;
15461 // Draw an inner border by clipping the arc and drawing a double-width border
15462 // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
15463 ctx.beginPath();
15464 ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
15465 if (innerRadius > pixelMargin) {
15466 angleMargin = pixelMargin / innerRadius;
15467 ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
15468 } else {
15469 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);
15470 }
15471 ctx.closePath();
15472 ctx.clip();
15473 }
15474 function toRadiusCorners(value) {
15475 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.am)(value, [
15476 'outerStart',
15477 'outerEnd',
15478 'innerStart',
15479 'innerEnd'
15480 ]);
15481 }
15482 /**
15483 * Parse border radius from the provided options
15484 */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
15485 const o = toRadiusCorners(arc.options.borderRadius);
15486 const halfThickness = (outerRadius - innerRadius) / 2;
15487 const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
15488 // Outer limits are complicated. We want to compute the available angular distance at
15489 // a radius of outerRadius - borderRadius because for small angular distances, this term limits.
15490 // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners.
15491 //
15492 // If the borderRadius is large, that value can become negative.
15493 // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius
15494 // we know that the thickness term will dominate and compute the limits at that point
15495 const computeOuterLimit = (val)=>{
15496 const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
15497 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(val, 0, Math.min(halfThickness, outerArcLimit));
15498 };
15499 return {
15500 outerStart: computeOuterLimit(o.outerStart),
15501 outerEnd: computeOuterLimit(o.outerEnd),
15502 innerStart: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerStart, 0, innerLimit),
15503 innerEnd: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerEnd, 0, innerLimit)
15504 };
15505 }
15506 /**
15507 * Convert (r, 𝜃) to (x, y)
15508 */ function rThetaToXY(r, theta, x, y) {
15509 return {
15510 x: x + r * Math.cos(theta),
15511 y: y + r * Math.sin(theta)
15512 };
15513 }
15514 /**
15515 * Path the arc, respecting border radius by separating into left and right halves.
15516 *
15517 * Start End
15518 *
15519 * 1--->a--->2 Outer
15520 * / \
15521 * 8 3
15522 * | |
15523 * | |
15524 * 7 4
15525 * \ /
15526 * 6<---b<---5 Inner
15527 */ function pathArc(ctx, element, offset, spacing, end, circular) {
15528 const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element;
15529 const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
15530 const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
15531 let spacingOffset = 0;
15532 const alpha = end - start;
15533 if (spacing) {
15534 // When spacing is present, it is the same for all items
15535 // So we adjust the start and end angle of the arc such that
15536 // the distance is the same as it would be without the spacing
15537 const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
15538 const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
15539 const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
15540 const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha;
15541 spacingOffset = (alpha - adjustedAngle) / 2;
15542 }
15543 const beta = Math.max(0.001, alpha * outerRadius - offset / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P) / outerRadius;
15544 const angleOffset = (alpha - beta) / 2;
15545 const startAngle = start + angleOffset + spacingOffset;
15546 const endAngle = end - angleOffset - spacingOffset;
15547 const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
15548 const outerStartAdjustedRadius = outerRadius - outerStart;
15549 const outerEndAdjustedRadius = outerRadius - outerEnd;
15550 const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
15551 const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
15552 const innerStartAdjustedRadius = innerRadius + innerStart;
15553 const innerEndAdjustedRadius = innerRadius + innerEnd;
15554 const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
15555 const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
15556 ctx.beginPath();
15557 if (circular) {
15558 // The first arc segments from point 1 to point a to point 2
15559 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;
15560 ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);
15561 ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);
15562 // The corner segment from point 2 to point 3
15563 if (outerEnd > 0) {
15564 const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
15565 ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15566 }
15567 // The line from point 3 to point 4
15568 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
15569 ctx.lineTo(p4.x, p4.y);
15570 // The corner segment from point 4 to point 5
15571 if (innerEnd > 0) {
15572 const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
15573 ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, innerEndAdjustedAngle + Math.PI);
15574 }
15575 // The inner arc from point 5 to point b to point 6
15576 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;
15577 ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);
15578 ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);
15579 // The corner segment from point 6 to point 7
15580 if (innerStart > 0) {
15581 const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
15582 ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15583 }
15584 // The line from point 7 to point 8
15585 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
15586 ctx.lineTo(p8.x, p8.y);
15587 // The corner segment from point 8 to point 1
15588 if (outerStart > 0) {
15589 const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
15590 ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, outerStartAdjustedAngle);
15591 }
15592 } else {
15593 ctx.moveTo(x, y);
15594 const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;
15595 const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;
15596 ctx.lineTo(outerStartX, outerStartY);
15597 const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;
15598 const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;
15599 ctx.lineTo(outerEndX, outerEndY);
15600 }
15601 ctx.closePath();
15602 }
15603 function drawArc(ctx, element, offset, spacing, circular) {
15604 const { fullCircles , startAngle , circumference } = element;
15605 let endAngle = element.endAngle;
15606 if (fullCircles) {
15607 pathArc(ctx, element, offset, spacing, endAngle, circular);
15608 for(let i = 0; i < fullCircles; ++i){
15609 ctx.fill();
15610 }
15611 if (!isNaN(circumference)) {
15612 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15613 }
15614 }
15615 pathArc(ctx, element, offset, spacing, endAngle, circular);
15616 ctx.fill();
15617 return endAngle;
15618 }
15619 function drawBorder(ctx, element, offset, spacing, circular) {
15620 const { fullCircles , startAngle , circumference , options } = element;
15621 const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options;
15622 const inner = options.borderAlign === 'inner';
15623 if (!borderWidth) {
15624 return;
15625 }
15626 ctx.setLineDash(borderDash || []);
15627 ctx.lineDashOffset = borderDashOffset;
15628 if (inner) {
15629 ctx.lineWidth = borderWidth * 2;
15630 ctx.lineJoin = borderJoinStyle || 'round';
15631 } else {
15632 ctx.lineWidth = borderWidth;
15633 ctx.lineJoin = borderJoinStyle || 'bevel';
15634 }
15635 let endAngle = element.endAngle;
15636 if (fullCircles) {
15637 pathArc(ctx, element, offset, spacing, endAngle, circular);
15638 for(let i = 0; i < fullCircles; ++i){
15639 ctx.stroke();
15640 }
15641 if (!isNaN(circumference)) {
15642 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15643 }
15644 }
15645 if (inner) {
15646 clipArc(ctx, element, endAngle);
15647 }
15648 if (options.selfJoin && endAngle - startAngle >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P && borderRadius === 0 && borderJoinStyle !== 'miter') {
15649 clipSelf(ctx, element, endAngle);
15650 }
15651 if (!fullCircles) {
15652 pathArc(ctx, element, offset, spacing, endAngle, circular);
15653 ctx.stroke();
15654 }
15655 }
15656 class ArcElement extends Element {
15657 static id = 'arc';
15658 static defaults = {
15659 borderAlign: 'center',
15660 borderColor: '#fff',
15661 borderDash: [],
15662 borderDashOffset: 0,
15663 borderJoinStyle: undefined,
15664 borderRadius: 0,
15665 borderWidth: 2,
15666 offset: 0,
15667 spacing: 0,
15668 angle: undefined,
15669 circular: true,
15670 selfJoin: false
15671 };
15672 static defaultRoutes = {
15673 backgroundColor: 'backgroundColor'
15674 };
15675 static descriptors = {
15676 _scriptable: true,
15677 _indexable: (name)=>name !== 'borderDash'
15678 };
15679 circumference;
15680 endAngle;
15681 fullCircles;
15682 innerRadius;
15683 outerRadius;
15684 pixelMargin;
15685 startAngle;
15686 constructor(cfg){
15687 super();
15688 this.options = undefined;
15689 this.circumference = undefined;
15690 this.startAngle = undefined;
15691 this.endAngle = undefined;
15692 this.innerRadius = undefined;
15693 this.outerRadius = undefined;
15694 this.pixelMargin = 0;
15695 this.fullCircles = 0;
15696 if (cfg) {
15697 Object.assign(this, cfg);
15698 }
15699 }
15700 inRange(chartX, chartY, useFinalPosition) {
15701 const point = this.getProps([
15702 'x',
15703 'y'
15704 ], useFinalPosition);
15705 const { angle , distance } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(point, {
15706 x: chartX,
15707 y: chartY
15708 });
15709 const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([
15710 'startAngle',
15711 'endAngle',
15712 'innerRadius',
15713 'outerRadius',
15714 'circumference'
15715 ], useFinalPosition);
15716 const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;
15717 const _circumference = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(circumference, endAngle - startAngle);
15718 const nonZeroBetween = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle) && startAngle !== endAngle;
15719 const betweenAngles = _circumference >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || nonZeroBetween;
15720 const withinRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(distance, innerRadius + rAdjust, outerRadius + rAdjust);
15721 return betweenAngles && withinRadius;
15722 }
15723 getCenterPoint(useFinalPosition) {
15724 const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([
15725 'x',
15726 'y',
15727 'startAngle',
15728 'endAngle',
15729 'innerRadius',
15730 'outerRadius'
15731 ], useFinalPosition);
15732 const { offset , spacing } = this.options;
15733 const halfAngle = (startAngle + endAngle) / 2;
15734 const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
15735 return {
15736 x: x + Math.cos(halfAngle) * halfRadius,
15737 y: y + Math.sin(halfAngle) * halfRadius
15738 };
15739 }
15740 tooltipPosition(useFinalPosition) {
15741 return this.getCenterPoint(useFinalPosition);
15742 }
15743 draw(ctx) {
15744 const { options , circumference } = this;
15745 const offset = (options.offset || 0) / 4;
15746 const spacing = (options.spacing || 0) / 2;
15747 const circular = options.circular;
15748 this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0;
15749 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;
15750 if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
15751 return;
15752 }
15753 ctx.save();
15754 const halfAngle = (this.startAngle + this.endAngle) / 2;
15755 ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
15756 const fix = 1 - Math.sin(Math.min(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, circumference || 0));
15757 const radiusOffset = offset * fix;
15758 ctx.fillStyle = options.backgroundColor;
15759 ctx.strokeStyle = options.borderColor;
15760 drawArc(ctx, this, radiusOffset, spacing, circular);
15761 drawBorder(ctx, this, radiusOffset, spacing, circular);
15762 ctx.restore();
15763 }
15764 }
15765
15766 function setStyle(ctx, options, style = options) {
15767 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderCapStyle, options.borderCapStyle);
15768 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDash, options.borderDash));
15769 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDashOffset, options.borderDashOffset);
15770 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderJoinStyle, options.borderJoinStyle);
15771 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderWidth, options.borderWidth);
15772 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderColor, options.borderColor);
15773 }
15774 function lineTo(ctx, previous, target) {
15775 ctx.lineTo(target.x, target.y);
15776 }
15777 function getLineMethod(options) {
15778 if (options.stepped) {
15779 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.at;
15780 }
15781 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15782 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.au;
15783 }
15784 return lineTo;
15785 }
15786 function pathVars(points, segment, params = {}) {
15787 const count = points.length;
15788 const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params;
15789 const { start: segmentStart , end: segmentEnd } = segment;
15790 const start = Math.max(paramsStart, segmentStart);
15791 const end = Math.min(paramsEnd, segmentEnd);
15792 const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;
15793 return {
15794 count,
15795 start,
15796 loop: segment.loop,
15797 ilen: end < start && !outside ? count + end - start : end - start
15798 };
15799 }
15800 function pathSegment(ctx, line, segment, params) {
15801 const { points , options } = line;
15802 const { count , start , loop , ilen } = pathVars(points, segment, params);
15803 const lineMethod = getLineMethod(options);
15804 let { move =true , reverse } = params || {};
15805 let i, point, prev;
15806 for(i = 0; i <= ilen; ++i){
15807 point = points[(start + (reverse ? ilen - i : i)) % count];
15808 if (point.skip) {
15809 continue;
15810 } else if (move) {
15811 ctx.moveTo(point.x, point.y);
15812 move = false;
15813 } else {
15814 lineMethod(ctx, prev, point, reverse, options.stepped);
15815 }
15816 prev = point;
15817 }
15818 if (loop) {
15819 point = points[(start + (reverse ? ilen : 0)) % count];
15820 lineMethod(ctx, prev, point, reverse, options.stepped);
15821 }
15822 return !!loop;
15823 }
15824 function fastPathSegment(ctx, line, segment, params) {
15825 const points = line.points;
15826 const { count , start , ilen } = pathVars(points, segment, params);
15827 const { move =true , reverse } = params || {};
15828 let avgX = 0;
15829 let countX = 0;
15830 let i, point, prevX, minY, maxY, lastY;
15831 const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count;
15832 const drawX = ()=>{
15833 if (minY !== maxY) {
15834 ctx.lineTo(avgX, maxY);
15835 ctx.lineTo(avgX, minY);
15836 ctx.lineTo(avgX, lastY);
15837 }
15838 };
15839 if (move) {
15840 point = points[pointIndex(0)];
15841 ctx.moveTo(point.x, point.y);
15842 }
15843 for(i = 0; i <= ilen; ++i){
15844 point = points[pointIndex(i)];
15845 if (point.skip) {
15846 continue;
15847 }
15848 const x = point.x;
15849 const y = point.y;
15850 const truncX = x | 0;
15851 if (truncX === prevX) {
15852 if (y < minY) {
15853 minY = y;
15854 } else if (y > maxY) {
15855 maxY = y;
15856 }
15857 avgX = (countX * avgX + x) / ++countX;
15858 } else {
15859 drawX();
15860 ctx.lineTo(x, y);
15861 prevX = truncX;
15862 countX = 0;
15863 minY = maxY = y;
15864 }
15865 lastY = y;
15866 }
15867 drawX();
15868 }
15869 function _getSegmentMethod(line) {
15870 const opts = line.options;
15871 const borderDash = opts.borderDash && opts.borderDash.length;
15872 const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;
15873 return useFastPath ? fastPathSegment : pathSegment;
15874 }
15875 function _getInterpolationMethod(options) {
15876 if (options.stepped) {
15877 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aq;
15878 }
15879 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15880 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ar;
15881 }
15882 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.as;
15883 }
15884 function strokePathWithCache(ctx, line, start, count) {
15885 let path = line._path;
15886 if (!path) {
15887 path = line._path = new Path2D();
15888 if (line.path(path, start, count)) {
15889 path.closePath();
15890 }
15891 }
15892 setStyle(ctx, line.options);
15893 ctx.stroke(path);
15894 }
15895 function strokePathDirect(ctx, line, start, count) {
15896 const { segments , options } = line;
15897 const segmentMethod = _getSegmentMethod(line);
15898 for (const segment of segments){
15899 setStyle(ctx, options, segment.style);
15900 ctx.beginPath();
15901 if (segmentMethod(ctx, line, segment, {
15902 start,
15903 end: start + count - 1
15904 })) {
15905 ctx.closePath();
15906 }
15907 ctx.stroke();
15908 }
15909 }
15910 const usePath2D = typeof Path2D === 'function';
15911 function draw(ctx, line, start, count) {
15912 if (usePath2D && !line.options.segment) {
15913 strokePathWithCache(ctx, line, start, count);
15914 } else {
15915 strokePathDirect(ctx, line, start, count);
15916 }
15917 }
15918 class LineElement extends Element {
15919 static id = 'line';
15920 static defaults = {
15921 borderCapStyle: 'butt',
15922 borderDash: [],
15923 borderDashOffset: 0,
15924 borderJoinStyle: 'miter',
15925 borderWidth: 3,
15926 capBezierPoints: true,
15927 cubicInterpolationMode: 'default',
15928 fill: false,
15929 spanGaps: false,
15930 stepped: false,
15931 tension: 0
15932 };
15933 static defaultRoutes = {
15934 backgroundColor: 'backgroundColor',
15935 borderColor: 'borderColor'
15936 };
15937 static descriptors = {
15938 _scriptable: true,
15939 _indexable: (name)=>name !== 'borderDash' && name !== 'fill'
15940 };
15941 constructor(cfg){
15942 super();
15943 this.animated = true;
15944 this.options = undefined;
15945 this._chart = undefined;
15946 this._loop = undefined;
15947 this._fullLoop = undefined;
15948 this._path = undefined;
15949 this._points = undefined;
15950 this._segments = undefined;
15951 this._decimated = false;
15952 this._pointsUpdated = false;
15953 this._datasetIndex = undefined;
15954 if (cfg) {
15955 Object.assign(this, cfg);
15956 }
15957 }
15958 updateControlPoints(chartArea, indexAxis) {
15959 const options = this.options;
15960 if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {
15961 const loop = options.spanGaps ? this._loop : this._fullLoop;
15962 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.an)(this._points, options, chartArea, loop, indexAxis);
15963 this._pointsUpdated = true;
15964 }
15965 }
15966 set points(points) {
15967 this._points = points;
15968 delete this._segments;
15969 delete this._path;
15970 this._pointsUpdated = false;
15971 }
15972 get points() {
15973 return this._points;
15974 }
15975 get segments() {
15976 return this._segments || (this._segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ao)(this, this.options.segment));
15977 }
15978 first() {
15979 const segments = this.segments;
15980 const points = this.points;
15981 return segments.length && points[segments[0].start];
15982 }
15983 last() {
15984 const segments = this.segments;
15985 const points = this.points;
15986 const count = segments.length;
15987 return count && points[segments[count - 1].end];
15988 }
15989 interpolate(point, property) {
15990 const options = this.options;
15991 const value = point[property];
15992 const points = this.points;
15993 const segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(this, {
15994 property,
15995 start: value,
15996 end: value
15997 });
15998 if (!segments.length) {
15999 return;
16000 }
16001 const result = [];
16002 const _interpolate = _getInterpolationMethod(options);
16003 let i, ilen;
16004 for(i = 0, ilen = segments.length; i < ilen; ++i){
16005 const { start , end } = segments[i];
16006 const p1 = points[start];
16007 const p2 = points[end];
16008 if (p1 === p2) {
16009 result.push(p1);
16010 continue;
16011 }
16012 const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
16013 const interpolated = _interpolate(p1, p2, t, options.stepped);
16014 interpolated[property] = point[property];
16015 result.push(interpolated);
16016 }
16017 return result.length === 1 ? result[0] : result;
16018 }
16019 pathSegment(ctx, segment, params) {
16020 const segmentMethod = _getSegmentMethod(this);
16021 return segmentMethod(ctx, this, segment, params);
16022 }
16023 path(ctx, start, count) {
16024 const segments = this.segments;
16025 const segmentMethod = _getSegmentMethod(this);
16026 let loop = this._loop;
16027 start = start || 0;
16028 count = count || this.points.length - start;
16029 for (const segment of segments){
16030 loop &= segmentMethod(ctx, this, segment, {
16031 start,
16032 end: start + count - 1
16033 });
16034 }
16035 return !!loop;
16036 }
16037 draw(ctx, chartArea, start, count) {
16038 const options = this.options || {};
16039 const points = this.points || [];
16040 if (points.length && options.borderWidth) {
16041 ctx.save();
16042 draw(ctx, this, start, count);
16043 ctx.restore();
16044 }
16045 if (this.animated) {
16046 this._pointsUpdated = false;
16047 this._path = undefined;
16048 }
16049 }
16050 }
16051
16052 function inRange$1(el, pos, axis, useFinalPosition) {
16053 const options = el.options;
16054 const { [axis]: value } = el.getProps([
16055 axis
16056 ], useFinalPosition);
16057 return Math.abs(pos - value) < options.radius + options.hitRadius;
16058 }
16059 class PointElement extends Element {
16060 static id = 'point';
16061 parsed;
16062 skip;
16063 stop;
16064 /**
16065 * @type {any}
16066 */ static defaults = {
16067 borderWidth: 1,
16068 hitRadius: 1,
16069 hoverBorderWidth: 1,
16070 hoverRadius: 4,
16071 pointStyle: 'circle',
16072 radius: 3,
16073 rotation: 0
16074 };
16075 /**
16076 * @type {any}
16077 */ static defaultRoutes = {
16078 backgroundColor: 'backgroundColor',
16079 borderColor: 'borderColor'
16080 };
16081 constructor(cfg){
16082 super();
16083 this.options = undefined;
16084 this.parsed = undefined;
16085 this.skip = undefined;
16086 this.stop = undefined;
16087 if (cfg) {
16088 Object.assign(this, cfg);
16089 }
16090 }
16091 inRange(mouseX, mouseY, useFinalPosition) {
16092 const options = this.options;
16093 const { x , y } = this.getProps([
16094 'x',
16095 'y'
16096 ], useFinalPosition);
16097 return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2);
16098 }
16099 inXRange(mouseX, useFinalPosition) {
16100 return inRange$1(this, mouseX, 'x', useFinalPosition);
16101 }
16102 inYRange(mouseY, useFinalPosition) {
16103 return inRange$1(this, mouseY, 'y', useFinalPosition);
16104 }
16105 getCenterPoint(useFinalPosition) {
16106 const { x , y } = this.getProps([
16107 'x',
16108 'y'
16109 ], useFinalPosition);
16110 return {
16111 x,
16112 y
16113 };
16114 }
16115 size(options) {
16116 options = options || this.options || {};
16117 let radius = options.radius || 0;
16118 radius = Math.max(radius, radius && options.hoverRadius || 0);
16119 const borderWidth = radius && options.borderWidth || 0;
16120 return (radius + borderWidth) * 2;
16121 }
16122 draw(ctx, area) {
16123 const options = this.options;
16124 if (this.skip || options.radius < 0.1 || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(this, area, this.size(options) / 2)) {
16125 return;
16126 }
16127 ctx.strokeStyle = options.borderColor;
16128 ctx.lineWidth = options.borderWidth;
16129 ctx.fillStyle = options.backgroundColor;
16130 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, options, this.x, this.y);
16131 }
16132 getRange() {
16133 const options = this.options || {};
16134 // @ts-expect-error Fallbacks should never be hit in practice
16135 return options.radius + options.hitRadius;
16136 }
16137 }
16138
16139 function getBarBounds(bar, useFinalPosition) {
16140 const { x , y , base , width , height } = bar.getProps([
16141 'x',
16142 'y',
16143 'base',
16144 'width',
16145 'height'
16146 ], useFinalPosition);
16147 let left, right, top, bottom, half;
16148 if (bar.horizontal) {
16149 half = height / 2;
16150 left = Math.min(x, base);
16151 right = Math.max(x, base);
16152 top = y - half;
16153 bottom = y + half;
16154 } else {
16155 half = width / 2;
16156 left = x - half;
16157 right = x + half;
16158 top = Math.min(y, base);
16159 bottom = Math.max(y, base);
16160 }
16161 return {
16162 left,
16163 top,
16164 right,
16165 bottom
16166 };
16167 }
16168 function skipOrLimit(skip, value, min, max) {
16169 return skip ? 0 : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(value, min, max);
16170 }
16171 function parseBorderWidth(bar, maxW, maxH) {
16172 const value = bar.options.borderWidth;
16173 const skip = bar.borderSkipped;
16174 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ax)(value);
16175 return {
16176 t: skipOrLimit(skip.top, o.top, 0, maxH),
16177 r: skipOrLimit(skip.right, o.right, 0, maxW),
16178 b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
16179 l: skipOrLimit(skip.left, o.left, 0, maxW)
16180 };
16181 }
16182 function parseBorderRadius(bar, maxW, maxH) {
16183 const { enableBorderRadius } = bar.getProps([
16184 'enableBorderRadius'
16185 ]);
16186 const value = bar.options.borderRadius;
16187 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(value);
16188 const maxR = Math.min(maxW, maxH);
16189 const skip = bar.borderSkipped;
16190 const enableBorder = enableBorderRadius || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value);
16191 return {
16192 topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
16193 topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
16194 bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
16195 bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
16196 };
16197 }
16198 function boundingRects(bar) {
16199 const bounds = getBarBounds(bar);
16200 const width = bounds.right - bounds.left;
16201 const height = bounds.bottom - bounds.top;
16202 const border = parseBorderWidth(bar, width / 2, height / 2);
16203 const radius = parseBorderRadius(bar, width / 2, height / 2);
16204 return {
16205 outer: {
16206 x: bounds.left,
16207 y: bounds.top,
16208 w: width,
16209 h: height,
16210 radius
16211 },
16212 inner: {
16213 x: bounds.left + border.l,
16214 y: bounds.top + border.t,
16215 w: width - border.l - border.r,
16216 h: height - border.t - border.b,
16217 radius: {
16218 topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
16219 topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
16220 bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
16221 bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))
16222 }
16223 }
16224 };
16225 }
16226 function inRange(bar, x, y, useFinalPosition) {
16227 const skipX = x === null;
16228 const skipY = y === null;
16229 const skipBoth = skipX && skipY;
16230 const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
16231 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));
16232 }
16233 function hasRadius(radius) {
16234 return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
16235 }
16236 function addNormalRectPath(ctx, rect) {
16237 ctx.rect(rect.x, rect.y, rect.w, rect.h);
16238 }
16239 function inflateRect(rect, amount, refRect = {}) {
16240 const x = rect.x !== refRect.x ? -amount : 0;
16241 const y = rect.y !== refRect.y ? -amount : 0;
16242 const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;
16243 const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;
16244 return {
16245 x: rect.x + x,
16246 y: rect.y + y,
16247 w: rect.w + w,
16248 h: rect.h + h,
16249 radius: rect.radius
16250 };
16251 }
16252 class BarElement extends Element {
16253 static id = 'bar';
16254 static defaults = {
16255 borderSkipped: 'start',
16256 borderWidth: 0,
16257 borderRadius: 0,
16258 inflateAmount: 'auto',
16259 pointStyle: undefined
16260 };
16261 static defaultRoutes = {
16262 backgroundColor: 'backgroundColor',
16263 borderColor: 'borderColor'
16264 };
16265 constructor(cfg){
16266 super();
16267 this.options = undefined;
16268 this.horizontal = undefined;
16269 this.base = undefined;
16270 this.width = undefined;
16271 this.height = undefined;
16272 this.inflateAmount = undefined;
16273 if (cfg) {
16274 Object.assign(this, cfg);
16275 }
16276 }
16277 draw(ctx) {
16278 const { inflateAmount , options: { borderColor , backgroundColor } } = this;
16279 const { inner , outer } = boundingRects(this);
16280 const addRectPath = hasRadius(outer.radius) ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw : addNormalRectPath;
16281 ctx.save();
16282 if (outer.w !== inner.w || outer.h !== inner.h) {
16283 ctx.beginPath();
16284 addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
16285 ctx.clip();
16286 addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
16287 ctx.fillStyle = borderColor;
16288 ctx.fill('evenodd');
16289 }
16290 ctx.beginPath();
16291 addRectPath(ctx, inflateRect(inner, inflateAmount));
16292 ctx.fillStyle = backgroundColor;
16293 ctx.fill();
16294 ctx.restore();
16295 }
16296 inRange(mouseX, mouseY, useFinalPosition) {
16297 return inRange(this, mouseX, mouseY, useFinalPosition);
16298 }
16299 inXRange(mouseX, useFinalPosition) {
16300 return inRange(this, mouseX, null, useFinalPosition);
16301 }
16302 inYRange(mouseY, useFinalPosition) {
16303 return inRange(this, null, mouseY, useFinalPosition);
16304 }
16305 getCenterPoint(useFinalPosition) {
16306 const { x , y , base , horizontal } = this.getProps([
16307 'x',
16308 'y',
16309 'base',
16310 'horizontal'
16311 ], useFinalPosition);
16312 return {
16313 x: horizontal ? (x + base) / 2 : x,
16314 y: horizontal ? y : (y + base) / 2
16315 };
16316 }
16317 getRange(axis) {
16318 return axis === 'x' ? this.width / 2 : this.height / 2;
16319 }
16320 }
16321
16322 var elements = /*#__PURE__*/Object.freeze({
16323 __proto__: null,
16324 ArcElement: ArcElement,
16325 BarElement: BarElement,
16326 LineElement: LineElement,
16327 PointElement: PointElement
16328 });
16329
16330 const BORDER_COLORS = [
16331 'rgb(54, 162, 235)',
16332 'rgb(255, 99, 132)',
16333 'rgb(255, 159, 64)',
16334 'rgb(255, 205, 86)',
16335 'rgb(75, 192, 192)',
16336 'rgb(153, 102, 255)',
16337 'rgb(201, 203, 207)' // grey
16338 ];
16339 // Border colors with 50% transparency
16340 const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)'));
16341 function getBorderColor(i) {
16342 return BORDER_COLORS[i % BORDER_COLORS.length];
16343 }
16344 function getBackgroundColor(i) {
16345 return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length];
16346 }
16347 function colorizeDefaultDataset(dataset, i) {
16348 dataset.borderColor = getBorderColor(i);
16349 dataset.backgroundColor = getBackgroundColor(i);
16350 return ++i;
16351 }
16352 function colorizeDoughnutDataset(dataset, i) {
16353 dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++));
16354 return i;
16355 }
16356 function colorizePolarAreaDataset(dataset, i) {
16357 dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++));
16358 return i;
16359 }
16360 function getColorizer(chart) {
16361 let i = 0;
16362 return (dataset, datasetIndex)=>{
16363 const controller = chart.getDatasetMeta(datasetIndex).controller;
16364 if (controller instanceof DoughnutController) {
16365 i = colorizeDoughnutDataset(dataset, i);
16366 } else if (controller instanceof PolarAreaController) {
16367 i = colorizePolarAreaDataset(dataset, i);
16368 } else if (controller) {
16369 i = colorizeDefaultDataset(dataset, i);
16370 }
16371 };
16372 }
16373 function containsColorsDefinitions(descriptors) {
16374 let k;
16375 for(k in descriptors){
16376 if (descriptors[k].borderColor || descriptors[k].backgroundColor) {
16377 return true;
16378 }
16379 }
16380 return false;
16381 }
16382 function containsColorsDefinition(descriptor) {
16383 return descriptor && (descriptor.borderColor || descriptor.backgroundColor);
16384 }
16385 function containsDefaultColorsDefenitions() {
16386 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)';
16387 }
16388 var plugin_colors = {
16389 id: 'colors',
16390 defaults: {
16391 enabled: true,
16392 forceOverride: false
16393 },
16394 beforeLayout (chart, _args, options) {
16395 if (!options.enabled) {
16396 return;
16397 }
16398 const { data: { datasets } , options: chartOptions } = chart.config;
16399 const { elements } = chartOptions;
16400 const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions();
16401 if (!options.forceOverride && containsColorDefenition) {
16402 return;
16403 }
16404 const colorizer = getColorizer(chart);
16405 datasets.forEach(colorizer);
16406 }
16407 };
16408
16409 function lttbDecimation(data, start, count, availableWidth, options) {
16410 const samples = options.samples || availableWidth;
16411 if (samples >= count) {
16412 return data.slice(start, start + count);
16413 }
16414 const decimated = [];
16415 const bucketWidth = (count - 2) / (samples - 2);
16416 let sampledIndex = 0;
16417 const endIndex = start + count - 1;
16418 let a = start;
16419 let i, maxAreaPoint, maxArea, area, nextA;
16420 decimated[sampledIndex++] = data[a];
16421 for(i = 0; i < samples - 2; i++){
16422 let avgX = 0;
16423 let avgY = 0;
16424 let j;
16425 const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;
16426 const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;
16427 const avgRangeLength = avgRangeEnd - avgRangeStart;
16428 for(j = avgRangeStart; j < avgRangeEnd; j++){
16429 avgX += data[j].x;
16430 avgY += data[j].y;
16431 }
16432 avgX /= avgRangeLength;
16433 avgY /= avgRangeLength;
16434 const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;
16435 const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;
16436 const { x: pointAx , y: pointAy } = data[a];
16437 maxArea = area = -1;
16438 for(j = rangeOffs; j < rangeTo; j++){
16439 area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy));
16440 if (area > maxArea) {
16441 maxArea = area;
16442 maxAreaPoint = data[j];
16443 nextA = j;
16444 }
16445 }
16446 decimated[sampledIndex++] = maxAreaPoint;
16447 a = nextA;
16448 }
16449 decimated[sampledIndex++] = data[endIndex];
16450 return decimated;
16451 }
16452 function minMaxDecimation(data, start, count, availableWidth) {
16453 let avgX = 0;
16454 let countX = 0;
16455 let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
16456 const decimated = [];
16457 const endIndex = start + count - 1;
16458 const xMin = data[start].x;
16459 const xMax = data[endIndex].x;
16460 const dx = xMax - xMin;
16461 for(i = start; i < start + count; ++i){
16462 point = data[i];
16463 x = (point.x - xMin) / dx * availableWidth;
16464 y = point.y;
16465 const truncX = x | 0;
16466 if (truncX === prevX) {
16467 if (y < minY) {
16468 minY = y;
16469 minIndex = i;
16470 } else if (y > maxY) {
16471 maxY = y;
16472 maxIndex = i;
16473 }
16474 avgX = (countX * avgX + point.x) / ++countX;
16475 } else {
16476 const lastIndex = i - 1;
16477 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(minIndex) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(maxIndex)) {
16478 const intermediateIndex1 = Math.min(minIndex, maxIndex);
16479 const intermediateIndex2 = Math.max(minIndex, maxIndex);
16480 if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
16481 decimated.push({
16482 ...data[intermediateIndex1],
16483 x: avgX
16484 });
16485 }
16486 if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
16487 decimated.push({
16488 ...data[intermediateIndex2],
16489 x: avgX
16490 });
16491 }
16492 }
16493 if (i > 0 && lastIndex !== startIndex) {
16494 decimated.push(data[lastIndex]);
16495 }
16496 decimated.push(point);
16497 prevX = truncX;
16498 countX = 0;
16499 minY = maxY = y;
16500 minIndex = maxIndex = startIndex = i;
16501 }
16502 }
16503 return decimated;
16504 }
16505 function cleanDecimatedDataset(dataset) {
16506 if (dataset._decimated) {
16507 const data = dataset._data;
16508 delete dataset._decimated;
16509 delete dataset._data;
16510 Object.defineProperty(dataset, 'data', {
16511 configurable: true,
16512 enumerable: true,
16513 writable: true,
16514 value: data
16515 });
16516 }
16517 }
16518 function cleanDecimatedData(chart) {
16519 chart.data.datasets.forEach((dataset)=>{
16520 cleanDecimatedDataset(dataset);
16521 });
16522 }
16523 function getStartAndCountOfVisiblePointsSimplified(meta, points) {
16524 const pointCount = points.length;
16525 let start = 0;
16526 let count;
16527 const { iScale } = meta;
16528 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
16529 if (minDefined) {
16530 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);
16531 }
16532 if (maxDefined) {
16533 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;
16534 } else {
16535 count = pointCount - start;
16536 }
16537 return {
16538 start,
16539 count
16540 };
16541 }
16542 var plugin_decimation = {
16543 id: 'decimation',
16544 defaults: {
16545 algorithm: 'min-max',
16546 enabled: false
16547 },
16548 beforeElementsUpdate: (chart, args, options)=>{
16549 if (!options.enabled) {
16550 cleanDecimatedData(chart);
16551 return;
16552 }
16553 const availableWidth = chart.width;
16554 chart.data.datasets.forEach((dataset, datasetIndex)=>{
16555 const { _data , indexAxis } = dataset;
16556 const meta = chart.getDatasetMeta(datasetIndex);
16557 const data = _data || dataset.data;
16558 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
16559 indexAxis,
16560 chart.options.indexAxis
16561 ]) === 'y') {
16562 return;
16563 }
16564 if (!meta.controller.supportsDecimation) {
16565 return;
16566 }
16567 const xAxis = chart.scales[meta.xAxisID];
16568 if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
16569 return;
16570 }
16571 if (chart.options.parsing) {
16572 return;
16573 }
16574 let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data);
16575 const threshold = options.threshold || 4 * availableWidth;
16576 if (count <= threshold) {
16577 cleanDecimatedDataset(dataset);
16578 return;
16579 }
16580 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(_data)) {
16581 dataset._data = data;
16582 delete dataset.data;
16583 Object.defineProperty(dataset, 'data', {
16584 configurable: true,
16585 enumerable: true,
16586 get: function() {
16587 return this._decimated;
16588 },
16589 set: function(d) {
16590 this._data = d;
16591 }
16592 });
16593 }
16594 let decimated;
16595 switch(options.algorithm){
16596 case 'lttb':
16597 decimated = lttbDecimation(data, start, count, availableWidth, options);
16598 break;
16599 case 'min-max':
16600 decimated = minMaxDecimation(data, start, count, availableWidth);
16601 break;
16602 default:
16603 throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
16604 }
16605 dataset._decimated = decimated;
16606 });
16607 },
16608 destroy (chart) {
16609 cleanDecimatedData(chart);
16610 }
16611 };
16612
16613 function _segments(line, target, property) {
16614 const segments = line.segments;
16615 const points = line.points;
16616 const tpoints = target.points;
16617 const parts = [];
16618 for (const segment of segments){
16619 let { start , end } = segment;
16620 end = _findSegmentEnd(start, end, points);
16621 const bounds = _getBounds(property, points[start], points[end], segment.loop);
16622 if (!target.segments) {
16623 parts.push({
16624 source: segment,
16625 target: bounds,
16626 start: points[start],
16627 end: points[end]
16628 });
16629 continue;
16630 }
16631 const targetSegments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(target, bounds);
16632 for (const tgt of targetSegments){
16633 const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);
16634 const fillSources = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.az)(segment, points, subBounds);
16635 for (const fillSource of fillSources){
16636 parts.push({
16637 source: fillSource,
16638 target: tgt,
16639 start: {
16640 [property]: _getEdge(bounds, subBounds, 'start', Math.max)
16641 },
16642 end: {
16643 [property]: _getEdge(bounds, subBounds, 'end', Math.min)
16644 }
16645 });
16646 }
16647 }
16648 }
16649 return parts;
16650 }
16651 function _getBounds(property, first, last, loop) {
16652 if (loop) {
16653 return;
16654 }
16655 let start = first[property];
16656 let end = last[property];
16657 if (property === 'angle') {
16658 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(start);
16659 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(end);
16660 }
16661 return {
16662 property,
16663 start,
16664 end
16665 };
16666 }
16667 function _pointsFromSegments(boundary, line) {
16668 const { x =null , y =null } = boundary || {};
16669 const linePoints = line.points;
16670 const points = [];
16671 line.segments.forEach(({ start , end })=>{
16672 end = _findSegmentEnd(start, end, linePoints);
16673 const first = linePoints[start];
16674 const last = linePoints[end];
16675 if (y !== null) {
16676 points.push({
16677 x: first.x,
16678 y
16679 });
16680 points.push({
16681 x: last.x,
16682 y
16683 });
16684 } else if (x !== null) {
16685 points.push({
16686 x,
16687 y: first.y
16688 });
16689 points.push({
16690 x,
16691 y: last.y
16692 });
16693 }
16694 });
16695 return points;
16696 }
16697 function _findSegmentEnd(start, end, points) {
16698 for(; end > start; end--){
16699 const point = points[end];
16700 if (!isNaN(point.x) && !isNaN(point.y)) {
16701 break;
16702 }
16703 }
16704 return end;
16705 }
16706 function _getEdge(a, b, prop, fn) {
16707 if (a && b) {
16708 return fn(a[prop], b[prop]);
16709 }
16710 return a ? a[prop] : b ? b[prop] : 0;
16711 }
16712
16713 function _createBoundaryLine(boundary, line) {
16714 let points = [];
16715 let _loop = false;
16716 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(boundary)) {
16717 _loop = true;
16718 points = boundary;
16719 } else {
16720 points = _pointsFromSegments(boundary, line);
16721 }
16722 return points.length ? new LineElement({
16723 points,
16724 options: {
16725 tension: 0
16726 },
16727 _loop,
16728 _fullLoop: _loop
16729 }) : null;
16730 }
16731 function _shouldApplyFill(source) {
16732 return source && source.fill !== false;
16733 }
16734
16735 function _resolveTarget(sources, index, propagate) {
16736 const source = sources[index];
16737 let fill = source.fill;
16738 const visited = [
16739 index
16740 ];
16741 let target;
16742 if (!propagate) {
16743 return fill;
16744 }
16745 while(fill !== false && visited.indexOf(fill) === -1){
16746 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16747 return fill;
16748 }
16749 target = sources[fill];
16750 if (!target) {
16751 return false;
16752 }
16753 if (target.visible) {
16754 return fill;
16755 }
16756 visited.push(fill);
16757 fill = target.fill;
16758 }
16759 return false;
16760 }
16761 function _decodeFill(line, index, count) {
16762 const fill = parseFillOption(line);
16763 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16764 return isNaN(fill.value) ? false : fill;
16765 }
16766 let target = parseFloat(fill);
16767 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(target) && Math.floor(target) === target) {
16768 return decodeTargetIndex(fill[0], index, target, count);
16769 }
16770 return [
16771 'origin',
16772 'start',
16773 'end',
16774 'stack',
16775 'shape'
16776 ].indexOf(fill) >= 0 && fill;
16777 }
16778 function decodeTargetIndex(firstCh, index, target, count) {
16779 if (firstCh === '-' || firstCh === '+') {
16780 target = index + target;
16781 }
16782 if (target === index || target < 0 || target >= count) {
16783 return false;
16784 }
16785 return target;
16786 }
16787 function _getTargetPixel(fill, scale) {
16788 let pixel = null;
16789 if (fill === 'start') {
16790 pixel = scale.bottom;
16791 } else if (fill === 'end') {
16792 pixel = scale.top;
16793 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16794 pixel = scale.getPixelForValue(fill.value);
16795 } else if (scale.getBasePixel) {
16796 pixel = scale.getBasePixel();
16797 }
16798 return pixel;
16799 }
16800 function _getTargetValue(fill, scale, startValue) {
16801 let value;
16802 if (fill === 'start') {
16803 value = startValue;
16804 } else if (fill === 'end') {
16805 value = scale.options.reverse ? scale.min : scale.max;
16806 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16807 value = fill.value;
16808 } else {
16809 value = scale.getBaseValue();
16810 }
16811 return value;
16812 }
16813 function parseFillOption(line) {
16814 const options = line.options;
16815 const fillOption = options.fill;
16816 let fill = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(fillOption && fillOption.target, fillOption);
16817 if (fill === undefined) {
16818 fill = !!options.backgroundColor;
16819 }
16820 if (fill === false || fill === null) {
16821 return false;
16822 }
16823 if (fill === true) {
16824 return 'origin';
16825 }
16826 return fill;
16827 }
16828
16829 function _buildStackLine(source) {
16830 const { scale , index , line } = source;
16831 const points = [];
16832 const segments = line.segments;
16833 const sourcePoints = line.points;
16834 const linesBelow = getLinesBelow(scale, index);
16835 linesBelow.push(_createBoundaryLine({
16836 x: null,
16837 y: scale.bottom
16838 }, line));
16839 for(let i = 0; i < segments.length; i++){
16840 const segment = segments[i];
16841 for(let j = segment.start; j <= segment.end; j++){
16842 addPointsBelow(points, sourcePoints[j], linesBelow);
16843 }
16844 }
16845 return new LineElement({
16846 points,
16847 options: {}
16848 });
16849 }
16850 function getLinesBelow(scale, index) {
16851 const below = [];
16852 const metas = scale.getMatchingVisibleMetas('line');
16853 for(let i = 0; i < metas.length; i++){
16854 const meta = metas[i];
16855 if (meta.index === index) {
16856 break;
16857 }
16858 if (!meta.hidden) {
16859 below.unshift(meta.dataset);
16860 }
16861 }
16862 return below;
16863 }
16864 function addPointsBelow(points, sourcePoint, linesBelow) {
16865 const postponed = [];
16866 for(let j = 0; j < linesBelow.length; j++){
16867 const line = linesBelow[j];
16868 const { first , last , point } = findPoint(line, sourcePoint, 'x');
16869 if (!point || first && last) {
16870 continue;
16871 }
16872 if (first) {
16873 postponed.unshift(point);
16874 } else {
16875 points.push(point);
16876 if (!last) {
16877 break;
16878 }
16879 }
16880 }
16881 points.push(...postponed);
16882 }
16883 function findPoint(line, sourcePoint, property) {
16884 const point = line.interpolate(sourcePoint, property);
16885 if (!point) {
16886 return {};
16887 }
16888 const pointValue = point[property];
16889 const segments = line.segments;
16890 const linePoints = line.points;
16891 let first = false;
16892 let last = false;
16893 for(let i = 0; i < segments.length; i++){
16894 const segment = segments[i];
16895 const firstValue = linePoints[segment.start][property];
16896 const lastValue = linePoints[segment.end][property];
16897 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(pointValue, firstValue, lastValue)) {
16898 first = pointValue === firstValue;
16899 last = pointValue === lastValue;
16900 break;
16901 }
16902 }
16903 return {
16904 first,
16905 last,
16906 point
16907 };
16908 }
16909
16910 class simpleArc {
16911 constructor(opts){
16912 this.x = opts.x;
16913 this.y = opts.y;
16914 this.radius = opts.radius;
16915 }
16916 pathSegment(ctx, bounds, opts) {
16917 const { x , y , radius } = this;
16918 bounds = bounds || {
16919 start: 0,
16920 end: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T
16921 };
16922 ctx.arc(x, y, radius, bounds.end, bounds.start, true);
16923 return !opts.bounds;
16924 }
16925 interpolate(point) {
16926 const { x , y , radius } = this;
16927 const angle = point.angle;
16928 return {
16929 x: x + Math.cos(angle) * radius,
16930 y: y + Math.sin(angle) * radius,
16931 angle
16932 };
16933 }
16934 }
16935
16936 function _getTarget(source) {
16937 const { chart , fill , line } = source;
16938 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16939 return getLineByIndex(chart, fill);
16940 }
16941 if (fill === 'stack') {
16942 return _buildStackLine(source);
16943 }
16944 if (fill === 'shape') {
16945 return true;
16946 }
16947 const boundary = computeBoundary(source);
16948 if (boundary instanceof simpleArc) {
16949 return boundary;
16950 }
16951 return _createBoundaryLine(boundary, line);
16952 }
16953 function getLineByIndex(chart, index) {
16954 const meta = chart.getDatasetMeta(index);
16955 const visible = meta && chart.isDatasetVisible(index);
16956 return visible ? meta.dataset : null;
16957 }
16958 function computeBoundary(source) {
16959 const scale = source.scale || {};
16960 if (scale.getPointPositionForValue) {
16961 return computeCircularBoundary(source);
16962 }
16963 return computeLinearBoundary(source);
16964 }
16965 function computeLinearBoundary(source) {
16966 const { scale ={} , fill } = source;
16967 const pixel = _getTargetPixel(fill, scale);
16968 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(pixel)) {
16969 const horizontal = scale.isHorizontal();
16970 return {
16971 x: horizontal ? pixel : null,
16972 y: horizontal ? null : pixel
16973 };
16974 }
16975 return null;
16976 }
16977 function computeCircularBoundary(source) {
16978 const { scale , fill } = source;
16979 const options = scale.options;
16980 const length = scale.getLabels().length;
16981 const start = options.reverse ? scale.max : scale.min;
16982 const value = _getTargetValue(fill, scale, start);
16983 const target = [];
16984 if (options.grid.circular) {
16985 const center = scale.getPointPositionForValue(0, start);
16986 return new simpleArc({
16987 x: center.x,
16988 y: center.y,
16989 radius: scale.getDistanceFromCenterForValue(value)
16990 });
16991 }
16992 for(let i = 0; i < length; ++i){
16993 target.push(scale.getPointPositionForValue(i, value));
16994 }
16995 return target;
16996 }
16997
16998 function _drawfill(ctx, source, area) {
16999 const target = _getTarget(source);
17000 const { chart , index , line , scale , axis } = source;
17001 const lineOpts = line.options;
17002 const fillOption = lineOpts.fill;
17003 const color = lineOpts.backgroundColor;
17004 const { above =color , below =color } = fillOption || {};
17005 const meta = chart.getDatasetMeta(index);
17006 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(chart, meta);
17007 if (target && line.points.length) {
17008 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
17009 doFill(ctx, {
17010 line,
17011 target,
17012 above,
17013 below,
17014 area,
17015 scale,
17016 axis,
17017 clip
17018 });
17019 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17020 }
17021 }
17022 function doFill(ctx, cfg) {
17023 const { line , target , above , below , area , scale , clip } = cfg;
17024 const property = line._loop ? 'angle' : cfg.axis;
17025 ctx.save();
17026 let fillColor = below;
17027 if (below !== above) {
17028 if (property === 'x') {
17029 clipVertical(ctx, target, area.top);
17030 fill(ctx, {
17031 line,
17032 target,
17033 color: above,
17034 scale,
17035 property,
17036 clip
17037 });
17038 ctx.restore();
17039 ctx.save();
17040 clipVertical(ctx, target, area.bottom);
17041 } else if (property === 'y') {
17042 clipHorizontal(ctx, target, area.left);
17043 fill(ctx, {
17044 line,
17045 target,
17046 color: below,
17047 scale,
17048 property,
17049 clip
17050 });
17051 ctx.restore();
17052 ctx.save();
17053 clipHorizontal(ctx, target, area.right);
17054 fillColor = above;
17055 }
17056 }
17057 fill(ctx, {
17058 line,
17059 target,
17060 color: fillColor,
17061 scale,
17062 property,
17063 clip
17064 });
17065 ctx.restore();
17066 }
17067 function clipVertical(ctx, target, clipY) {
17068 const { segments , points } = target;
17069 let first = true;
17070 let lineLoop = false;
17071 ctx.beginPath();
17072 for (const segment of segments){
17073 const { start , end } = segment;
17074 const firstPoint = points[start];
17075 const lastPoint = points[_findSegmentEnd(start, end, points)];
17076 if (first) {
17077 ctx.moveTo(firstPoint.x, firstPoint.y);
17078 first = false;
17079 } else {
17080 ctx.lineTo(firstPoint.x, clipY);
17081 ctx.lineTo(firstPoint.x, firstPoint.y);
17082 }
17083 lineLoop = !!target.pathSegment(ctx, segment, {
17084 move: lineLoop
17085 });
17086 if (lineLoop) {
17087 ctx.closePath();
17088 } else {
17089 ctx.lineTo(lastPoint.x, clipY);
17090 }
17091 }
17092 ctx.lineTo(target.first().x, clipY);
17093 ctx.closePath();
17094 ctx.clip();
17095 }
17096 function clipHorizontal(ctx, target, clipX) {
17097 const { segments , points } = target;
17098 let first = true;
17099 let lineLoop = false;
17100 ctx.beginPath();
17101 for (const segment of segments){
17102 const { start , end } = segment;
17103 const firstPoint = points[start];
17104 const lastPoint = points[_findSegmentEnd(start, end, points)];
17105 if (first) {
17106 ctx.moveTo(firstPoint.x, firstPoint.y);
17107 first = false;
17108 } else {
17109 ctx.lineTo(clipX, firstPoint.y);
17110 ctx.lineTo(firstPoint.x, firstPoint.y);
17111 }
17112 lineLoop = !!target.pathSegment(ctx, segment, {
17113 move: lineLoop
17114 });
17115 if (lineLoop) {
17116 ctx.closePath();
17117 } else {
17118 ctx.lineTo(clipX, lastPoint.y);
17119 }
17120 }
17121 ctx.lineTo(clipX, target.first().y);
17122 ctx.closePath();
17123 ctx.clip();
17124 }
17125 function fill(ctx, cfg) {
17126 const { line , target , property , color , scale , clip } = cfg;
17127 const segments = _segments(line, target, property);
17128 for (const { source: src , target: tgt , start , end } of segments){
17129 const { style: { backgroundColor =color } = {} } = src;
17130 const notShape = target !== true;
17131 ctx.save();
17132 ctx.fillStyle = backgroundColor;
17133 clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end));
17134 ctx.beginPath();
17135 const lineLoop = !!line.pathSegment(ctx, src);
17136 let loop;
17137 if (notShape) {
17138 if (lineLoop) {
17139 ctx.closePath();
17140 } else {
17141 interpolatedLineTo(ctx, target, end, property);
17142 }
17143 const targetLoop = !!target.pathSegment(ctx, tgt, {
17144 move: lineLoop,
17145 reverse: true
17146 });
17147 loop = lineLoop && targetLoop;
17148 if (!loop) {
17149 interpolatedLineTo(ctx, target, start, property);
17150 }
17151 }
17152 ctx.closePath();
17153 ctx.fill(loop ? 'evenodd' : 'nonzero');
17154 ctx.restore();
17155 }
17156 }
17157 function clipBounds(ctx, scale, clip, bounds) {
17158 const chartArea = scale.chart.chartArea;
17159 const { property , start , end } = bounds || {};
17160 if (property === 'x' || property === 'y') {
17161 let left, top, right, bottom;
17162 if (property === 'x') {
17163 left = start;
17164 top = chartArea.top;
17165 right = end;
17166 bottom = chartArea.bottom;
17167 } else {
17168 left = chartArea.left;
17169 top = start;
17170 right = chartArea.right;
17171 bottom = end;
17172 }
17173 ctx.beginPath();
17174 if (clip) {
17175 left = Math.max(left, clip.left);
17176 right = Math.min(right, clip.right);
17177 top = Math.max(top, clip.top);
17178 bottom = Math.min(bottom, clip.bottom);
17179 }
17180 ctx.rect(left, top, right - left, bottom - top);
17181 ctx.clip();
17182 }
17183 }
17184 function interpolatedLineTo(ctx, target, point, property) {
17185 const interpolatedPoint = target.interpolate(point, property);
17186 if (interpolatedPoint) {
17187 ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
17188 }
17189 }
17190
17191 var index = {
17192 id: 'filler',
17193 afterDatasetsUpdate (chart, _args, options) {
17194 const count = (chart.data.datasets || []).length;
17195 const sources = [];
17196 let meta, i, line, source;
17197 for(i = 0; i < count; ++i){
17198 meta = chart.getDatasetMeta(i);
17199 line = meta.dataset;
17200 source = null;
17201 if (line && line.options && line instanceof LineElement) {
17202 source = {
17203 visible: chart.isDatasetVisible(i),
17204 index: i,
17205 fill: _decodeFill(line, i, count),
17206 chart,
17207 axis: meta.controller.options.indexAxis,
17208 scale: meta.vScale,
17209 line
17210 };
17211 }
17212 meta.$filler = source;
17213 sources.push(source);
17214 }
17215 for(i = 0; i < count; ++i){
17216 source = sources[i];
17217 if (!source || source.fill === false) {
17218 continue;
17219 }
17220 source.fill = _resolveTarget(sources, i, options.propagate);
17221 }
17222 },
17223 beforeDraw (chart, _args, options) {
17224 const draw = options.drawTime === 'beforeDraw';
17225 const metasets = chart.getSortedVisibleDatasetMetas();
17226 const area = chart.chartArea;
17227 for(let i = metasets.length - 1; i >= 0; --i){
17228 const source = metasets[i].$filler;
17229 if (!source) {
17230 continue;
17231 }
17232 source.line.updateControlPoints(area, source.axis);
17233 if (draw && source.fill) {
17234 _drawfill(chart.ctx, source, area);
17235 }
17236 }
17237 },
17238 beforeDatasetsDraw (chart, _args, options) {
17239 if (options.drawTime !== 'beforeDatasetsDraw') {
17240 return;
17241 }
17242 const metasets = chart.getSortedVisibleDatasetMetas();
17243 for(let i = metasets.length - 1; i >= 0; --i){
17244 const source = metasets[i].$filler;
17245 if (_shouldApplyFill(source)) {
17246 _drawfill(chart.ctx, source, chart.chartArea);
17247 }
17248 }
17249 },
17250 beforeDatasetDraw (chart, args, options) {
17251 const source = args.meta.$filler;
17252 if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') {
17253 return;
17254 }
17255 _drawfill(chart.ctx, source, chart.chartArea);
17256 },
17257 defaults: {
17258 propagate: true,
17259 drawTime: 'beforeDatasetDraw'
17260 }
17261 };
17262
17263 const getBoxSize = (labelOpts, fontSize)=>{
17264 let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts;
17265 if (labelOpts.usePointStyle) {
17266 boxHeight = Math.min(boxHeight, fontSize);
17267 boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);
17268 }
17269 return {
17270 boxWidth,
17271 boxHeight,
17272 itemHeight: Math.max(fontSize, boxHeight)
17273 };
17274 };
17275 const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
17276 class Legend extends Element {
17277 constructor(config){
17278 super();
17279 this._added = false;
17280 this.legendHitBoxes = [];
17281 this._hoveredItem = null;
17282 this.doughnutMode = false;
17283 this.chart = config.chart;
17284 this.options = config.options;
17285 this.ctx = config.ctx;
17286 this.legendItems = undefined;
17287 this.columnSizes = undefined;
17288 this.lineWidths = undefined;
17289 this.maxHeight = undefined;
17290 this.maxWidth = undefined;
17291 this.top = undefined;
17292 this.bottom = undefined;
17293 this.left = undefined;
17294 this.right = undefined;
17295 this.height = undefined;
17296 this.width = undefined;
17297 this._margins = undefined;
17298 this.position = undefined;
17299 this.weight = undefined;
17300 this.fullSize = undefined;
17301 }
17302 update(maxWidth, maxHeight, margins) {
17303 this.maxWidth = maxWidth;
17304 this.maxHeight = maxHeight;
17305 this._margins = margins;
17306 this.setDimensions();
17307 this.buildLabels();
17308 this.fit();
17309 }
17310 setDimensions() {
17311 if (this.isHorizontal()) {
17312 this.width = this.maxWidth;
17313 this.left = this._margins.left;
17314 this.right = this.width;
17315 } else {
17316 this.height = this.maxHeight;
17317 this.top = this._margins.top;
17318 this.bottom = this.height;
17319 }
17320 }
17321 buildLabels() {
17322 const labelOpts = this.options.labels || {};
17323 let legendItems = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(labelOpts.generateLabels, [
17324 this.chart
17325 ], this) || [];
17326 if (labelOpts.filter) {
17327 legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data));
17328 }
17329 if (labelOpts.sort) {
17330 legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data));
17331 }
17332 if (this.options.reverse) {
17333 legendItems.reverse();
17334 }
17335 this.legendItems = legendItems;
17336 }
17337 fit() {
17338 const { options , ctx } = this;
17339 if (!options.display) {
17340 this.width = this.height = 0;
17341 return;
17342 }
17343 const labelOpts = options.labels;
17344 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17345 const fontSize = labelFont.size;
17346 const titleHeight = this._computeTitleHeight();
17347 const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize);
17348 let width, height;
17349 ctx.font = labelFont.string;
17350 if (this.isHorizontal()) {
17351 width = this.maxWidth;
17352 height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
17353 } else {
17354 height = this.maxHeight;
17355 width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;
17356 }
17357 this.width = Math.min(width, options.maxWidth || this.maxWidth);
17358 this.height = Math.min(height, options.maxHeight || this.maxHeight);
17359 }
17360 _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
17361 const { ctx , maxWidth , options: { labels: { padding } } } = this;
17362 const hitboxes = this.legendHitBoxes = [];
17363 const lineWidths = this.lineWidths = [
17364 0
17365 ];
17366 const lineHeight = itemHeight + padding;
17367 let totalHeight = titleHeight;
17368 ctx.textAlign = 'left';
17369 ctx.textBaseline = 'middle';
17370 let row = -1;
17371 let top = -lineHeight;
17372 this.legendItems.forEach((legendItem, i)=>{
17373 const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;
17374 if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
17375 totalHeight += lineHeight;
17376 lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
17377 top += lineHeight;
17378 row++;
17379 }
17380 hitboxes[i] = {
17381 left: 0,
17382 top,
17383 row,
17384 width: itemWidth,
17385 height: itemHeight
17386 };
17387 lineWidths[lineWidths.length - 1] += itemWidth + padding;
17388 });
17389 return totalHeight;
17390 }
17391 _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {
17392 const { ctx , maxHeight , options: { labels: { padding } } } = this;
17393 const hitboxes = this.legendHitBoxes = [];
17394 const columnSizes = this.columnSizes = [];
17395 const heightLimit = maxHeight - titleHeight;
17396 let totalWidth = padding;
17397 let currentColWidth = 0;
17398 let currentColHeight = 0;
17399 let left = 0;
17400 let col = 0;
17401 this.legendItems.forEach((legendItem, i)=>{
17402 const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);
17403 if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
17404 totalWidth += currentColWidth + padding;
17405 columnSizes.push({
17406 width: currentColWidth,
17407 height: currentColHeight
17408 });
17409 left += currentColWidth + padding;
17410 col++;
17411 currentColWidth = currentColHeight = 0;
17412 }
17413 hitboxes[i] = {
17414 left,
17415 top: currentColHeight,
17416 col,
17417 width: itemWidth,
17418 height: itemHeight
17419 };
17420 currentColWidth = Math.max(currentColWidth, itemWidth);
17421 currentColHeight += itemHeight + padding;
17422 });
17423 totalWidth += currentColWidth;
17424 columnSizes.push({
17425 width: currentColWidth,
17426 height: currentColHeight
17427 });
17428 return totalWidth;
17429 }
17430 adjustHitBoxes() {
17431 if (!this.options.display) {
17432 return;
17433 }
17434 const titleHeight = this._computeTitleHeight();
17435 const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this;
17436 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(rtl, this.left, this.width);
17437 if (this.isHorizontal()) {
17438 let row = 0;
17439 let left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17440 for (const hitbox of hitboxes){
17441 if (row !== hitbox.row) {
17442 row = hitbox.row;
17443 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17444 }
17445 hitbox.top += this.top + titleHeight + padding;
17446 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
17447 left += hitbox.width + padding;
17448 }
17449 } else {
17450 let col = 0;
17451 let top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17452 for (const hitbox of hitboxes){
17453 if (hitbox.col !== col) {
17454 col = hitbox.col;
17455 top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17456 }
17457 hitbox.top = top;
17458 hitbox.left += this.left + padding;
17459 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
17460 top += hitbox.height + padding;
17461 }
17462 }
17463 }
17464 isHorizontal() {
17465 return this.options.position === 'top' || this.options.position === 'bottom';
17466 }
17467 draw() {
17468 if (this.options.display) {
17469 const ctx = this.ctx;
17470 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, this);
17471 this._draw();
17472 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17473 }
17474 }
17475 _draw() {
17476 const { options: opts , columnSizes , lineWidths , ctx } = this;
17477 const { align , labels: labelOpts } = opts;
17478 const defaultColor = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.color;
17479 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17480 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17481 const { padding } = labelOpts;
17482 const fontSize = labelFont.size;
17483 const halfFontSize = fontSize / 2;
17484 let cursor;
17485 this.drawTitle();
17486 ctx.textAlign = rtlHelper.textAlign('left');
17487 ctx.textBaseline = 'middle';
17488 ctx.lineWidth = 0.5;
17489 ctx.font = labelFont.string;
17490 const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize);
17491 const drawLegendBox = function(x, y, legendItem) {
17492 if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
17493 return;
17494 }
17495 ctx.save();
17496 const lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineWidth, 1);
17497 ctx.fillStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.fillStyle, defaultColor);
17498 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineCap, 'butt');
17499 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDashOffset, 0);
17500 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineJoin, 'miter');
17501 ctx.lineWidth = lineWidth;
17502 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.strokeStyle, defaultColor);
17503 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDash, []));
17504 if (labelOpts.usePointStyle) {
17505 const drawOptions = {
17506 radius: boxHeight * Math.SQRT2 / 2,
17507 pointStyle: legendItem.pointStyle,
17508 rotation: legendItem.rotation,
17509 borderWidth: lineWidth
17510 };
17511 const centerX = rtlHelper.xPlus(x, boxWidth / 2);
17512 const centerY = y + halfFontSize;
17513 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aE)(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);
17514 } else {
17515 const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
17516 const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);
17517 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(legendItem.borderRadius);
17518 ctx.beginPath();
17519 if (Object.values(borderRadius).some((v)=>v !== 0)) {
17520 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
17521 x: xBoxLeft,
17522 y: yBoxTop,
17523 w: boxWidth,
17524 h: boxHeight,
17525 radius: borderRadius
17526 });
17527 } else {
17528 ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
17529 }
17530 ctx.fill();
17531 if (lineWidth !== 0) {
17532 ctx.stroke();
17533 }
17534 }
17535 ctx.restore();
17536 };
17537 const fillText = function(x, y, legendItem) {
17538 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, {
17539 strikethrough: legendItem.hidden,
17540 textAlign: rtlHelper.textAlign(legendItem.textAlign)
17541 });
17542 };
17543 const isHorizontal = this.isHorizontal();
17544 const titleHeight = this._computeTitleHeight();
17545 if (isHorizontal) {
17546 cursor = {
17547 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[0]),
17548 y: this.top + padding + titleHeight,
17549 line: 0
17550 };
17551 } else {
17552 cursor = {
17553 x: this.left + padding,
17554 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
17555 line: 0
17556 };
17557 }
17558 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(this.ctx, opts.textDirection);
17559 const lineHeight = itemHeight + padding;
17560 this.legendItems.forEach((legendItem, i)=>{
17561 ctx.strokeStyle = legendItem.fontColor;
17562 ctx.fillStyle = legendItem.fontColor;
17563 const textWidth = ctx.measureText(legendItem.text).width;
17564 const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
17565 const width = boxWidth + halfFontSize + textWidth;
17566 let x = cursor.x;
17567 let y = cursor.y;
17568 rtlHelper.setWidth(this.width);
17569 if (isHorizontal) {
17570 if (i > 0 && x + width + padding > this.right) {
17571 y = cursor.y += lineHeight;
17572 cursor.line++;
17573 x = cursor.x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[cursor.line]);
17574 }
17575 } else if (i > 0 && y + lineHeight > this.bottom) {
17576 x = cursor.x = x + columnSizes[cursor.line].width + padding;
17577 cursor.line++;
17578 y = cursor.y = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
17579 }
17580 const realX = rtlHelper.x(x);
17581 drawLegendBox(realX, y, legendItem);
17582 x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aC)(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
17583 fillText(rtlHelper.x(x), y, legendItem);
17584 if (isHorizontal) {
17585 cursor.x += width + padding;
17586 } else if (typeof legendItem.text !== 'string') {
17587 const fontLineHeight = labelFont.lineHeight;
17588 cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;
17589 } else {
17590 cursor.y += lineHeight;
17591 }
17592 });
17593 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(this.ctx, opts.textDirection);
17594 }
17595 drawTitle() {
17596 const opts = this.options;
17597 const titleOpts = opts.title;
17598 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17599 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17600 if (!titleOpts.display) {
17601 return;
17602 }
17603 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17604 const ctx = this.ctx;
17605 const position = titleOpts.position;
17606 const halfFontSize = titleFont.size / 2;
17607 const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
17608 let y;
17609 let left = this.left;
17610 let maxWidth = this.width;
17611 if (this.isHorizontal()) {
17612 maxWidth = Math.max(...this.lineWidths);
17613 y = this.top + topPaddingPlusHalfFontSize;
17614 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, left, this.right - maxWidth);
17615 } else {
17616 const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0);
17617 y = topPaddingPlusHalfFontSize + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
17618 }
17619 const x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(position, left, left + maxWidth);
17620 ctx.textAlign = rtlHelper.textAlign((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(position));
17621 ctx.textBaseline = 'middle';
17622 ctx.strokeStyle = titleOpts.color;
17623 ctx.fillStyle = titleOpts.color;
17624 ctx.font = titleFont.string;
17625 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, titleOpts.text, x, y, titleFont);
17626 }
17627 _computeTitleHeight() {
17628 const titleOpts = this.options.title;
17629 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17630 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17631 return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
17632 }
17633 _getLegendItemAt(x, y) {
17634 let i, hitBox, lh;
17635 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)) {
17636 lh = this.legendHitBoxes;
17637 for(i = 0; i < lh.length; ++i){
17638 hitBox = lh[i];
17639 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)) {
17640 return this.legendItems[i];
17641 }
17642 }
17643 }
17644 return null;
17645 }
17646 handleEvent(e) {
17647 const opts = this.options;
17648 if (!isListened(e.type, opts)) {
17649 return;
17650 }
17651 const hoveredItem = this._getLegendItemAt(e.x, e.y);
17652 if (e.type === 'mousemove' || e.type === 'mouseout') {
17653 const previous = this._hoveredItem;
17654 const sameItem = itemsEqual(previous, hoveredItem);
17655 if (previous && !sameItem) {
17656 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onLeave, [
17657 e,
17658 previous,
17659 this
17660 ], this);
17661 }
17662 this._hoveredItem = hoveredItem;
17663 if (hoveredItem && !sameItem) {
17664 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onHover, [
17665 e,
17666 hoveredItem,
17667 this
17668 ], this);
17669 }
17670 } else if (hoveredItem) {
17671 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onClick, [
17672 e,
17673 hoveredItem,
17674 this
17675 ], this);
17676 }
17677 }
17678 }
17679 function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {
17680 const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);
17681 const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);
17682 return {
17683 itemWidth,
17684 itemHeight
17685 };
17686 }
17687 function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {
17688 let legendItemText = legendItem.text;
17689 if (legendItemText && typeof legendItemText !== 'string') {
17690 legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b);
17691 }
17692 return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;
17693 }
17694 function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {
17695 let itemHeight = _itemHeight;
17696 if (typeof legendItem.text !== 'string') {
17697 itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);
17698 }
17699 return itemHeight;
17700 }
17701 function calculateLegendItemHeight(legendItem, fontLineHeight) {
17702 const labelHeight = legendItem.text ? legendItem.text.length : 0;
17703 return fontLineHeight * labelHeight;
17704 }
17705 function isListened(type, opts) {
17706 if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) {
17707 return true;
17708 }
17709 if (opts.onClick && (type === 'click' || type === 'mouseup')) {
17710 return true;
17711 }
17712 return false;
17713 }
17714 var plugin_legend = {
17715 id: 'legend',
17716 _element: Legend,
17717 start (chart, _args, options) {
17718 const legend = chart.legend = new Legend({
17719 ctx: chart.ctx,
17720 options,
17721 chart
17722 });
17723 layouts.configure(chart, legend, options);
17724 layouts.addBox(chart, legend);
17725 },
17726 stop (chart) {
17727 layouts.removeBox(chart, chart.legend);
17728 delete chart.legend;
17729 },
17730 beforeUpdate (chart, _args, options) {
17731 const legend = chart.legend;
17732 layouts.configure(chart, legend, options);
17733 legend.options = options;
17734 },
17735 afterUpdate (chart) {
17736 const legend = chart.legend;
17737 legend.buildLabels();
17738 legend.adjustHitBoxes();
17739 },
17740 afterEvent (chart, args) {
17741 if (!args.replay) {
17742 chart.legend.handleEvent(args.event);
17743 }
17744 },
17745 defaults: {
17746 display: true,
17747 position: 'top',
17748 align: 'center',
17749 fullSize: true,
17750 reverse: false,
17751 weight: 1000,
17752 onClick (e, legendItem, legend) {
17753 const index = legendItem.datasetIndex;
17754 const ci = legend.chart;
17755 if (ci.isDatasetVisible(index)) {
17756 ci.hide(index);
17757 legendItem.hidden = true;
17758 } else {
17759 ci.show(index);
17760 legendItem.hidden = false;
17761 }
17762 },
17763 onHover: null,
17764 onLeave: null,
17765 labels: {
17766 color: (ctx)=>ctx.chart.options.color,
17767 boxWidth: 40,
17768 padding: 10,
17769 generateLabels (chart) {
17770 const datasets = chart.data.datasets;
17771 const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
17772 return chart._getSortedDatasetMetas().map((meta)=>{
17773 const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
17774 const borderWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(style.borderWidth);
17775 return {
17776 text: datasets[meta.index].label,
17777 fillStyle: style.backgroundColor,
17778 fontColor: color,
17779 hidden: !meta.visible,
17780 lineCap: style.borderCapStyle,
17781 lineDash: style.borderDash,
17782 lineDashOffset: style.borderDashOffset,
17783 lineJoin: style.borderJoinStyle,
17784 lineWidth: (borderWidth.width + borderWidth.height) / 4,
17785 strokeStyle: style.borderColor,
17786 pointStyle: pointStyle || style.pointStyle,
17787 rotation: style.rotation,
17788 textAlign: textAlign || style.textAlign,
17789 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
17790 datasetIndex: meta.index
17791 };
17792 }, this);
17793 }
17794 },
17795 title: {
17796 color: (ctx)=>ctx.chart.options.color,
17797 display: false,
17798 position: 'center',
17799 text: ''
17800 }
17801 },
17802 descriptors: {
17803 _scriptable: (name)=>!name.startsWith('on'),
17804 labels: {
17805 _scriptable: (name)=>![
17806 'generateLabels',
17807 'filter',
17808 'sort'
17809 ].includes(name)
17810 }
17811 }
17812 };
17813
17814 class Title extends Element {
17815 constructor(config){
17816 super();
17817 this.chart = config.chart;
17818 this.options = config.options;
17819 this.ctx = config.ctx;
17820 this._padding = undefined;
17821 this.top = undefined;
17822 this.bottom = undefined;
17823 this.left = undefined;
17824 this.right = undefined;
17825 this.width = undefined;
17826 this.height = undefined;
17827 this.position = undefined;
17828 this.weight = undefined;
17829 this.fullSize = undefined;
17830 }
17831 update(maxWidth, maxHeight) {
17832 const opts = this.options;
17833 this.left = 0;
17834 this.top = 0;
17835 if (!opts.display) {
17836 this.width = this.height = this.right = this.bottom = 0;
17837 return;
17838 }
17839 this.width = this.right = maxWidth;
17840 this.height = this.bottom = maxHeight;
17841 const lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(opts.text) ? opts.text.length : 1;
17842 this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.padding);
17843 const textSize = lineCount * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font).lineHeight + this._padding.height;
17844 if (this.isHorizontal()) {
17845 this.height = textSize;
17846 } else {
17847 this.width = textSize;
17848 }
17849 }
17850 isHorizontal() {
17851 const pos = this.options.position;
17852 return pos === 'top' || pos === 'bottom';
17853 }
17854 _drawArgs(offset) {
17855 const { top , left , bottom , right , options } = this;
17856 const align = options.align;
17857 let rotation = 0;
17858 let maxWidth, titleX, titleY;
17859 if (this.isHorizontal()) {
17860 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
17861 titleY = top + offset;
17862 maxWidth = right - left;
17863 } else {
17864 if (options.position === 'left') {
17865 titleX = left + offset;
17866 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
17867 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * -0.5;
17868 } else {
17869 titleX = right - offset;
17870 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, top, bottom);
17871 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * 0.5;
17872 }
17873 maxWidth = bottom - top;
17874 }
17875 return {
17876 titleX,
17877 titleY,
17878 maxWidth,
17879 rotation
17880 };
17881 }
17882 draw() {
17883 const ctx = this.ctx;
17884 const opts = this.options;
17885 if (!opts.display) {
17886 return;
17887 }
17888 const fontOpts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
17889 const lineHeight = fontOpts.lineHeight;
17890 const offset = lineHeight / 2 + this._padding.top;
17891 const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset);
17892 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, opts.text, 0, 0, fontOpts, {
17893 color: opts.color,
17894 maxWidth,
17895 rotation,
17896 textAlign: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(opts.align),
17897 textBaseline: 'middle',
17898 translation: [
17899 titleX,
17900 titleY
17901 ]
17902 });
17903 }
17904 }
17905 function createTitle(chart, titleOpts) {
17906 const title = new Title({
17907 ctx: chart.ctx,
17908 options: titleOpts,
17909 chart
17910 });
17911 layouts.configure(chart, title, titleOpts);
17912 layouts.addBox(chart, title);
17913 chart.titleBlock = title;
17914 }
17915 var plugin_title = {
17916 id: 'title',
17917 _element: Title,
17918 start (chart, _args, options) {
17919 createTitle(chart, options);
17920 },
17921 stop (chart) {
17922 const titleBlock = chart.titleBlock;
17923 layouts.removeBox(chart, titleBlock);
17924 delete chart.titleBlock;
17925 },
17926 beforeUpdate (chart, _args, options) {
17927 const title = chart.titleBlock;
17928 layouts.configure(chart, title, options);
17929 title.options = options;
17930 },
17931 defaults: {
17932 align: 'center',
17933 display: false,
17934 font: {
17935 weight: 'bold'
17936 },
17937 fullSize: true,
17938 padding: 10,
17939 position: 'top',
17940 text: '',
17941 weight: 2000
17942 },
17943 defaultRoutes: {
17944 color: 'color'
17945 },
17946 descriptors: {
17947 _scriptable: true,
17948 _indexable: false
17949 }
17950 };
17951
17952 const map = new WeakMap();
17953 var plugin_subtitle = {
17954 id: 'subtitle',
17955 start (chart, _args, options) {
17956 const title = new Title({
17957 ctx: chart.ctx,
17958 options,
17959 chart
17960 });
17961 layouts.configure(chart, title, options);
17962 layouts.addBox(chart, title);
17963 map.set(chart, title);
17964 },
17965 stop (chart) {
17966 layouts.removeBox(chart, map.get(chart));
17967 map.delete(chart);
17968 },
17969 beforeUpdate (chart, _args, options) {
17970 const title = map.get(chart);
17971 layouts.configure(chart, title, options);
17972 title.options = options;
17973 },
17974 defaults: {
17975 align: 'center',
17976 display: false,
17977 font: {
17978 weight: 'normal'
17979 },
17980 fullSize: true,
17981 padding: 0,
17982 position: 'top',
17983 text: '',
17984 weight: 1500
17985 },
17986 defaultRoutes: {
17987 color: 'color'
17988 },
17989 descriptors: {
17990 _scriptable: true,
17991 _indexable: false
17992 }
17993 };
17994
17995 const positioners = {
17996 average (items) {
17997 if (!items.length) {
17998 return false;
17999 }
18000 let i, len;
18001 let xSet = new Set();
18002 let y = 0;
18003 let count = 0;
18004 for(i = 0, len = items.length; i < len; ++i){
18005 const el = items[i].element;
18006 if (el && el.hasValue()) {
18007 const pos = el.tooltipPosition();
18008 xSet.add(pos.x);
18009 y += pos.y;
18010 ++count;
18011 }
18012 }
18013 if (count === 0 || xSet.size === 0) {
18014 return false;
18015 }
18016 const xAverage = [
18017 ...xSet
18018 ].reduce((a, b)=>a + b) / xSet.size;
18019 return {
18020 x: xAverage,
18021 y: y / count
18022 };
18023 },
18024 nearest (items, eventPosition) {
18025 if (!items.length) {
18026 return false;
18027 }
18028 let x = eventPosition.x;
18029 let y = eventPosition.y;
18030 let minDistance = Number.POSITIVE_INFINITY;
18031 let i, len, nearestElement;
18032 for(i = 0, len = items.length; i < len; ++i){
18033 const el = items[i].element;
18034 if (el && el.hasValue()) {
18035 const center = el.getCenterPoint();
18036 const d = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aF)(eventPosition, center);
18037 if (d < minDistance) {
18038 minDistance = d;
18039 nearestElement = el;
18040 }
18041 }
18042 }
18043 if (nearestElement) {
18044 const tp = nearestElement.tooltipPosition();
18045 x = tp.x;
18046 y = tp.y;
18047 }
18048 return {
18049 x,
18050 y
18051 };
18052 }
18053 };
18054 function pushOrConcat(base, toPush) {
18055 if (toPush) {
18056 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(toPush)) {
18057 Array.prototype.push.apply(base, toPush);
18058 } else {
18059 base.push(toPush);
18060 }
18061 }
18062 return base;
18063 }
18064 function splitNewlines(str) {
18065 if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
18066 return str.split('\n');
18067 }
18068 return str;
18069 }
18070 function createTooltipItem(chart, item) {
18071 const { element , datasetIndex , index } = item;
18072 const controller = chart.getDatasetMeta(datasetIndex).controller;
18073 const { label , value } = controller.getLabelAndValue(index);
18074 return {
18075 chart,
18076 label,
18077 parsed: controller.getParsed(index),
18078 raw: chart.data.datasets[datasetIndex].data[index],
18079 formattedValue: value,
18080 dataset: controller.getDataset(),
18081 dataIndex: index,
18082 datasetIndex,
18083 element
18084 };
18085 }
18086 function getTooltipSize(tooltip, options) {
18087 const ctx = tooltip.chart.ctx;
18088 const { body , footer , title } = tooltip;
18089 const { boxWidth , boxHeight } = options;
18090 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18091 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18092 const footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18093 const titleLineCount = title.length;
18094 const footerLineCount = footer.length;
18095 const bodyLineItemCount = body.length;
18096 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18097 let height = padding.height;
18098 let width = 0;
18099 let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
18100 combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
18101 if (titleLineCount) {
18102 height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;
18103 }
18104 if (combinedBodyLength) {
18105 const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
18106 height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;
18107 }
18108 if (footerLineCount) {
18109 height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;
18110 }
18111 let widthPadding = 0;
18112 const maxLineWidth = function(line) {
18113 width = Math.max(width, ctx.measureText(line).width + widthPadding);
18114 };
18115 ctx.save();
18116 ctx.font = titleFont.string;
18117 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.title, maxLineWidth);
18118 ctx.font = bodyFont.string;
18119 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
18120 widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;
18121 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(body, (bodyItem)=>{
18122 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, maxLineWidth);
18123 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.lines, maxLineWidth);
18124 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, maxLineWidth);
18125 });
18126 widthPadding = 0;
18127 ctx.font = footerFont.string;
18128 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.footer, maxLineWidth);
18129 ctx.restore();
18130 width += padding.width;
18131 return {
18132 width,
18133 height
18134 };
18135 }
18136 function determineYAlign(chart, size) {
18137 const { y , height } = size;
18138 if (y < height / 2) {
18139 return 'top';
18140 } else if (y > chart.height - height / 2) {
18141 return 'bottom';
18142 }
18143 return 'center';
18144 }
18145 function doesNotFitWithAlign(xAlign, chart, options, size) {
18146 const { x , width } = size;
18147 const caret = options.caretSize + options.caretPadding;
18148 if (xAlign === 'left' && x + width + caret > chart.width) {
18149 return true;
18150 }
18151 if (xAlign === 'right' && x - width - caret < 0) {
18152 return true;
18153 }
18154 }
18155 function determineXAlign(chart, options, size, yAlign) {
18156 const { x , width } = size;
18157 const { width: chartWidth , chartArea: { left , right } } = chart;
18158 let xAlign = 'center';
18159 if (yAlign === 'center') {
18160 xAlign = x <= (left + right) / 2 ? 'left' : 'right';
18161 } else if (x <= width / 2) {
18162 xAlign = 'left';
18163 } else if (x >= chartWidth - width / 2) {
18164 xAlign = 'right';
18165 }
18166 if (doesNotFitWithAlign(xAlign, chart, options, size)) {
18167 xAlign = 'center';
18168 }
18169 return xAlign;
18170 }
18171 function determineAlignment(chart, options, size) {
18172 const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
18173 return {
18174 xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
18175 yAlign
18176 };
18177 }
18178 function alignX(size, xAlign) {
18179 let { x , width } = size;
18180 if (xAlign === 'right') {
18181 x -= width;
18182 } else if (xAlign === 'center') {
18183 x -= width / 2;
18184 }
18185 return x;
18186 }
18187 function alignY(size, yAlign, paddingAndSize) {
18188 let { y , height } = size;
18189 if (yAlign === 'top') {
18190 y += paddingAndSize;
18191 } else if (yAlign === 'bottom') {
18192 y -= height + paddingAndSize;
18193 } else {
18194 y -= height / 2;
18195 }
18196 return y;
18197 }
18198 function getBackgroundPoint(options, size, alignment, chart) {
18199 const { caretSize , caretPadding , cornerRadius } = options;
18200 const { xAlign , yAlign } = alignment;
18201 const paddingAndSize = caretSize + caretPadding;
18202 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18203 let x = alignX(size, xAlign);
18204 const y = alignY(size, yAlign, paddingAndSize);
18205 if (yAlign === 'center') {
18206 if (xAlign === 'left') {
18207 x += paddingAndSize;
18208 } else if (xAlign === 'right') {
18209 x -= paddingAndSize;
18210 }
18211 } else if (xAlign === 'left') {
18212 x -= Math.max(topLeft, bottomLeft) + caretSize;
18213 } else if (xAlign === 'right') {
18214 x += Math.max(topRight, bottomRight) + caretSize;
18215 }
18216 return {
18217 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(x, 0, chart.width - size.width),
18218 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(y, 0, chart.height - size.height)
18219 };
18220 }
18221 function getAlignedX(tooltip, align, options) {
18222 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18223 return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;
18224 }
18225 function getBeforeAfterBodyLines(callback) {
18226 return pushOrConcat([], splitNewlines(callback));
18227 }
18228 function createTooltipContext(parent, tooltip, tooltipItems) {
18229 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
18230 tooltip,
18231 tooltipItems,
18232 type: 'tooltip'
18233 });
18234 }
18235 function overrideCallbacks(callbacks, context) {
18236 const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
18237 return override ? callbacks.override(override) : callbacks;
18238 }
18239 const defaultCallbacks = {
18240 beforeTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18241 title (tooltipItems) {
18242 if (tooltipItems.length > 0) {
18243 const item = tooltipItems[0];
18244 const labels = item.chart.data.labels;
18245 const labelCount = labels ? labels.length : 0;
18246 if (this && this.options && this.options.mode === 'dataset') {
18247 return item.dataset.label || '';
18248 } else if (item.label) {
18249 return item.label;
18250 } else if (labelCount > 0 && item.dataIndex < labelCount) {
18251 return labels[item.dataIndex];
18252 }
18253 }
18254 return '';
18255 },
18256 afterTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18257 beforeBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18258 beforeLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18259 label (tooltipItem) {
18260 if (this && this.options && this.options.mode === 'dataset') {
18261 return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
18262 }
18263 let label = tooltipItem.dataset.label || '';
18264 if (label) {
18265 label += ': ';
18266 }
18267 const value = tooltipItem.formattedValue;
18268 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
18269 label += value;
18270 }
18271 return label;
18272 },
18273 labelColor (tooltipItem) {
18274 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18275 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18276 return {
18277 borderColor: options.borderColor,
18278 backgroundColor: options.backgroundColor,
18279 borderWidth: options.borderWidth,
18280 borderDash: options.borderDash,
18281 borderDashOffset: options.borderDashOffset,
18282 borderRadius: 0
18283 };
18284 },
18285 labelTextColor () {
18286 return this.options.bodyColor;
18287 },
18288 labelPointStyle (tooltipItem) {
18289 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18290 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18291 return {
18292 pointStyle: options.pointStyle,
18293 rotation: options.rotation
18294 };
18295 },
18296 afterLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18297 afterBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18298 beforeFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18299 footer: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18300 afterFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG
18301 };
18302 function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
18303 const result = callbacks[name].call(ctx, arg);
18304 if (typeof result === 'undefined') {
18305 return defaultCallbacks[name].call(ctx, arg);
18306 }
18307 return result;
18308 }
18309 class Tooltip extends Element {
18310 static positioners = positioners;
18311 constructor(config){
18312 super();
18313 this.opacity = 0;
18314 this._active = [];
18315 this._eventPosition = undefined;
18316 this._size = undefined;
18317 this._cachedAnimations = undefined;
18318 this._tooltipItems = [];
18319 this.$animations = undefined;
18320 this.$context = undefined;
18321 this.chart = config.chart;
18322 this.options = config.options;
18323 this.dataPoints = undefined;
18324 this.title = undefined;
18325 this.beforeBody = undefined;
18326 this.body = undefined;
18327 this.afterBody = undefined;
18328 this.footer = undefined;
18329 this.xAlign = undefined;
18330 this.yAlign = undefined;
18331 this.x = undefined;
18332 this.y = undefined;
18333 this.height = undefined;
18334 this.width = undefined;
18335 this.caretX = undefined;
18336 this.caretY = undefined;
18337 this.labelColors = undefined;
18338 this.labelPointStyles = undefined;
18339 this.labelTextColors = undefined;
18340 }
18341 initialize(options) {
18342 this.options = options;
18343 this._cachedAnimations = undefined;
18344 this.$context = undefined;
18345 }
18346 _resolveAnimations() {
18347 const cached = this._cachedAnimations;
18348 if (cached) {
18349 return cached;
18350 }
18351 const chart = this.chart;
18352 const options = this.options.setContext(this.getContext());
18353 const opts = options.enabled && chart.options.animation && options.animations;
18354 const animations = new Animations(this.chart, opts);
18355 if (opts._cacheable) {
18356 this._cachedAnimations = Object.freeze(animations);
18357 }
18358 return animations;
18359 }
18360 getContext() {
18361 return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
18362 }
18363 getTitle(context, options) {
18364 const { callbacks } = options;
18365 const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);
18366 const title = invokeCallbackWithFallback(callbacks, 'title', this, context);
18367 const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);
18368 let lines = [];
18369 lines = pushOrConcat(lines, splitNewlines(beforeTitle));
18370 lines = pushOrConcat(lines, splitNewlines(title));
18371 lines = pushOrConcat(lines, splitNewlines(afterTitle));
18372 return lines;
18373 }
18374 getBeforeBody(tooltipItems, options) {
18375 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems));
18376 }
18377 getBody(tooltipItems, options) {
18378 const { callbacks } = options;
18379 const bodyItems = [];
18380 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18381 const bodyItem = {
18382 before: [],
18383 lines: [],
18384 after: []
18385 };
18386 const scoped = overrideCallbacks(callbacks, context);
18387 pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));
18388 pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));
18389 pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));
18390 bodyItems.push(bodyItem);
18391 });
18392 return bodyItems;
18393 }
18394 getAfterBody(tooltipItems, options) {
18395 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems));
18396 }
18397 getFooter(tooltipItems, options) {
18398 const { callbacks } = options;
18399 const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);
18400 const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);
18401 const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);
18402 let lines = [];
18403 lines = pushOrConcat(lines, splitNewlines(beforeFooter));
18404 lines = pushOrConcat(lines, splitNewlines(footer));
18405 lines = pushOrConcat(lines, splitNewlines(afterFooter));
18406 return lines;
18407 }
18408 _createItems(options) {
18409 const active = this._active;
18410 const data = this.chart.data;
18411 const labelColors = [];
18412 const labelPointStyles = [];
18413 const labelTextColors = [];
18414 let tooltipItems = [];
18415 let i, len;
18416 for(i = 0, len = active.length; i < len; ++i){
18417 tooltipItems.push(createTooltipItem(this.chart, active[i]));
18418 }
18419 if (options.filter) {
18420 tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data));
18421 }
18422 if (options.itemSort) {
18423 tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data));
18424 }
18425 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18426 const scoped = overrideCallbacks(options.callbacks, context);
18427 labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));
18428 labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));
18429 labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));
18430 });
18431 this.labelColors = labelColors;
18432 this.labelPointStyles = labelPointStyles;
18433 this.labelTextColors = labelTextColors;
18434 this.dataPoints = tooltipItems;
18435 return tooltipItems;
18436 }
18437 update(changed, replay) {
18438 const options = this.options.setContext(this.getContext());
18439 const active = this._active;
18440 let properties;
18441 let tooltipItems = [];
18442 if (!active.length) {
18443 if (this.opacity !== 0) {
18444 properties = {
18445 opacity: 0
18446 };
18447 }
18448 } else {
18449 const position = positioners[options.position].call(this, active, this._eventPosition);
18450 tooltipItems = this._createItems(options);
18451 this.title = this.getTitle(tooltipItems, options);
18452 this.beforeBody = this.getBeforeBody(tooltipItems, options);
18453 this.body = this.getBody(tooltipItems, options);
18454 this.afterBody = this.getAfterBody(tooltipItems, options);
18455 this.footer = this.getFooter(tooltipItems, options);
18456 const size = this._size = getTooltipSize(this, options);
18457 const positionAndSize = Object.assign({}, position, size);
18458 const alignment = determineAlignment(this.chart, options, positionAndSize);
18459 const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
18460 this.xAlign = alignment.xAlign;
18461 this.yAlign = alignment.yAlign;
18462 properties = {
18463 opacity: 1,
18464 x: backgroundPoint.x,
18465 y: backgroundPoint.y,
18466 width: size.width,
18467 height: size.height,
18468 caretX: position.x,
18469 caretY: position.y
18470 };
18471 }
18472 this._tooltipItems = tooltipItems;
18473 this.$context = undefined;
18474 if (properties) {
18475 this._resolveAnimations().update(this, properties);
18476 }
18477 if (changed && options.external) {
18478 options.external.call(this, {
18479 chart: this.chart,
18480 tooltip: this,
18481 replay
18482 });
18483 }
18484 }
18485 drawCaret(tooltipPoint, ctx, size, options) {
18486 const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
18487 ctx.lineTo(caretPosition.x1, caretPosition.y1);
18488 ctx.lineTo(caretPosition.x2, caretPosition.y2);
18489 ctx.lineTo(caretPosition.x3, caretPosition.y3);
18490 }
18491 getCaretPosition(tooltipPoint, size, options) {
18492 const { xAlign , yAlign } = this;
18493 const { caretSize , cornerRadius } = options;
18494 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18495 const { x: ptX , y: ptY } = tooltipPoint;
18496 const { width , height } = size;
18497 let x1, x2, x3, y1, y2, y3;
18498 if (yAlign === 'center') {
18499 y2 = ptY + height / 2;
18500 if (xAlign === 'left') {
18501 x1 = ptX;
18502 x2 = x1 - caretSize;
18503 y1 = y2 + caretSize;
18504 y3 = y2 - caretSize;
18505 } else {
18506 x1 = ptX + width;
18507 x2 = x1 + caretSize;
18508 y1 = y2 - caretSize;
18509 y3 = y2 + caretSize;
18510 }
18511 x3 = x1;
18512 } else {
18513 if (xAlign === 'left') {
18514 x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;
18515 } else if (xAlign === 'right') {
18516 x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
18517 } else {
18518 x2 = this.caretX;
18519 }
18520 if (yAlign === 'top') {
18521 y1 = ptY;
18522 y2 = y1 - caretSize;
18523 x1 = x2 - caretSize;
18524 x3 = x2 + caretSize;
18525 } else {
18526 y1 = ptY + height;
18527 y2 = y1 + caretSize;
18528 x1 = x2 + caretSize;
18529 x3 = x2 - caretSize;
18530 }
18531 y3 = y1;
18532 }
18533 return {
18534 x1,
18535 x2,
18536 x3,
18537 y1,
18538 y2,
18539 y3
18540 };
18541 }
18542 drawTitle(pt, ctx, options) {
18543 const title = this.title;
18544 const length = title.length;
18545 let titleFont, titleSpacing, i;
18546 if (length) {
18547 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18548 pt.x = getAlignedX(this, options.titleAlign, options);
18549 ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
18550 ctx.textBaseline = 'middle';
18551 titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18552 titleSpacing = options.titleSpacing;
18553 ctx.fillStyle = options.titleColor;
18554 ctx.font = titleFont.string;
18555 for(i = 0; i < length; ++i){
18556 ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
18557 pt.y += titleFont.lineHeight + titleSpacing;
18558 if (i + 1 === length) {
18559 pt.y += options.titleMarginBottom - titleSpacing;
18560 }
18561 }
18562 }
18563 }
18564 _drawColorBox(ctx, pt, i, rtlHelper, options) {
18565 const labelColor = this.labelColors[i];
18566 const labelPointStyle = this.labelPointStyles[i];
18567 const { boxHeight , boxWidth } = options;
18568 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18569 const colorX = getAlignedX(this, 'left', options);
18570 const rtlColorX = rtlHelper.x(colorX);
18571 const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
18572 const colorY = pt.y + yOffSet;
18573 if (options.usePointStyle) {
18574 const drawOptions = {
18575 radius: Math.min(boxWidth, boxHeight) / 2,
18576 pointStyle: labelPointStyle.pointStyle,
18577 rotation: labelPointStyle.rotation,
18578 borderWidth: 1
18579 };
18580 const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
18581 const centerY = colorY + boxHeight / 2;
18582 ctx.strokeStyle = options.multiKeyBackground;
18583 ctx.fillStyle = options.multiKeyBackground;
18584 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18585 ctx.strokeStyle = labelColor.borderColor;
18586 ctx.fillStyle = labelColor.backgroundColor;
18587 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18588 } else {
18589 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;
18590 ctx.strokeStyle = labelColor.borderColor;
18591 ctx.setLineDash(labelColor.borderDash || []);
18592 ctx.lineDashOffset = labelColor.borderDashOffset || 0;
18593 const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);
18594 const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);
18595 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(labelColor.borderRadius);
18596 if (Object.values(borderRadius).some((v)=>v !== 0)) {
18597 ctx.beginPath();
18598 ctx.fillStyle = options.multiKeyBackground;
18599 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18600 x: outerX,
18601 y: colorY,
18602 w: boxWidth,
18603 h: boxHeight,
18604 radius: borderRadius
18605 });
18606 ctx.fill();
18607 ctx.stroke();
18608 ctx.fillStyle = labelColor.backgroundColor;
18609 ctx.beginPath();
18610 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18611 x: innerX,
18612 y: colorY + 1,
18613 w: boxWidth - 2,
18614 h: boxHeight - 2,
18615 radius: borderRadius
18616 });
18617 ctx.fill();
18618 } else {
18619 ctx.fillStyle = options.multiKeyBackground;
18620 ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
18621 ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
18622 ctx.fillStyle = labelColor.backgroundColor;
18623 ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
18624 }
18625 }
18626 ctx.fillStyle = this.labelTextColors[i];
18627 }
18628 drawBody(pt, ctx, options) {
18629 const { body } = this;
18630 const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options;
18631 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18632 let bodyLineHeight = bodyFont.lineHeight;
18633 let xLinePadding = 0;
18634 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18635 const fillLineOfText = function(line) {
18636 ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
18637 pt.y += bodyLineHeight + bodySpacing;
18638 };
18639 const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
18640 let bodyItem, textColor, lines, i, j, ilen, jlen;
18641 ctx.textAlign = bodyAlign;
18642 ctx.textBaseline = 'middle';
18643 ctx.font = bodyFont.string;
18644 pt.x = getAlignedX(this, bodyAlignForCalculation, options);
18645 ctx.fillStyle = options.bodyColor;
18646 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.beforeBody, fillLineOfText);
18647 xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;
18648 for(i = 0, ilen = body.length; i < ilen; ++i){
18649 bodyItem = body[i];
18650 textColor = this.labelTextColors[i];
18651 ctx.fillStyle = textColor;
18652 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, fillLineOfText);
18653 lines = bodyItem.lines;
18654 if (displayColors && lines.length) {
18655 this._drawColorBox(ctx, pt, i, rtlHelper, options);
18656 bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
18657 }
18658 for(j = 0, jlen = lines.length; j < jlen; ++j){
18659 fillLineOfText(lines[j]);
18660 bodyLineHeight = bodyFont.lineHeight;
18661 }
18662 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, fillLineOfText);
18663 }
18664 xLinePadding = 0;
18665 bodyLineHeight = bodyFont.lineHeight;
18666 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.afterBody, fillLineOfText);
18667 pt.y -= bodySpacing;
18668 }
18669 drawFooter(pt, ctx, options) {
18670 const footer = this.footer;
18671 const length = footer.length;
18672 let footerFont, i;
18673 if (length) {
18674 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18675 pt.x = getAlignedX(this, options.footerAlign, options);
18676 pt.y += options.footerMarginTop;
18677 ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
18678 ctx.textBaseline = 'middle';
18679 footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18680 ctx.fillStyle = options.footerColor;
18681 ctx.font = footerFont.string;
18682 for(i = 0; i < length; ++i){
18683 ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
18684 pt.y += footerFont.lineHeight + options.footerSpacing;
18685 }
18686 }
18687 }
18688 drawBackground(pt, ctx, tooltipSize, options) {
18689 const { xAlign , yAlign } = this;
18690 const { x , y } = pt;
18691 const { width , height } = tooltipSize;
18692 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(options.cornerRadius);
18693 ctx.fillStyle = options.backgroundColor;
18694 ctx.strokeStyle = options.borderColor;
18695 ctx.lineWidth = options.borderWidth;
18696 ctx.beginPath();
18697 ctx.moveTo(x + topLeft, y);
18698 if (yAlign === 'top') {
18699 this.drawCaret(pt, ctx, tooltipSize, options);
18700 }
18701 ctx.lineTo(x + width - topRight, y);
18702 ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
18703 if (yAlign === 'center' && xAlign === 'right') {
18704 this.drawCaret(pt, ctx, tooltipSize, options);
18705 }
18706 ctx.lineTo(x + width, y + height - bottomRight);
18707 ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
18708 if (yAlign === 'bottom') {
18709 this.drawCaret(pt, ctx, tooltipSize, options);
18710 }
18711 ctx.lineTo(x + bottomLeft, y + height);
18712 ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
18713 if (yAlign === 'center' && xAlign === 'left') {
18714 this.drawCaret(pt, ctx, tooltipSize, options);
18715 }
18716 ctx.lineTo(x, y + topLeft);
18717 ctx.quadraticCurveTo(x, y, x + topLeft, y);
18718 ctx.closePath();
18719 ctx.fill();
18720 if (options.borderWidth > 0) {
18721 ctx.stroke();
18722 }
18723 }
18724 _updateAnimationTarget(options) {
18725 const chart = this.chart;
18726 const anims = this.$animations;
18727 const animX = anims && anims.x;
18728 const animY = anims && anims.y;
18729 if (animX || animY) {
18730 const position = positioners[options.position].call(this, this._active, this._eventPosition);
18731 if (!position) {
18732 return;
18733 }
18734 const size = this._size = getTooltipSize(this, options);
18735 const positionAndSize = Object.assign({}, position, this._size);
18736 const alignment = determineAlignment(chart, options, positionAndSize);
18737 const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
18738 if (animX._to !== point.x || animY._to !== point.y) {
18739 this.xAlign = alignment.xAlign;
18740 this.yAlign = alignment.yAlign;
18741 this.width = size.width;
18742 this.height = size.height;
18743 this.caretX = position.x;
18744 this.caretY = position.y;
18745 this._resolveAnimations().update(this, point);
18746 }
18747 }
18748 }
18749 _willRender() {
18750 return !!this.opacity;
18751 }
18752 draw(ctx) {
18753 const options = this.options.setContext(this.getContext());
18754 let opacity = this.opacity;
18755 if (!opacity) {
18756 return;
18757 }
18758 this._updateAnimationTarget(options);
18759 const tooltipSize = {
18760 width: this.width,
18761 height: this.height
18762 };
18763 const pt = {
18764 x: this.x,
18765 y: this.y
18766 };
18767 opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
18768 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18769 const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
18770 if (options.enabled && hasTooltipContent) {
18771 ctx.save();
18772 ctx.globalAlpha = opacity;
18773 this.drawBackground(pt, ctx, tooltipSize, options);
18774 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(ctx, options.textDirection);
18775 pt.y += padding.top;
18776 this.drawTitle(pt, ctx, options);
18777 this.drawBody(pt, ctx, options);
18778 this.drawFooter(pt, ctx, options);
18779 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(ctx, options.textDirection);
18780 ctx.restore();
18781 }
18782 }
18783 getActiveElements() {
18784 return this._active || [];
18785 }
18786 setActiveElements(activeElements, eventPosition) {
18787 const lastActive = this._active;
18788 const active = activeElements.map(({ datasetIndex , index })=>{
18789 const meta = this.chart.getDatasetMeta(datasetIndex);
18790 if (!meta) {
18791 throw new Error('Cannot find a dataset at index ' + datasetIndex);
18792 }
18793 return {
18794 datasetIndex,
18795 element: meta.data[index],
18796 index
18797 };
18798 });
18799 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(lastActive, active);
18800 const positionChanged = this._positionChanged(active, eventPosition);
18801 if (changed || positionChanged) {
18802 this._active = active;
18803 this._eventPosition = eventPosition;
18804 this._ignoreReplayEvents = true;
18805 this.update(true);
18806 }
18807 }
18808 handleEvent(e, replay, inChartArea = true) {
18809 if (replay && this._ignoreReplayEvents) {
18810 return false;
18811 }
18812 this._ignoreReplayEvents = false;
18813 const options = this.options;
18814 const lastActive = this._active || [];
18815 const active = this._getActiveElements(e, lastActive, replay, inChartArea);
18816 const positionChanged = this._positionChanged(active, e);
18817 const changed = replay || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive) || positionChanged;
18818 if (changed) {
18819 this._active = active;
18820 if (options.enabled || options.external) {
18821 this._eventPosition = {
18822 x: e.x,
18823 y: e.y
18824 };
18825 this.update(true, replay);
18826 }
18827 }
18828 return changed;
18829 }
18830 _getActiveElements(e, lastActive, replay, inChartArea) {
18831 const options = this.options;
18832 if (e.type === 'mouseout') {
18833 return [];
18834 }
18835 if (!inChartArea) {
18836 return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined);
18837 }
18838 const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
18839 if (options.reverse) {
18840 active.reverse();
18841 }
18842 return active;
18843 }
18844 _positionChanged(active, e) {
18845 const { caretX , caretY , options } = this;
18846 const position = positioners[options.position].call(this, active, e);
18847 return position !== false && (caretX !== position.x || caretY !== position.y);
18848 }
18849 }
18850 var plugin_tooltip = {
18851 id: 'tooltip',
18852 _element: Tooltip,
18853 positioners,
18854 afterInit (chart, _args, options) {
18855 if (options) {
18856 chart.tooltip = new Tooltip({
18857 chart,
18858 options
18859 });
18860 }
18861 },
18862 beforeUpdate (chart, _args, options) {
18863 if (chart.tooltip) {
18864 chart.tooltip.initialize(options);
18865 }
18866 },
18867 reset (chart, _args, options) {
18868 if (chart.tooltip) {
18869 chart.tooltip.initialize(options);
18870 }
18871 },
18872 afterDraw (chart) {
18873 const tooltip = chart.tooltip;
18874 if (tooltip && tooltip._willRender()) {
18875 const args = {
18876 tooltip
18877 };
18878 if (chart.notifyPlugins('beforeTooltipDraw', {
18879 ...args,
18880 cancelable: true
18881 }) === false) {
18882 return;
18883 }
18884 tooltip.draw(chart.ctx);
18885 chart.notifyPlugins('afterTooltipDraw', args);
18886 }
18887 },
18888 afterEvent (chart, args) {
18889 if (chart.tooltip) {
18890 const useFinalPosition = args.replay;
18891 if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
18892 args.changed = true;
18893 }
18894 }
18895 },
18896 defaults: {
18897 enabled: true,
18898 external: null,
18899 position: 'average',
18900 backgroundColor: 'rgba(0,0,0,0.8)',
18901 titleColor: '#fff',
18902 titleFont: {
18903 weight: 'bold'
18904 },
18905 titleSpacing: 2,
18906 titleMarginBottom: 6,
18907 titleAlign: 'left',
18908 bodyColor: '#fff',
18909 bodySpacing: 2,
18910 bodyFont: {},
18911 bodyAlign: 'left',
18912 footerColor: '#fff',
18913 footerSpacing: 2,
18914 footerMarginTop: 6,
18915 footerFont: {
18916 weight: 'bold'
18917 },
18918 footerAlign: 'left',
18919 padding: 6,
18920 caretPadding: 2,
18921 caretSize: 5,
18922 cornerRadius: 6,
18923 boxHeight: (ctx, opts)=>opts.bodyFont.size,
18924 boxWidth: (ctx, opts)=>opts.bodyFont.size,
18925 multiKeyBackground: '#fff',
18926 displayColors: true,
18927 boxPadding: 0,
18928 borderColor: 'rgba(0,0,0,0)',
18929 borderWidth: 0,
18930 animation: {
18931 duration: 400,
18932 easing: 'easeOutQuart'
18933 },
18934 animations: {
18935 numbers: {
18936 type: 'number',
18937 properties: [
18938 'x',
18939 'y',
18940 'width',
18941 'height',
18942 'caretX',
18943 'caretY'
18944 ]
18945 },
18946 opacity: {
18947 easing: 'linear',
18948 duration: 200
18949 }
18950 },
18951 callbacks: defaultCallbacks
18952 },
18953 defaultRoutes: {
18954 bodyFont: 'font',
18955 footerFont: 'font',
18956 titleFont: 'font'
18957 },
18958 descriptors: {
18959 _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external',
18960 _indexable: false,
18961 callbacks: {
18962 _scriptable: false,
18963 _indexable: false
18964 },
18965 animation: {
18966 _fallback: false
18967 },
18968 animations: {
18969 _fallback: 'animation'
18970 }
18971 },
18972 additionalOptionScopes: [
18973 'interaction'
18974 ]
18975 };
18976
18977 var plugins = /*#__PURE__*/Object.freeze({
18978 __proto__: null,
18979 Colors: plugin_colors,
18980 Decimation: plugin_decimation,
18981 Filler: index,
18982 Legend: plugin_legend,
18983 SubTitle: plugin_subtitle,
18984 Title: plugin_title,
18985 Tooltip: plugin_tooltip
18986 });
18987
18988 const addIfString = (labels, raw, index, addedLabels)=>{
18989 if (typeof raw === 'string') {
18990 index = labels.push(raw) - 1;
18991 addedLabels.unshift({
18992 index,
18993 label: raw
18994 });
18995 } else if (isNaN(raw)) {
18996 index = null;
18997 }
18998 return index;
18999 };
19000 function findOrAddLabel(labels, raw, index, addedLabels) {
19001 const first = labels.indexOf(raw);
19002 if (first === -1) {
19003 return addIfString(labels, raw, index, addedLabels);
19004 }
19005 const last = labels.lastIndexOf(raw);
19006 return first !== last ? index : first;
19007 }
19008 const validIndex = (index, max)=>index === null ? null : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(Math.round(index), 0, max);
19009 function _getLabelForValue(value) {
19010 const labels = this.getLabels();
19011 if (value >= 0 && value < labels.length) {
19012 return labels[value];
19013 }
19014 return value;
19015 }
19016 class CategoryScale extends Scale {
19017 static id = 'category';
19018 static defaults = {
19019 ticks: {
19020 callback: _getLabelForValue
19021 }
19022 };
19023 constructor(cfg){
19024 super(cfg);
19025 this._startValue = undefined;
19026 this._valueRange = 0;
19027 this._addedLabels = [];
19028 }
19029 init(scaleOptions) {
19030 const added = this._addedLabels;
19031 if (added.length) {
19032 const labels = this.getLabels();
19033 for (const { index , label } of added){
19034 if (labels[index] === label) {
19035 labels.splice(index, 1);
19036 }
19037 }
19038 this._addedLabels = [];
19039 }
19040 super.init(scaleOptions);
19041 }
19042 parse(raw, index) {
19043 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19044 return null;
19045 }
19046 const labels = this.getLabels();
19047 index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(index, raw), this._addedLabels);
19048 return validIndex(index, labels.length - 1);
19049 }
19050 determineDataLimits() {
19051 const { minDefined , maxDefined } = this.getUserBounds();
19052 let { min , max } = this.getMinMax(true);
19053 if (this.options.bounds === 'ticks') {
19054 if (!minDefined) {
19055 min = 0;
19056 }
19057 if (!maxDefined) {
19058 max = this.getLabels().length - 1;
19059 }
19060 }
19061 this.min = min;
19062 this.max = max;
19063 }
19064 buildTicks() {
19065 const min = this.min;
19066 const max = this.max;
19067 const offset = this.options.offset;
19068 const ticks = [];
19069 let labels = this.getLabels();
19070 labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);
19071 this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
19072 this._startValue = this.min - (offset ? 0.5 : 0);
19073 for(let value = min; value <= max; value++){
19074 ticks.push({
19075 value
19076 });
19077 }
19078 return ticks;
19079 }
19080 getLabelForValue(value) {
19081 return _getLabelForValue.call(this, value);
19082 }
19083 configure() {
19084 super.configure();
19085 if (!this.isHorizontal()) {
19086 this._reversePixels = !this._reversePixels;
19087 }
19088 }
19089 getPixelForValue(value) {
19090 if (typeof value !== 'number') {
19091 value = this.parse(value);
19092 }
19093 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19094 }
19095 getPixelForTick(index) {
19096 const ticks = this.ticks;
19097 if (index < 0 || index > ticks.length - 1) {
19098 return null;
19099 }
19100 return this.getPixelForValue(ticks[index].value);
19101 }
19102 getValueForPixel(pixel) {
19103 return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
19104 }
19105 getBasePixel() {
19106 return this.bottom;
19107 }
19108 }
19109
19110 function generateTicks$1(generationOptions, dataRange) {
19111 const ticks = [];
19112 const MIN_SPACING = 1e-14;
19113 const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions;
19114 const unit = step || 1;
19115 const maxSpaces = maxTicks - 1;
19116 const { min: rmin , max: rmax } = dataRange;
19117 const minDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(min);
19118 const maxDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(max);
19119 const countDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(count);
19120 const minSpacing = (rmax - rmin) / (maxDigits + 1);
19121 let spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)((rmax - rmin) / maxSpaces / unit) * unit;
19122 let factor, niceMin, niceMax, numSpaces;
19123 if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
19124 return [
19125 {
19126 value: rmin
19127 },
19128 {
19129 value: rmax
19130 }
19131 ];
19132 }
19133 numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
19134 if (numSpaces > maxSpaces) {
19135 spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)(numSpaces * spacing / maxSpaces / unit) * unit;
19136 }
19137 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision)) {
19138 factor = Math.pow(10, precision);
19139 spacing = Math.ceil(spacing * factor) / factor;
19140 }
19141 if (bounds === 'ticks') {
19142 niceMin = Math.floor(rmin / spacing) * spacing;
19143 niceMax = Math.ceil(rmax / spacing) * spacing;
19144 } else {
19145 niceMin = rmin;
19146 niceMax = rmax;
19147 }
19148 if (minDefined && maxDefined && step && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aJ)((max - min) / step, spacing / 1000)) {
19149 numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
19150 spacing = (max - min) / numSpaces;
19151 niceMin = min;
19152 niceMax = max;
19153 } else if (countDefined) {
19154 niceMin = minDefined ? min : niceMin;
19155 niceMax = maxDefined ? max : niceMax;
19156 numSpaces = count - 1;
19157 spacing = (niceMax - niceMin) / numSpaces;
19158 } else {
19159 numSpaces = (niceMax - niceMin) / spacing;
19160 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(numSpaces, Math.round(numSpaces), spacing / 1000)) {
19161 numSpaces = Math.round(numSpaces);
19162 } else {
19163 numSpaces = Math.ceil(numSpaces);
19164 }
19165 }
19166 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));
19167 factor = Math.pow(10, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision) ? decimalPlaces : precision);
19168 niceMin = Math.round(niceMin * factor) / factor;
19169 niceMax = Math.round(niceMax * factor) / factor;
19170 let j = 0;
19171 if (minDefined) {
19172 if (includeBounds && niceMin !== min) {
19173 ticks.push({
19174 value: min
19175 });
19176 if (niceMin < min) {
19177 j++;
19178 }
19179 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
19180 j++;
19181 }
19182 } else if (niceMin < min) {
19183 j++;
19184 }
19185 }
19186 for(; j < numSpaces; ++j){
19187 const tickValue = Math.round((niceMin + j * spacing) * factor) / factor;
19188 if (maxDefined && tickValue > max) {
19189 break;
19190 }
19191 ticks.push({
19192 value: tickValue
19193 });
19194 }
19195 if (maxDefined && includeBounds && niceMax !== max) {
19196 if (ticks.length && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
19197 ticks[ticks.length - 1].value = max;
19198 } else {
19199 ticks.push({
19200 value: max
19201 });
19202 }
19203 } else if (!maxDefined || niceMax === max) {
19204 ticks.push({
19205 value: niceMax
19206 });
19207 }
19208 return ticks;
19209 }
19210 function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) {
19211 const rad = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(minRotation);
19212 const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;
19213 const length = 0.75 * minSpacing * ('' + value).length;
19214 return Math.min(minSpacing / ratio, length);
19215 }
19216 class LinearScaleBase extends Scale {
19217 constructor(cfg){
19218 super(cfg);
19219 this.start = undefined;
19220 this.end = undefined;
19221 this._startValue = undefined;
19222 this._endValue = undefined;
19223 this._valueRange = 0;
19224 }
19225 parse(raw, index) {
19226 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19227 return null;
19228 }
19229 if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
19230 return null;
19231 }
19232 return +raw;
19233 }
19234 handleTickRangeOptions() {
19235 const { beginAtZero } = this.options;
19236 const { minDefined , maxDefined } = this.getUserBounds();
19237 let { min , max } = this;
19238 const setMin = (v)=>min = minDefined ? min : v;
19239 const setMax = (v)=>max = maxDefined ? max : v;
19240 if (beginAtZero) {
19241 const minSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(min);
19242 const maxSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(max);
19243 if (minSign < 0 && maxSign < 0) {
19244 setMax(0);
19245 } else if (minSign > 0 && maxSign > 0) {
19246 setMin(0);
19247 }
19248 }
19249 if (min === max) {
19250 let offset = max === 0 ? 1 : Math.abs(max * 0.05);
19251 setMax(max + offset);
19252 if (!beginAtZero) {
19253 setMin(min - offset);
19254 }
19255 }
19256 this.min = min;
19257 this.max = max;
19258 }
19259 getTickLimit() {
19260 const tickOpts = this.options.ticks;
19261 let { maxTicksLimit , stepSize } = tickOpts;
19262 let maxTicks;
19263 if (stepSize) {
19264 maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
19265 if (maxTicks > 1000) {
19266 console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
19267 maxTicks = 1000;
19268 }
19269 } else {
19270 maxTicks = this.computeTickLimit();
19271 maxTicksLimit = maxTicksLimit || 11;
19272 }
19273 if (maxTicksLimit) {
19274 maxTicks = Math.min(maxTicksLimit, maxTicks);
19275 }
19276 return maxTicks;
19277 }
19278 computeTickLimit() {
19279 return Number.POSITIVE_INFINITY;
19280 }
19281 buildTicks() {
19282 const opts = this.options;
19283 const tickOpts = opts.ticks;
19284 let maxTicks = this.getTickLimit();
19285 maxTicks = Math.max(2, maxTicks);
19286 const numericGeneratorOptions = {
19287 maxTicks,
19288 bounds: opts.bounds,
19289 min: opts.min,
19290 max: opts.max,
19291 precision: tickOpts.precision,
19292 step: tickOpts.stepSize,
19293 count: tickOpts.count,
19294 maxDigits: this._maxDigits(),
19295 horizontal: this.isHorizontal(),
19296 minRotation: tickOpts.minRotation || 0,
19297 includeBounds: tickOpts.includeBounds !== false
19298 };
19299 const dataRange = this._range || this;
19300 const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
19301 if (opts.bounds === 'ticks') {
19302 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19303 }
19304 if (opts.reverse) {
19305 ticks.reverse();
19306 this.start = this.max;
19307 this.end = this.min;
19308 } else {
19309 this.start = this.min;
19310 this.end = this.max;
19311 }
19312 return ticks;
19313 }
19314 configure() {
19315 const ticks = this.ticks;
19316 let start = this.min;
19317 let end = this.max;
19318 super.configure();
19319 if (this.options.offset && ticks.length) {
19320 const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
19321 start -= offset;
19322 end += offset;
19323 }
19324 this._startValue = start;
19325 this._endValue = end;
19326 this._valueRange = end - start;
19327 }
19328 getLabelForValue(value) {
19329 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19330 }
19331 }
19332
19333 class LinearScale extends LinearScaleBase {
19334 static id = 'linear';
19335 static defaults = {
19336 ticks: {
19337 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19338 }
19339 };
19340 determineDataLimits() {
19341 const { min , max } = this.getMinMax(true);
19342 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? min : 0;
19343 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? max : 1;
19344 this.handleTickRangeOptions();
19345 }
19346 computeTickLimit() {
19347 const horizontal = this.isHorizontal();
19348 const length = horizontal ? this.width : this.height;
19349 const minRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.ticks.minRotation);
19350 const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;
19351 const tickFont = this._resolveTickFontOptions(0);
19352 return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
19353 }
19354 getPixelForValue(value) {
19355 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19356 }
19357 getValueForPixel(pixel) {
19358 return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
19359 }
19360 }
19361
19362 const log10Floor = (v)=>Math.floor((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(v));
19363 const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m);
19364 function isMajor(tickVal) {
19365 const remain = tickVal / Math.pow(10, log10Floor(tickVal));
19366 return remain === 1;
19367 }
19368 function steps(min, max, rangeExp) {
19369 const rangeStep = Math.pow(10, rangeExp);
19370 const start = Math.floor(min / rangeStep);
19371 const end = Math.ceil(max / rangeStep);
19372 return end - start;
19373 }
19374 function startExp(min, max) {
19375 const range = max - min;
19376 let rangeExp = log10Floor(range);
19377 while(steps(min, max, rangeExp) > 10){
19378 rangeExp++;
19379 }
19380 while(steps(min, max, rangeExp) < 10){
19381 rangeExp--;
19382 }
19383 return Math.min(rangeExp, log10Floor(min));
19384 }
19385 function generateTicks(generationOptions, { min , max }) {
19386 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, min);
19387 const ticks = [];
19388 const minExp = log10Floor(min);
19389 let exp = startExp(min, max);
19390 let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
19391 const stepSize = Math.pow(10, exp);
19392 const base = minExp > exp ? Math.pow(10, minExp) : 0;
19393 const start = Math.round((min - base) * precision) / precision;
19394 const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;
19395 let significand = Math.floor((start - offset) / Math.pow(10, exp));
19396 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);
19397 while(value < max){
19398 ticks.push({
19399 value,
19400 major: isMajor(value),
19401 significand
19402 });
19403 if (significand >= 10) {
19404 significand = significand < 15 ? 15 : 20;
19405 } else {
19406 significand++;
19407 }
19408 if (significand >= 20) {
19409 exp++;
19410 significand = 2;
19411 precision = exp >= 0 ? 1 : precision;
19412 }
19413 value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;
19414 }
19415 const lastTick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.max, value);
19416 ticks.push({
19417 value: lastTick,
19418 major: isMajor(lastTick),
19419 significand
19420 });
19421 return ticks;
19422 }
19423 class LogarithmicScale extends Scale {
19424 static id = 'logarithmic';
19425 static defaults = {
19426 ticks: {
19427 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.logarithmic,
19428 major: {
19429 enabled: true
19430 }
19431 }
19432 };
19433 constructor(cfg){
19434 super(cfg);
19435 this.start = undefined;
19436 this.end = undefined;
19437 this._startValue = undefined;
19438 this._valueRange = 0;
19439 }
19440 parse(raw, index) {
19441 const value = LinearScaleBase.prototype.parse.apply(this, [
19442 raw,
19443 index
19444 ]);
19445 if (value === 0) {
19446 this._zero = true;
19447 return undefined;
19448 }
19449 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value) && value > 0 ? value : null;
19450 }
19451 determineDataLimits() {
19452 const { min , max } = this.getMinMax(true);
19453 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? Math.max(0, min) : null;
19454 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? Math.max(0, max) : null;
19455 if (this.options.beginAtZero) {
19456 this._zero = true;
19457 }
19458 if (this._zero && this.min !== this._suggestedMin && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(this._userMin)) {
19459 this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);
19460 }
19461 this.handleTickRangeOptions();
19462 }
19463 handleTickRangeOptions() {
19464 const { minDefined , maxDefined } = this.getUserBounds();
19465 let min = this.min;
19466 let max = this.max;
19467 const setMin = (v)=>min = minDefined ? min : v;
19468 const setMax = (v)=>max = maxDefined ? max : v;
19469 if (min === max) {
19470 if (min <= 0) {
19471 setMin(1);
19472 setMax(10);
19473 } else {
19474 setMin(changeExponent(min, -1));
19475 setMax(changeExponent(max, +1));
19476 }
19477 }
19478 if (min <= 0) {
19479 setMin(changeExponent(max, -1));
19480 }
19481 if (max <= 0) {
19482 setMax(changeExponent(min, +1));
19483 }
19484 this.min = min;
19485 this.max = max;
19486 }
19487 buildTicks() {
19488 const opts = this.options;
19489 const generationOptions = {
19490 min: this._userMin,
19491 max: this._userMax
19492 };
19493 const ticks = generateTicks(generationOptions, this);
19494 if (opts.bounds === 'ticks') {
19495 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19496 }
19497 if (opts.reverse) {
19498 ticks.reverse();
19499 this.start = this.max;
19500 this.end = this.min;
19501 } else {
19502 this.start = this.min;
19503 this.end = this.max;
19504 }
19505 return ticks;
19506 }
19507 getLabelForValue(value) {
19508 return value === undefined ? '0' : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19509 }
19510 configure() {
19511 const start = this.min;
19512 super.configure();
19513 this._startValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start);
19514 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);
19515 }
19516 getPixelForValue(value) {
19517 if (value === undefined || value === 0) {
19518 value = this.min;
19519 }
19520 if (value === null || isNaN(value)) {
19521 return NaN;
19522 }
19523 return this.getPixelForDecimal(value === this.min ? 0 : ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(value) - this._startValue) / this._valueRange);
19524 }
19525 getValueForPixel(pixel) {
19526 const decimal = this.getDecimalForPixel(pixel);
19527 return Math.pow(10, this._startValue + decimal * this._valueRange);
19528 }
19529 }
19530
19531 function getTickBackdropHeight(opts) {
19532 const tickOpts = opts.ticks;
19533 if (tickOpts.display && opts.display) {
19534 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(tickOpts.backdropPadding);
19535 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;
19536 }
19537 return 0;
19538 }
19539 function measureLabelSize(ctx, font, label) {
19540 label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label : [
19541 label
19542 ];
19543 return {
19544 w: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aO)(ctx, font.string, label),
19545 h: label.length * font.lineHeight
19546 };
19547 }
19548 function determineLimits(angle, pos, size, min, max) {
19549 if (angle === min || angle === max) {
19550 return {
19551 start: pos - size / 2,
19552 end: pos + size / 2
19553 };
19554 } else if (angle < min || angle > max) {
19555 return {
19556 start: pos - size,
19557 end: pos
19558 };
19559 }
19560 return {
19561 start: pos,
19562 end: pos + size
19563 };
19564 }
19565 function fitWithPointLabels(scale) {
19566 const orig = {
19567 l: scale.left + scale._padding.left,
19568 r: scale.right - scale._padding.right,
19569 t: scale.top + scale._padding.top,
19570 b: scale.bottom - scale._padding.bottom
19571 };
19572 const limits = Object.assign({}, orig);
19573 const labelSizes = [];
19574 const padding = [];
19575 const valueCount = scale._pointLabels.length;
19576 const pointLabelOpts = scale.options.pointLabels;
19577 const additionalAngle = pointLabelOpts.centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0;
19578 for(let i = 0; i < valueCount; i++){
19579 const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
19580 padding[i] = opts.padding;
19581 const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
19582 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
19583 const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
19584 labelSizes[i] = textSize;
19585 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(scale.getIndexAngle(i) + additionalAngle);
19586 const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(angleRadians));
19587 const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
19588 const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
19589 updateLimits(limits, orig, angleRadians, hLimits, vLimits);
19590 }
19591 scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);
19592 scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
19593 }
19594 function updateLimits(limits, orig, angle, hLimits, vLimits) {
19595 const sin = Math.abs(Math.sin(angle));
19596 const cos = Math.abs(Math.cos(angle));
19597 let x = 0;
19598 let y = 0;
19599 if (hLimits.start < orig.l) {
19600 x = (orig.l - hLimits.start) / sin;
19601 limits.l = Math.min(limits.l, orig.l - x);
19602 } else if (hLimits.end > orig.r) {
19603 x = (hLimits.end - orig.r) / sin;
19604 limits.r = Math.max(limits.r, orig.r + x);
19605 }
19606 if (vLimits.start < orig.t) {
19607 y = (orig.t - vLimits.start) / cos;
19608 limits.t = Math.min(limits.t, orig.t - y);
19609 } else if (vLimits.end > orig.b) {
19610 y = (vLimits.end - orig.b) / cos;
19611 limits.b = Math.max(limits.b, orig.b + y);
19612 }
19613 }
19614 function createPointLabelItem(scale, index, itemOpts) {
19615 const outerDistance = scale.drawingArea;
19616 const { extra , additionalAngle , padding , size } = itemOpts;
19617 const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);
19618 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)));
19619 const y = yForAngle(pointLabelPosition.y, size.h, angle);
19620 const textAlign = getTextAlignForAngle(angle);
19621 const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
19622 return {
19623 visible: true,
19624 x: pointLabelPosition.x,
19625 y,
19626 textAlign,
19627 left,
19628 top: y,
19629 right: left + size.w,
19630 bottom: y + size.h
19631 };
19632 }
19633 function isNotOverlapped(item, area) {
19634 if (!area) {
19635 return true;
19636 }
19637 const { left , top , right , bottom } = item;
19638 const apexesInArea = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19639 x: left,
19640 y: top
19641 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19642 x: left,
19643 y: bottom
19644 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19645 x: right,
19646 y: top
19647 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19648 x: right,
19649 y: bottom
19650 }, area);
19651 return !apexesInArea;
19652 }
19653 function buildPointLabelItems(scale, labelSizes, padding) {
19654 const items = [];
19655 const valueCount = scale._pointLabels.length;
19656 const opts = scale.options;
19657 const { centerPointLabels , display } = opts.pointLabels;
19658 const itemOpts = {
19659 extra: getTickBackdropHeight(opts) / 2,
19660 additionalAngle: centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0
19661 };
19662 let area;
19663 for(let i = 0; i < valueCount; i++){
19664 itemOpts.padding = padding[i];
19665 itemOpts.size = labelSizes[i];
19666 const item = createPointLabelItem(scale, i, itemOpts);
19667 items.push(item);
19668 if (display === 'auto') {
19669 item.visible = isNotOverlapped(item, area);
19670 if (item.visible) {
19671 area = item;
19672 }
19673 }
19674 }
19675 return items;
19676 }
19677 function getTextAlignForAngle(angle) {
19678 if (angle === 0 || angle === 180) {
19679 return 'center';
19680 } else if (angle < 180) {
19681 return 'left';
19682 }
19683 return 'right';
19684 }
19685 function leftForTextAlign(x, w, align) {
19686 if (align === 'right') {
19687 x -= w;
19688 } else if (align === 'center') {
19689 x -= w / 2;
19690 }
19691 return x;
19692 }
19693 function yForAngle(y, h, angle) {
19694 if (angle === 90 || angle === 270) {
19695 y -= h / 2;
19696 } else if (angle > 270 || angle < 90) {
19697 y -= h;
19698 }
19699 return y;
19700 }
19701 function drawPointLabelBox(ctx, opts, item) {
19702 const { left , top , right , bottom } = item;
19703 const { backdropColor } = opts;
19704 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(backdropColor)) {
19705 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(opts.borderRadius);
19706 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.backdropPadding);
19707 ctx.fillStyle = backdropColor;
19708 const backdropLeft = left - padding.left;
19709 const backdropTop = top - padding.top;
19710 const backdropWidth = right - left + padding.width;
19711 const backdropHeight = bottom - top + padding.height;
19712 if (Object.values(borderRadius).some((v)=>v !== 0)) {
19713 ctx.beginPath();
19714 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
19715 x: backdropLeft,
19716 y: backdropTop,
19717 w: backdropWidth,
19718 h: backdropHeight,
19719 radius: borderRadius
19720 });
19721 ctx.fill();
19722 } else {
19723 ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);
19724 }
19725 }
19726 }
19727 function drawPointLabels(scale, labelCount) {
19728 const { ctx , options: { pointLabels } } = scale;
19729 for(let i = labelCount - 1; i >= 0; i--){
19730 const item = scale._pointLabelItems[i];
19731 if (!item.visible) {
19732 continue;
19733 }
19734 const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));
19735 drawPointLabelBox(ctx, optsAtIndex, item);
19736 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
19737 const { x , y , textAlign } = item;
19738 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, {
19739 color: optsAtIndex.color,
19740 textAlign: textAlign,
19741 textBaseline: 'middle'
19742 });
19743 }
19744 }
19745 function pathRadiusLine(scale, radius, circular, labelCount) {
19746 const { ctx } = scale;
19747 if (circular) {
19748 ctx.arc(scale.xCenter, scale.yCenter, radius, 0, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
19749 } else {
19750 let pointPosition = scale.getPointPosition(0, radius);
19751 ctx.moveTo(pointPosition.x, pointPosition.y);
19752 for(let i = 1; i < labelCount; i++){
19753 pointPosition = scale.getPointPosition(i, radius);
19754 ctx.lineTo(pointPosition.x, pointPosition.y);
19755 }
19756 }
19757 }
19758 function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {
19759 const ctx = scale.ctx;
19760 const circular = gridLineOpts.circular;
19761 const { color , lineWidth } = gridLineOpts;
19762 if (!circular && !labelCount || !color || !lineWidth || radius < 0) {
19763 return;
19764 }
19765 ctx.save();
19766 ctx.strokeStyle = color;
19767 ctx.lineWidth = lineWidth;
19768 ctx.setLineDash(borderOpts.dash || []);
19769 ctx.lineDashOffset = borderOpts.dashOffset;
19770 ctx.beginPath();
19771 pathRadiusLine(scale, radius, circular, labelCount);
19772 ctx.closePath();
19773 ctx.stroke();
19774 ctx.restore();
19775 }
19776 function createPointLabelContext(parent, index, label) {
19777 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
19778 label,
19779 index,
19780 type: 'pointLabel'
19781 });
19782 }
19783 class RadialLinearScale extends LinearScaleBase {
19784 static id = 'radialLinear';
19785 static defaults = {
19786 display: true,
19787 animate: true,
19788 position: 'chartArea',
19789 angleLines: {
19790 display: true,
19791 lineWidth: 1,
19792 borderDash: [],
19793 borderDashOffset: 0.0
19794 },
19795 grid: {
19796 circular: false
19797 },
19798 startAngle: 0,
19799 ticks: {
19800 showLabelBackdrop: true,
19801 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19802 },
19803 pointLabels: {
19804 backdropColor: undefined,
19805 backdropPadding: 2,
19806 display: true,
19807 font: {
19808 size: 10
19809 },
19810 callback (label) {
19811 return label;
19812 },
19813 padding: 5,
19814 centerPointLabels: false
19815 }
19816 };
19817 static defaultRoutes = {
19818 'angleLines.color': 'borderColor',
19819 'pointLabels.color': 'color',
19820 'ticks.color': 'color'
19821 };
19822 static descriptors = {
19823 angleLines: {
19824 _fallback: 'grid'
19825 }
19826 };
19827 constructor(cfg){
19828 super(cfg);
19829 this.xCenter = undefined;
19830 this.yCenter = undefined;
19831 this.drawingArea = undefined;
19832 this._pointLabels = [];
19833 this._pointLabelItems = [];
19834 }
19835 setDimensions() {
19836 const padding = this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(getTickBackdropHeight(this.options) / 2);
19837 const w = this.width = this.maxWidth - padding.width;
19838 const h = this.height = this.maxHeight - padding.height;
19839 this.xCenter = Math.floor(this.left + w / 2 + padding.left);
19840 this.yCenter = Math.floor(this.top + h / 2 + padding.top);
19841 this.drawingArea = Math.floor(Math.min(w, h) / 2);
19842 }
19843 determineDataLimits() {
19844 const { min , max } = this.getMinMax(false);
19845 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : 0;
19846 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : 0;
19847 this.handleTickRangeOptions();
19848 }
19849 computeTickLimit() {
19850 return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
19851 }
19852 generateTickLabels(ticks) {
19853 LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
19854 this._pointLabels = this.getLabels().map((value, index)=>{
19855 const label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.pointLabels.callback, [
19856 value,
19857 index
19858 ], this);
19859 return label || label === 0 ? label : '';
19860 }).filter((v, i)=>this.chart.getDataVisibility(i));
19861 }
19862 fit() {
19863 const opts = this.options;
19864 if (opts.display && opts.pointLabels.display) {
19865 fitWithPointLabels(this);
19866 } else {
19867 this.setCenterPoint(0, 0, 0, 0);
19868 }
19869 }
19870 setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
19871 this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
19872 this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
19873 this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
19874 }
19875 getIndexAngle(index) {
19876 const angleMultiplier = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T / (this._pointLabels.length || 1);
19877 const startAngle = this.options.startAngle || 0;
19878 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(index * angleMultiplier + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(startAngle));
19879 }
19880 getDistanceFromCenterForValue(value) {
19881 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
19882 return NaN;
19883 }
19884 const scalingFactor = this.drawingArea / (this.max - this.min);
19885 if (this.options.reverse) {
19886 return (this.max - value) * scalingFactor;
19887 }
19888 return (value - this.min) * scalingFactor;
19889 }
19890 getValueForDistanceFromCenter(distance) {
19891 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(distance)) {
19892 return NaN;
19893 }
19894 const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
19895 return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
19896 }
19897 getPointLabelContext(index) {
19898 const pointLabels = this._pointLabels || [];
19899 if (index >= 0 && index < pointLabels.length) {
19900 const pointLabel = pointLabels[index];
19901 return createPointLabelContext(this.getContext(), index, pointLabel);
19902 }
19903 }
19904 getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
19905 const angle = this.getIndexAngle(index) - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H + additionalAngle;
19906 return {
19907 x: Math.cos(angle) * distanceFromCenter + this.xCenter,
19908 y: Math.sin(angle) * distanceFromCenter + this.yCenter,
19909 angle
19910 };
19911 }
19912 getPointPositionForValue(index, value) {
19913 return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
19914 }
19915 getBasePosition(index) {
19916 return this.getPointPositionForValue(index || 0, this.getBaseValue());
19917 }
19918 getPointLabelPosition(index) {
19919 const { left , top , right , bottom } = this._pointLabelItems[index];
19920 return {
19921 left,
19922 top,
19923 right,
19924 bottom
19925 };
19926 }
19927 drawBackground() {
19928 const { backgroundColor , grid: { circular } } = this.options;
19929 if (backgroundColor) {
19930 const ctx = this.ctx;
19931 ctx.save();
19932 ctx.beginPath();
19933 pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
19934 ctx.closePath();
19935 ctx.fillStyle = backgroundColor;
19936 ctx.fill();
19937 ctx.restore();
19938 }
19939 }
19940 drawGrid() {
19941 const ctx = this.ctx;
19942 const opts = this.options;
19943 const { angleLines , grid , border } = opts;
19944 const labelCount = this._pointLabels.length;
19945 let i, offset, position;
19946 if (opts.pointLabels.display) {
19947 drawPointLabels(this, labelCount);
19948 }
19949 if (grid.display) {
19950 this.ticks.forEach((tick, index)=>{
19951 if (index !== 0 || index === 0 && this.min < 0) {
19952 offset = this.getDistanceFromCenterForValue(tick.value);
19953 const context = this.getContext(index);
19954 const optsAtIndex = grid.setContext(context);
19955 const optsAtIndexBorder = border.setContext(context);
19956 drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);
19957 }
19958 });
19959 }
19960 if (angleLines.display) {
19961 ctx.save();
19962 for(i = labelCount - 1; i >= 0; i--){
19963 const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
19964 const { color , lineWidth } = optsAtIndex;
19965 if (!lineWidth || !color) {
19966 continue;
19967 }
19968 ctx.lineWidth = lineWidth;
19969 ctx.strokeStyle = color;
19970 ctx.setLineDash(optsAtIndex.borderDash);
19971 ctx.lineDashOffset = optsAtIndex.borderDashOffset;
19972 offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);
19973 position = this.getPointPosition(i, offset);
19974 ctx.beginPath();
19975 ctx.moveTo(this.xCenter, this.yCenter);
19976 ctx.lineTo(position.x, position.y);
19977 ctx.stroke();
19978 }
19979 ctx.restore();
19980 }
19981 }
19982 drawBorder() {}
19983 drawLabels() {
19984 const ctx = this.ctx;
19985 const opts = this.options;
19986 const tickOpts = opts.ticks;
19987 if (!tickOpts.display) {
19988 return;
19989 }
19990 const startAngle = this.getIndexAngle(0);
19991 let offset, width;
19992 ctx.save();
19993 ctx.translate(this.xCenter, this.yCenter);
19994 ctx.rotate(startAngle);
19995 ctx.textAlign = 'center';
19996 ctx.textBaseline = 'middle';
19997 this.ticks.forEach((tick, index)=>{
19998 if (index === 0 && this.min >= 0 && !opts.reverse) {
19999 return;
20000 }
20001 const optsAtIndex = tickOpts.setContext(this.getContext(index));
20002 const tickFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
20003 offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
20004 if (optsAtIndex.showLabelBackdrop) {
20005 ctx.font = tickFont.string;
20006 width = ctx.measureText(tick.label).width;
20007 ctx.fillStyle = optsAtIndex.backdropColor;
20008 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
20009 ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);
20010 }
20011 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, tick.label, 0, -offset, tickFont, {
20012 color: optsAtIndex.color,
20013 strokeColor: optsAtIndex.textStrokeColor,
20014 strokeWidth: optsAtIndex.textStrokeWidth
20015 });
20016 });
20017 ctx.restore();
20018 }
20019 drawTitle() {}
20020 }
20021
20022 const INTERVALS = {
20023 millisecond: {
20024 common: true,
20025 size: 1,
20026 steps: 1000
20027 },
20028 second: {
20029 common: true,
20030 size: 1000,
20031 steps: 60
20032 },
20033 minute: {
20034 common: true,
20035 size: 60000,
20036 steps: 60
20037 },
20038 hour: {
20039 common: true,
20040 size: 3600000,
20041 steps: 24
20042 },
20043 day: {
20044 common: true,
20045 size: 86400000,
20046 steps: 30
20047 },
20048 week: {
20049 common: false,
20050 size: 604800000,
20051 steps: 4
20052 },
20053 month: {
20054 common: true,
20055 size: 2.628e9,
20056 steps: 12
20057 },
20058 quarter: {
20059 common: false,
20060 size: 7.884e9,
20061 steps: 4
20062 },
20063 year: {
20064 common: true,
20065 size: 3.154e10
20066 }
20067 };
20068 const UNITS = /* #__PURE__ */ Object.keys(INTERVALS);
20069 function sorter(a, b) {
20070 return a - b;
20071 }
20072 function parse(scale, input) {
20073 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(input)) {
20074 return null;
20075 }
20076 const adapter = scale._adapter;
20077 const { parser , round , isoWeekday } = scale._parseOpts;
20078 let value = input;
20079 if (typeof parser === 'function') {
20080 value = parser(value);
20081 }
20082 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
20083 value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value);
20084 }
20085 if (value === null) {
20086 return null;
20087 }
20088 if (round) {
20089 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);
20090 }
20091 return +value;
20092 }
20093 function determineUnitForAutoTicks(minUnit, min, max, capacity) {
20094 const ilen = UNITS.length;
20095 for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){
20096 const interval = INTERVALS[UNITS[i]];
20097 const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
20098 if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
20099 return UNITS[i];
20100 }
20101 }
20102 return UNITS[ilen - 1];
20103 }
20104 function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
20105 for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){
20106 const unit = UNITS[i];
20107 if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
20108 return unit;
20109 }
20110 }
20111 return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
20112 }
20113 function determineMajorUnit(unit) {
20114 for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){
20115 if (INTERVALS[UNITS[i]].common) {
20116 return UNITS[i];
20117 }
20118 }
20119 }
20120 function addTick(ticks, time, timestamps) {
20121 if (!timestamps) {
20122 ticks[time] = true;
20123 } else if (timestamps.length) {
20124 const { lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aQ)(timestamps, time);
20125 const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
20126 ticks[timestamp] = true;
20127 }
20128 }
20129 function setMajorTicks(scale, ticks, map, majorUnit) {
20130 const adapter = scale._adapter;
20131 const first = +adapter.startOf(ticks[0].value, majorUnit);
20132 const last = ticks[ticks.length - 1].value;
20133 let major, index;
20134 for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){
20135 index = map[major];
20136 if (index >= 0) {
20137 ticks[index].major = true;
20138 }
20139 }
20140 return ticks;
20141 }
20142 function ticksFromTimestamps(scale, values, majorUnit) {
20143 const ticks = [];
20144 const map = {};
20145 const ilen = values.length;
20146 let i, value;
20147 for(i = 0; i < ilen; ++i){
20148 value = values[i];
20149 map[value] = i;
20150 ticks.push({
20151 value,
20152 major: false
20153 });
20154 }
20155 return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
20156 }
20157 class TimeScale extends Scale {
20158 static id = 'time';
20159 static defaults = {
20160 bounds: 'data',
20161 adapters: {},
20162 time: {
20163 parser: false,
20164 unit: false,
20165 round: false,
20166 isoWeekday: false,
20167 minUnit: 'millisecond',
20168 displayFormats: {}
20169 },
20170 ticks: {
20171 source: 'auto',
20172 callback: false,
20173 major: {
20174 enabled: false
20175 }
20176 }
20177 };
20178 constructor(props){
20179 super(props);
20180 this._cache = {
20181 data: [],
20182 labels: [],
20183 all: []
20184 };
20185 this._unit = 'day';
20186 this._majorUnit = undefined;
20187 this._offsets = {};
20188 this._normalized = false;
20189 this._parseOpts = undefined;
20190 }
20191 init(scaleOpts, opts = {}) {
20192 const time = scaleOpts.time || (scaleOpts.time = {});
20193 const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
20194 adapter.init(opts);
20195 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(time.displayFormats, adapter.formats());
20196 this._parseOpts = {
20197 parser: time.parser,
20198 round: time.round,
20199 isoWeekday: time.isoWeekday
20200 };
20201 super.init(scaleOpts);
20202 this._normalized = opts.normalized;
20203 }
20204 parse(raw, index) {
20205 if (raw === undefined) {
20206 return null;
20207 }
20208 return parse(this, raw);
20209 }
20210 beforeLayout() {
20211 super.beforeLayout();
20212 this._cache = {
20213 data: [],
20214 labels: [],
20215 all: []
20216 };
20217 }
20218 determineDataLimits() {
20219 const options = this.options;
20220 const adapter = this._adapter;
20221 const unit = options.time.unit || 'day';
20222 let { min , max , minDefined , maxDefined } = this.getUserBounds();
20223 function _applyBounds(bounds) {
20224 if (!minDefined && !isNaN(bounds.min)) {
20225 min = Math.min(min, bounds.min);
20226 }
20227 if (!maxDefined && !isNaN(bounds.max)) {
20228 max = Math.max(max, bounds.max);
20229 }
20230 }
20231 if (!minDefined || !maxDefined) {
20232 _applyBounds(this._getLabelBounds());
20233 if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
20234 _applyBounds(this.getMinMax(false));
20235 }
20236 }
20237 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
20238 max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
20239 this.min = Math.min(min, max - 1);
20240 this.max = Math.max(min + 1, max);
20241 }
20242 _getLabelBounds() {
20243 const arr = this.getLabelTimestamps();
20244 let min = Number.POSITIVE_INFINITY;
20245 let max = Number.NEGATIVE_INFINITY;
20246 if (arr.length) {
20247 min = arr[0];
20248 max = arr[arr.length - 1];
20249 }
20250 return {
20251 min,
20252 max
20253 };
20254 }
20255 buildTicks() {
20256 const options = this.options;
20257 const timeOpts = options.time;
20258 const tickOpts = options.ticks;
20259 const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();
20260 if (options.bounds === 'ticks' && timestamps.length) {
20261 this.min = this._userMin || timestamps[0];
20262 this.max = this._userMax || timestamps[timestamps.length - 1];
20263 }
20264 const min = this.min;
20265 const max = this.max;
20266 const ticks = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aP)(timestamps, min, max);
20267 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));
20268 this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit);
20269 this.initOffsets(timestamps);
20270 if (options.reverse) {
20271 ticks.reverse();
20272 }
20273 return ticksFromTimestamps(this, ticks, this._majorUnit);
20274 }
20275 afterAutoSkip() {
20276 if (this.options.offsetAfterAutoskip) {
20277 this.initOffsets(this.ticks.map((tick)=>+tick.value));
20278 }
20279 }
20280 initOffsets(timestamps = []) {
20281 let start = 0;
20282 let end = 0;
20283 let first, last;
20284 if (this.options.offset && timestamps.length) {
20285 first = this.getDecimalForValue(timestamps[0]);
20286 if (timestamps.length === 1) {
20287 start = 1 - first;
20288 } else {
20289 start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
20290 }
20291 last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
20292 if (timestamps.length === 1) {
20293 end = last;
20294 } else {
20295 end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
20296 }
20297 }
20298 const limit = timestamps.length < 3 ? 0.5 : 0.25;
20299 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(start, 0, limit);
20300 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(end, 0, limit);
20301 this._offsets = {
20302 start,
20303 end,
20304 factor: 1 / (start + 1 + end)
20305 };
20306 }
20307 _generate() {
20308 const adapter = this._adapter;
20309 const min = this.min;
20310 const max = this.max;
20311 const options = this.options;
20312 const timeOpts = options.time;
20313 const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
20314 const stepSize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.stepSize, 1);
20315 const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
20316 const hasWeekday = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(weekday) || weekday === true;
20317 const ticks = {};
20318 let first = min;
20319 let time, count;
20320 if (hasWeekday) {
20321 first = +adapter.startOf(first, 'isoWeek', weekday);
20322 }
20323 first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
20324 if (adapter.diff(max, min, minor) > 100000 * stepSize) {
20325 throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
20326 }
20327 const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();
20328 for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){
20329 addTick(ticks, time, timestamps);
20330 }
20331 if (time === max || options.bounds === 'ticks' || count === 1) {
20332 addTick(ticks, time, timestamps);
20333 }
20334 return Object.keys(ticks).sort(sorter).map((x)=>+x);
20335 }
20336 getLabelForValue(value) {
20337 const adapter = this._adapter;
20338 const timeOpts = this.options.time;
20339 if (timeOpts.tooltipFormat) {
20340 return adapter.format(value, timeOpts.tooltipFormat);
20341 }
20342 return adapter.format(value, timeOpts.displayFormats.datetime);
20343 }
20344 format(value, format) {
20345 const options = this.options;
20346 const formats = options.time.displayFormats;
20347 const unit = this._unit;
20348 const fmt = format || formats[unit];
20349 return this._adapter.format(value, fmt);
20350 }
20351 _tickFormatFunction(time, index, ticks, format) {
20352 const options = this.options;
20353 const formatter = options.ticks.callback;
20354 if (formatter) {
20355 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(formatter, [
20356 time,
20357 index,
20358 ticks
20359 ], this);
20360 }
20361 const formats = options.time.displayFormats;
20362 const unit = this._unit;
20363 const majorUnit = this._majorUnit;
20364 const minorFormat = unit && formats[unit];
20365 const majorFormat = majorUnit && formats[majorUnit];
20366 const tick = ticks[index];
20367 const major = majorUnit && majorFormat && tick && tick.major;
20368 return this._adapter.format(time, format || (major ? majorFormat : minorFormat));
20369 }
20370 generateTickLabels(ticks) {
20371 let i, ilen, tick;
20372 for(i = 0, ilen = ticks.length; i < ilen; ++i){
20373 tick = ticks[i];
20374 tick.label = this._tickFormatFunction(tick.value, i, ticks);
20375 }
20376 }
20377 getDecimalForValue(value) {
20378 return value === null ? NaN : (value - this.min) / (this.max - this.min);
20379 }
20380 getPixelForValue(value) {
20381 const offsets = this._offsets;
20382 const pos = this.getDecimalForValue(value);
20383 return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
20384 }
20385 getValueForPixel(pixel) {
20386 const offsets = this._offsets;
20387 const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20388 return this.min + pos * (this.max - this.min);
20389 }
20390 _getLabelSize(label) {
20391 const ticksOpts = this.options.ticks;
20392 const tickLabelWidth = this.ctx.measureText(label).width;
20393 const angle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
20394 const cosRotation = Math.cos(angle);
20395 const sinRotation = Math.sin(angle);
20396 const tickFontSize = this._resolveTickFontOptions(0).size;
20397 return {
20398 w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,
20399 h: tickLabelWidth * sinRotation + tickFontSize * cosRotation
20400 };
20401 }
20402 _getLabelCapacity(exampleTime) {
20403 const timeOpts = this.options.time;
20404 const displayFormats = timeOpts.displayFormats;
20405 const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
20406 const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [
20407 exampleTime
20408 ], this._majorUnit), format);
20409 const size = this._getLabelSize(exampleLabel);
20410 const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
20411 return capacity > 0 ? capacity : 1;
20412 }
20413 getDataTimestamps() {
20414 let timestamps = this._cache.data || [];
20415 let i, ilen;
20416 if (timestamps.length) {
20417 return timestamps;
20418 }
20419 const metas = this.getMatchingVisibleMetas();
20420 if (this._normalized && metas.length) {
20421 return this._cache.data = metas[0].controller.getAllParsedValues(this);
20422 }
20423 for(i = 0, ilen = metas.length; i < ilen; ++i){
20424 timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));
20425 }
20426 return this._cache.data = this.normalize(timestamps);
20427 }
20428 getLabelTimestamps() {
20429 const timestamps = this._cache.labels || [];
20430 let i, ilen;
20431 if (timestamps.length) {
20432 return timestamps;
20433 }
20434 const labels = this.getLabels();
20435 for(i = 0, ilen = labels.length; i < ilen; ++i){
20436 timestamps.push(parse(this, labels[i]));
20437 }
20438 return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);
20439 }
20440 normalize(values) {
20441 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort(sorter));
20442 }
20443 }
20444
20445 function interpolate(table, val, reverse) {
20446 let lo = 0;
20447 let hi = table.length - 1;
20448 let prevSource, nextSource, prevTarget, nextTarget;
20449 if (reverse) {
20450 if (val >= table[lo].pos && val <= table[hi].pos) {
20451 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'pos', val));
20452 }
20453 ({ pos: prevSource , time: prevTarget } = table[lo]);
20454 ({ pos: nextSource , time: nextTarget } = table[hi]);
20455 } else {
20456 if (val >= table[lo].time && val <= table[hi].time) {
20457 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'time', val));
20458 }
20459 ({ time: prevSource , pos: prevTarget } = table[lo]);
20460 ({ time: nextSource , pos: nextTarget } = table[hi]);
20461 }
20462 const span = nextSource - prevSource;
20463 return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
20464 }
20465 class TimeSeriesScale extends TimeScale {
20466 static id = 'timeseries';
20467 static defaults = TimeScale.defaults;
20468 constructor(props){
20469 super(props);
20470 this._table = [];
20471 this._minPos = undefined;
20472 this._tableRange = undefined;
20473 }
20474 initOffsets() {
20475 const timestamps = this._getTimestampsForTable();
20476 const table = this._table = this.buildLookupTable(timestamps);
20477 this._minPos = interpolate(table, this.min);
20478 this._tableRange = interpolate(table, this.max) - this._minPos;
20479 super.initOffsets(timestamps);
20480 }
20481 buildLookupTable(timestamps) {
20482 const { min , max } = this;
20483 const items = [];
20484 const table = [];
20485 let i, ilen, prev, curr, next;
20486 for(i = 0, ilen = timestamps.length; i < ilen; ++i){
20487 curr = timestamps[i];
20488 if (curr >= min && curr <= max) {
20489 items.push(curr);
20490 }
20491 }
20492 if (items.length < 2) {
20493 return [
20494 {
20495 time: min,
20496 pos: 0
20497 },
20498 {
20499 time: max,
20500 pos: 1
20501 }
20502 ];
20503 }
20504 for(i = 0, ilen = items.length; i < ilen; ++i){
20505 next = items[i + 1];
20506 prev = items[i - 1];
20507 curr = items[i];
20508 if (Math.round((next + prev) / 2) !== curr) {
20509 table.push({
20510 time: curr,
20511 pos: i / (ilen - 1)
20512 });
20513 }
20514 }
20515 return table;
20516 }
20517 _generate() {
20518 const min = this.min;
20519 const max = this.max;
20520 let timestamps = super.getDataTimestamps();
20521 if (!timestamps.includes(min) || !timestamps.length) {
20522 timestamps.splice(0, 0, min);
20523 }
20524 if (!timestamps.includes(max) || timestamps.length === 1) {
20525 timestamps.push(max);
20526 }
20527 return timestamps.sort((a, b)=>a - b);
20528 }
20529 _getTimestampsForTable() {
20530 let timestamps = this._cache.all || [];
20531 if (timestamps.length) {
20532 return timestamps;
20533 }
20534 const data = this.getDataTimestamps();
20535 const label = this.getLabelTimestamps();
20536 if (data.length && label.length) {
20537 timestamps = this.normalize(data.concat(label));
20538 } else {
20539 timestamps = data.length ? data : label;
20540 }
20541 timestamps = this._cache.all = timestamps;
20542 return timestamps;
20543 }
20544 getDecimalForValue(value) {
20545 return (interpolate(this._table, value) - this._minPos) / this._tableRange;
20546 }
20547 getValueForPixel(pixel) {
20548 const offsets = this._offsets;
20549 const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20550 return interpolate(this._table, decimal * this._tableRange + this._minPos, true);
20551 }
20552 }
20553
20554 var scales = /*#__PURE__*/Object.freeze({
20555 __proto__: null,
20556 CategoryScale: CategoryScale,
20557 LinearScale: LinearScale,
20558 LogarithmicScale: LogarithmicScale,
20559 RadialLinearScale: RadialLinearScale,
20560 TimeScale: TimeScale,
20561 TimeSeriesScale: TimeSeriesScale
20562 });
20563
20564 const registerables = [
20565 controllers,
20566 elements,
20567 plugins,
20568 scales
20569 ];
20570
20571
20572 //# sourceMappingURL=chart.js.map
20573
20574
20575 /***/ },
20576
20577 /***/ "./node_modules/chart.js/dist/chunks/helpers.dataset.js"
20578 /*!**************************************************************!*\
20579 !*** ./node_modules/chart.js/dist/chunks/helpers.dataset.js ***!
20580 \**************************************************************/
20581 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
20582
20583 "use strict";
20584 __webpack_require__.r(__webpack_exports__);
20585 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
20586 /* harmony export */ $: () => (/* binding */ unclipArea),
20587 /* harmony export */ A: () => (/* binding */ _rlookupByKey),
20588 /* harmony export */ B: () => (/* binding */ _lookupByKey),
20589 /* harmony export */ C: () => (/* binding */ _isPointInArea),
20590 /* harmony export */ D: () => (/* binding */ getAngleFromPoint),
20591 /* harmony export */ E: () => (/* binding */ toPadding),
20592 /* harmony export */ F: () => (/* binding */ each),
20593 /* harmony export */ G: () => (/* binding */ getMaximumSize),
20594 /* harmony export */ H: () => (/* binding */ HALF_PI),
20595 /* harmony export */ I: () => (/* binding */ _getParentNode),
20596 /* harmony export */ J: () => (/* binding */ readUsedSize),
20597 /* harmony export */ K: () => (/* binding */ supportsEventListenerOptions),
20598 /* harmony export */ L: () => (/* binding */ throttled),
20599 /* harmony export */ M: () => (/* binding */ _isDomSupported),
20600 /* harmony export */ N: () => (/* binding */ _factorize),
20601 /* harmony export */ O: () => (/* binding */ finiteOrDefault),
20602 /* harmony export */ P: () => (/* binding */ PI),
20603 /* harmony export */ Q: () => (/* binding */ callback),
20604 /* harmony export */ R: () => (/* binding */ _addGrace),
20605 /* harmony export */ S: () => (/* binding */ _limitValue),
20606 /* harmony export */ T: () => (/* binding */ TAU),
20607 /* harmony export */ U: () => (/* binding */ toDegrees),
20608 /* harmony export */ V: () => (/* binding */ _measureText),
20609 /* harmony export */ W: () => (/* binding */ _int16Range),
20610 /* harmony export */ X: () => (/* binding */ _alignPixel),
20611 /* harmony export */ Y: () => (/* binding */ clipArea),
20612 /* harmony export */ Z: () => (/* binding */ renderText),
20613 /* harmony export */ _: () => (/* binding */ _arrayUnique),
20614 /* harmony export */ a: () => (/* binding */ resolve),
20615 /* harmony export */ a$: () => (/* binding */ getStyle),
20616 /* harmony export */ a0: () => (/* binding */ toFont),
20617 /* harmony export */ a1: () => (/* binding */ _toLeftRightCenter),
20618 /* harmony export */ a2: () => (/* binding */ _alignStartEnd),
20619 /* harmony export */ a3: () => (/* binding */ overrides),
20620 /* harmony export */ a4: () => (/* binding */ merge),
20621 /* harmony export */ a5: () => (/* binding */ _capitalize),
20622 /* harmony export */ a6: () => (/* binding */ descriptors),
20623 /* harmony export */ a7: () => (/* binding */ isFunction),
20624 /* harmony export */ a8: () => (/* binding */ _attachContext),
20625 /* harmony export */ a9: () => (/* binding */ _createResolver),
20626 /* harmony export */ aA: () => (/* binding */ getRtlAdapter),
20627 /* harmony export */ aB: () => (/* binding */ overrideTextDirection),
20628 /* harmony export */ aC: () => (/* binding */ _textX),
20629 /* harmony export */ aD: () => (/* binding */ restoreTextDirection),
20630 /* harmony export */ aE: () => (/* binding */ drawPointLegend),
20631 /* harmony export */ aF: () => (/* binding */ distanceBetweenPoints),
20632 /* harmony export */ aG: () => (/* binding */ noop),
20633 /* harmony export */ aH: () => (/* binding */ _setMinAndMaxByKey),
20634 /* harmony export */ aI: () => (/* binding */ niceNum),
20635 /* harmony export */ aJ: () => (/* binding */ almostWhole),
20636 /* harmony export */ aK: () => (/* binding */ almostEquals),
20637 /* harmony export */ aL: () => (/* binding */ _decimalPlaces),
20638 /* harmony export */ aM: () => (/* binding */ Ticks),
20639 /* harmony export */ aN: () => (/* binding */ log10),
20640 /* harmony export */ aO: () => (/* binding */ _longestText),
20641 /* harmony export */ aP: () => (/* binding */ _filterBetween),
20642 /* harmony export */ aQ: () => (/* binding */ _lookup),
20643 /* harmony export */ aR: () => (/* binding */ isPatternOrGradient),
20644 /* harmony export */ aS: () => (/* binding */ getHoverColor),
20645 /* harmony export */ aT: () => (/* binding */ clone),
20646 /* harmony export */ aU: () => (/* binding */ _merger),
20647 /* harmony export */ aV: () => (/* binding */ _mergerIf),
20648 /* harmony export */ aW: () => (/* binding */ _deprecated),
20649 /* harmony export */ aX: () => (/* binding */ _splitKey),
20650 /* harmony export */ aY: () => (/* binding */ toFontString),
20651 /* harmony export */ aZ: () => (/* binding */ splineCurve),
20652 /* harmony export */ a_: () => (/* binding */ splineCurveMonotone),
20653 /* harmony export */ aa: () => (/* binding */ _descriptors),
20654 /* harmony export */ ab: () => (/* binding */ mergeIf),
20655 /* harmony export */ ac: () => (/* binding */ uid),
20656 /* harmony export */ ad: () => (/* binding */ debounce),
20657 /* harmony export */ ae: () => (/* binding */ retinaScale),
20658 /* harmony export */ af: () => (/* binding */ clearCanvas),
20659 /* harmony export */ ag: () => (/* binding */ setsEqual),
20660 /* harmony export */ ah: () => (/* binding */ getDatasetClipArea),
20661 /* harmony export */ ai: () => (/* binding */ _elementsEqual),
20662 /* harmony export */ aj: () => (/* binding */ _isClickEvent),
20663 /* harmony export */ ak: () => (/* binding */ _isBetween),
20664 /* harmony export */ al: () => (/* binding */ _normalizeAngle),
20665 /* harmony export */ am: () => (/* binding */ _readValueToProps),
20666 /* harmony export */ an: () => (/* binding */ _updateBezierControlPoints),
20667 /* harmony export */ ao: () => (/* binding */ _computeSegments),
20668 /* harmony export */ ap: () => (/* binding */ _boundSegments),
20669 /* harmony export */ aq: () => (/* binding */ _steppedInterpolation),
20670 /* harmony export */ ar: () => (/* binding */ _bezierInterpolation),
20671 /* harmony export */ as: () => (/* binding */ _pointInLine),
20672 /* harmony export */ at: () => (/* binding */ _steppedLineTo),
20673 /* harmony export */ au: () => (/* binding */ _bezierCurveTo),
20674 /* harmony export */ av: () => (/* binding */ drawPoint),
20675 /* harmony export */ aw: () => (/* binding */ addRoundedRectPath),
20676 /* harmony export */ ax: () => (/* binding */ toTRBL),
20677 /* harmony export */ ay: () => (/* binding */ toTRBLCorners),
20678 /* harmony export */ az: () => (/* binding */ _boundSegment),
20679 /* harmony export */ b: () => (/* binding */ isArray),
20680 /* harmony export */ b0: () => (/* binding */ fontString),
20681 /* harmony export */ b1: () => (/* binding */ toLineHeight),
20682 /* harmony export */ b2: () => (/* binding */ PITAU),
20683 /* harmony export */ b3: () => (/* binding */ INFINITY),
20684 /* harmony export */ b4: () => (/* binding */ RAD_PER_DEG),
20685 /* harmony export */ b5: () => (/* binding */ QUARTER_PI),
20686 /* harmony export */ b6: () => (/* binding */ TWO_THIRDS_PI),
20687 /* harmony export */ b7: () => (/* binding */ _angleDiff),
20688 /* harmony export */ c: () => (/* binding */ color),
20689 /* harmony export */ d: () => (/* binding */ defaults),
20690 /* harmony export */ e: () => (/* binding */ effects),
20691 /* harmony export */ f: () => (/* binding */ resolveObjectKey),
20692 /* harmony export */ g: () => (/* binding */ isNumberFinite),
20693 /* harmony export */ h: () => (/* binding */ defined),
20694 /* harmony export */ i: () => (/* binding */ isObject),
20695 /* harmony export */ j: () => (/* binding */ createContext),
20696 /* harmony export */ k: () => (/* binding */ isNullOrUndef),
20697 /* harmony export */ l: () => (/* binding */ listenArrayEvents),
20698 /* harmony export */ m: () => (/* binding */ toPercentage),
20699 /* harmony export */ n: () => (/* binding */ toDimension),
20700 /* harmony export */ o: () => (/* binding */ formatNumber),
20701 /* harmony export */ p: () => (/* binding */ _angleBetween),
20702 /* harmony export */ q: () => (/* binding */ _getStartAndCountOfVisiblePoints),
20703 /* harmony export */ r: () => (/* binding */ requestAnimFrame),
20704 /* harmony export */ s: () => (/* binding */ sign),
20705 /* harmony export */ t: () => (/* binding */ toRadians),
20706 /* harmony export */ u: () => (/* binding */ unlistenArrayEvents),
20707 /* harmony export */ v: () => (/* binding */ valueOrDefault),
20708 /* harmony export */ w: () => (/* binding */ _scaleRangesChanged),
20709 /* harmony export */ x: () => (/* binding */ isNumber),
20710 /* harmony export */ y: () => (/* binding */ _parseObjectDataRadialScale),
20711 /* harmony export */ z: () => (/* binding */ getRelativePosition)
20712 /* harmony export */ });
20713 /* harmony import */ var _kurkle_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kurkle/color */ "./node_modules/@kurkle/color/dist/color.esm.js");
20714 /*!
20715 * Chart.js v4.5.1
20716 * https://www.chartjs.org
20717 * (c) 2025 Chart.js Contributors
20718 * Released under the MIT License
20719 */
20720
20721
20722 /**
20723 * @namespace Chart.helpers
20724 */ /**
20725 * An empty function that can be used, for example, for optional callback.
20726 */ function noop() {
20727 /* noop */ }
20728 /**
20729 * Returns a unique id, sequentially generated from a global variable.
20730 */ const uid = (()=>{
20731 let id = 0;
20732 return ()=>id++;
20733 })();
20734 /**
20735 * Returns true if `value` is neither null nor undefined, else returns false.
20736 * @param value - The value to test.
20737 * @since 2.7.0
20738 */ function isNullOrUndef(value) {
20739 return value === null || value === undefined;
20740 }
20741 /**
20742 * Returns true if `value` is an array (including typed arrays), else returns false.
20743 * @param value - The value to test.
20744 * @function
20745 */ function isArray(value) {
20746 if (Array.isArray && Array.isArray(value)) {
20747 return true;
20748 }
20749 const type = Object.prototype.toString.call(value);
20750 if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') {
20751 return true;
20752 }
20753 return false;
20754 }
20755 /**
20756 * Returns true if `value` is an object (excluding null), else returns false.
20757 * @param value - The value to test.
20758 * @since 2.7.0
20759 */ function isObject(value) {
20760 return value !== null && Object.prototype.toString.call(value) === '[object Object]';
20761 }
20762 /**
20763 * Returns true if `value` is a finite number, else returns false
20764 * @param value - The value to test.
20765 */ function isNumberFinite(value) {
20766 return (typeof value === 'number' || value instanceof Number) && isFinite(+value);
20767 }
20768 /**
20769 * Returns `value` if finite, else returns `defaultValue`.
20770 * @param value - The value to return if defined.
20771 * @param defaultValue - The value to return if `value` is not finite.
20772 */ function finiteOrDefault(value, defaultValue) {
20773 return isNumberFinite(value) ? value : defaultValue;
20774 }
20775 /**
20776 * Returns `value` if defined, else returns `defaultValue`.
20777 * @param value - The value to return if defined.
20778 * @param defaultValue - The value to return if `value` is undefined.
20779 */ function valueOrDefault(value, defaultValue) {
20780 return typeof value === 'undefined' ? defaultValue : value;
20781 }
20782 const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;
20783 const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;
20784 /**
20785 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
20786 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
20787 * @param fn - The function to call.
20788 * @param args - The arguments with which `fn` should be called.
20789 * @param [thisArg] - The value of `this` provided for the call to `fn`.
20790 */ function callback(fn, args, thisArg) {
20791 if (fn && typeof fn.call === 'function') {
20792 return fn.apply(thisArg, args);
20793 }
20794 }
20795 function each(loopable, fn, thisArg, reverse) {
20796 let i, len, keys;
20797 if (isArray(loopable)) {
20798 len = loopable.length;
20799 if (reverse) {
20800 for(i = len - 1; i >= 0; i--){
20801 fn.call(thisArg, loopable[i], i);
20802 }
20803 } else {
20804 for(i = 0; i < len; i++){
20805 fn.call(thisArg, loopable[i], i);
20806 }
20807 }
20808 } else if (isObject(loopable)) {
20809 keys = Object.keys(loopable);
20810 len = keys.length;
20811 for(i = 0; i < len; i++){
20812 fn.call(thisArg, loopable[keys[i]], keys[i]);
20813 }
20814 }
20815 }
20816 /**
20817 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
20818 * @param a0 - The array to compare
20819 * @param a1 - The array to compare
20820 * @private
20821 */ function _elementsEqual(a0, a1) {
20822 let i, ilen, v0, v1;
20823 if (!a0 || !a1 || a0.length !== a1.length) {
20824 return false;
20825 }
20826 for(i = 0, ilen = a0.length; i < ilen; ++i){
20827 v0 = a0[i];
20828 v1 = a1[i];
20829 if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
20830 return false;
20831 }
20832 }
20833 return true;
20834 }
20835 /**
20836 * Returns a deep copy of `source` without keeping references on objects and arrays.
20837 * @param source - The value to clone.
20838 */ function clone(source) {
20839 if (isArray(source)) {
20840 return source.map(clone);
20841 }
20842 if (isObject(source)) {
20843 const target = Object.create(null);
20844 const keys = Object.keys(source);
20845 const klen = keys.length;
20846 let k = 0;
20847 for(; k < klen; ++k){
20848 target[keys[k]] = clone(source[keys[k]]);
20849 }
20850 return target;
20851 }
20852 return source;
20853 }
20854 function isValidKey(key) {
20855 return [
20856 '__proto__',
20857 'prototype',
20858 'constructor'
20859 ].indexOf(key) === -1;
20860 }
20861 /**
20862 * The default merger when Chart.helpers.merge is called without merger option.
20863 * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
20864 * @private
20865 */ function _merger(key, target, source, options) {
20866 if (!isValidKey(key)) {
20867 return;
20868 }
20869 const tval = target[key];
20870 const sval = source[key];
20871 if (isObject(tval) && isObject(sval)) {
20872 // eslint-disable-next-line @typescript-eslint/no-use-before-define
20873 merge(tval, sval, options);
20874 } else {
20875 target[key] = clone(sval);
20876 }
20877 }
20878 function merge(target, source, options) {
20879 const sources = isArray(source) ? source : [
20880 source
20881 ];
20882 const ilen = sources.length;
20883 if (!isObject(target)) {
20884 return target;
20885 }
20886 options = options || {};
20887 const merger = options.merger || _merger;
20888 let current;
20889 for(let i = 0; i < ilen; ++i){
20890 current = sources[i];
20891 if (!isObject(current)) {
20892 continue;
20893 }
20894 const keys = Object.keys(current);
20895 for(let k = 0, klen = keys.length; k < klen; ++k){
20896 merger(keys[k], target, current, options);
20897 }
20898 }
20899 return target;
20900 }
20901 function mergeIf(target, source) {
20902 // eslint-disable-next-line @typescript-eslint/no-use-before-define
20903 return merge(target, source, {
20904 merger: _mergerIf
20905 });
20906 }
20907 /**
20908 * Merges source[key] in target[key] only if target[key] is undefined.
20909 * @private
20910 */ function _mergerIf(key, target, source) {
20911 if (!isValidKey(key)) {
20912 return;
20913 }
20914 const tval = target[key];
20915 const sval = source[key];
20916 if (isObject(tval) && isObject(sval)) {
20917 mergeIf(tval, sval);
20918 } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
20919 target[key] = clone(sval);
20920 }
20921 }
20922 /**
20923 * @private
20924 */ function _deprecated(scope, value, previous, current) {
20925 if (value !== undefined) {
20926 console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead');
20927 }
20928 }
20929 // resolveObjectKey resolver cache
20930 const keyResolvers = {
20931 // Chart.helpers.core resolveObjectKey should resolve empty key to root object
20932 '': (v)=>v,
20933 // default resolvers
20934 x: (o)=>o.x,
20935 y: (o)=>o.y
20936 };
20937 /**
20938 * @private
20939 */ function _splitKey(key) {
20940 const parts = key.split('.');
20941 const keys = [];
20942 let tmp = '';
20943 for (const part of parts){
20944 tmp += part;
20945 if (tmp.endsWith('\\')) {
20946 tmp = tmp.slice(0, -1) + '.';
20947 } else {
20948 keys.push(tmp);
20949 tmp = '';
20950 }
20951 }
20952 return keys;
20953 }
20954 function _getKeyResolver(key) {
20955 const keys = _splitKey(key);
20956 return (obj)=>{
20957 for (const k of keys){
20958 if (k === '') {
20959 break;
20960 }
20961 obj = obj && obj[k];
20962 }
20963 return obj;
20964 };
20965 }
20966 function resolveObjectKey(obj, key) {
20967 const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
20968 return resolver(obj);
20969 }
20970 /**
20971 * @private
20972 */ function _capitalize(str) {
20973 return str.charAt(0).toUpperCase() + str.slice(1);
20974 }
20975 const defined = (value)=>typeof value !== 'undefined';
20976 const isFunction = (value)=>typeof value === 'function';
20977 // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
20978 const setsEqual = (a, b)=>{
20979 if (a.size !== b.size) {
20980 return false;
20981 }
20982 for (const item of a){
20983 if (!b.has(item)) {
20984 return false;
20985 }
20986 }
20987 return true;
20988 };
20989 /**
20990 * @param e - The event
20991 * @private
20992 */ function _isClickEvent(e) {
20993 return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
20994 }
20995
20996 /**
20997 * @alias Chart.helpers.math
20998 * @namespace
20999 */ const PI = Math.PI;
21000 const TAU = 2 * PI;
21001 const PITAU = TAU + PI;
21002 const INFINITY = Number.POSITIVE_INFINITY;
21003 const RAD_PER_DEG = PI / 180;
21004 const HALF_PI = PI / 2;
21005 const QUARTER_PI = PI / 4;
21006 const TWO_THIRDS_PI = PI * 2 / 3;
21007 const log10 = Math.log10;
21008 const sign = Math.sign;
21009 function almostEquals(x, y, epsilon) {
21010 return Math.abs(x - y) < epsilon;
21011 }
21012 /**
21013 * Implementation of the nice number algorithm used in determining where axis labels will go
21014 */ function niceNum(range) {
21015 const roundedRange = Math.round(range);
21016 range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
21017 const niceRange = Math.pow(10, Math.floor(log10(range)));
21018 const fraction = range / niceRange;
21019 const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
21020 return niceFraction * niceRange;
21021 }
21022 /**
21023 * Returns an array of factors sorted from 1 to sqrt(value)
21024 * @private
21025 */ function _factorize(value) {
21026 const result = [];
21027 const sqrt = Math.sqrt(value);
21028 let i;
21029 for(i = 1; i < sqrt; i++){
21030 if (value % i === 0) {
21031 result.push(i);
21032 result.push(value / i);
21033 }
21034 }
21035 if (sqrt === (sqrt | 0)) {
21036 result.push(sqrt);
21037 }
21038 result.sort((a, b)=>a - b).pop();
21039 return result;
21040 }
21041 /**
21042 * Verifies that attempting to coerce n to string or number won't throw a TypeError.
21043 */ function isNonPrimitive(n) {
21044 return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n);
21045 }
21046 function isNumber(n) {
21047 return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n);
21048 }
21049 function almostWhole(x, epsilon) {
21050 const rounded = Math.round(x);
21051 return rounded - epsilon <= x && rounded + epsilon >= x;
21052 }
21053 /**
21054 * @private
21055 */ function _setMinAndMaxByKey(array, target, property) {
21056 let i, ilen, value;
21057 for(i = 0, ilen = array.length; i < ilen; i++){
21058 value = array[i][property];
21059 if (!isNaN(value)) {
21060 target.min = Math.min(target.min, value);
21061 target.max = Math.max(target.max, value);
21062 }
21063 }
21064 }
21065 function toRadians(degrees) {
21066 return degrees * (PI / 180);
21067 }
21068 function toDegrees(radians) {
21069 return radians * (180 / PI);
21070 }
21071 /**
21072 * Returns the number of decimal places
21073 * i.e. the number of digits after the decimal point, of the value of this Number.
21074 * @param x - A number.
21075 * @returns The number of decimal places.
21076 * @private
21077 */ function _decimalPlaces(x) {
21078 if (!isNumberFinite(x)) {
21079 return;
21080 }
21081 let e = 1;
21082 let p = 0;
21083 while(Math.round(x * e) / e !== x){
21084 e *= 10;
21085 p++;
21086 }
21087 return p;
21088 }
21089 // Gets the angle from vertical upright to the point about a centre.
21090 function getAngleFromPoint(centrePoint, anglePoint) {
21091 const distanceFromXCenter = anglePoint.x - centrePoint.x;
21092 const distanceFromYCenter = anglePoint.y - centrePoint.y;
21093 const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
21094 let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
21095 if (angle < -0.5 * PI) {
21096 angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
21097 }
21098 return {
21099 angle,
21100 distance: radialDistanceFromCenter
21101 };
21102 }
21103 function distanceBetweenPoints(pt1, pt2) {
21104 return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
21105 }
21106 /**
21107 * Shortest distance between angles, in either direction.
21108 * @private
21109 */ function _angleDiff(a, b) {
21110 return (a - b + PITAU) % TAU - PI;
21111 }
21112 /**
21113 * Normalize angle to be between 0 and 2*PI
21114 * @private
21115 */ function _normalizeAngle(a) {
21116 return (a % TAU + TAU) % TAU;
21117 }
21118 /**
21119 * @private
21120 */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
21121 const a = _normalizeAngle(angle);
21122 const s = _normalizeAngle(start);
21123 const e = _normalizeAngle(end);
21124 const angleToStart = _normalizeAngle(s - a);
21125 const angleToEnd = _normalizeAngle(e - a);
21126 const startToAngle = _normalizeAngle(a - s);
21127 const endToAngle = _normalizeAngle(a - e);
21128 return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;
21129 }
21130 /**
21131 * Limit `value` between `min` and `max`
21132 * @param value
21133 * @param min
21134 * @param max
21135 * @private
21136 */ function _limitValue(value, min, max) {
21137 return Math.max(min, Math.min(max, value));
21138 }
21139 /**
21140 * @param {number} value
21141 * @private
21142 */ function _int16Range(value) {
21143 return _limitValue(value, -32768, 32767);
21144 }
21145 /**
21146 * @param value
21147 * @param start
21148 * @param end
21149 * @param [epsilon]
21150 * @private
21151 */ function _isBetween(value, start, end, epsilon = 1e-6) {
21152 return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
21153 }
21154
21155 function _lookup(table, value, cmp) {
21156 cmp = cmp || ((index)=>table[index] < value);
21157 let hi = table.length - 1;
21158 let lo = 0;
21159 let mid;
21160 while(hi - lo > 1){
21161 mid = lo + hi >> 1;
21162 if (cmp(mid)) {
21163 lo = mid;
21164 } else {
21165 hi = mid;
21166 }
21167 }
21168 return {
21169 lo,
21170 hi
21171 };
21172 }
21173 /**
21174 * Binary search
21175 * @param table - the table search. must be sorted!
21176 * @param key - property name for the value in each entry
21177 * @param value - value to find
21178 * @param last - lookup last index
21179 * @private
21180 */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{
21181 const ti = table[index][key];
21182 return ti < value || ti === value && table[index + 1][key] === value;
21183 } : (index)=>table[index][key] < value);
21184 /**
21185 * Reverse binary search
21186 * @param table - the table search. must be sorted!
21187 * @param key - property name for the value in each entry
21188 * @param value - value to find
21189 * @private
21190 */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);
21191 /**
21192 * Return subset of `values` between `min` and `max` inclusive.
21193 * Values are assumed to be in sorted order.
21194 * @param values - sorted array of values
21195 * @param min - min value
21196 * @param max - max value
21197 */ function _filterBetween(values, min, max) {
21198 let start = 0;
21199 let end = values.length;
21200 while(start < end && values[start] < min){
21201 start++;
21202 }
21203 while(end > start && values[end - 1] > max){
21204 end--;
21205 }
21206 return start > 0 || end < values.length ? values.slice(start, end) : values;
21207 }
21208 const arrayEvents = [
21209 'push',
21210 'pop',
21211 'shift',
21212 'splice',
21213 'unshift'
21214 ];
21215 function listenArrayEvents(array, listener) {
21216 if (array._chartjs) {
21217 array._chartjs.listeners.push(listener);
21218 return;
21219 }
21220 Object.defineProperty(array, '_chartjs', {
21221 configurable: true,
21222 enumerable: false,
21223 value: {
21224 listeners: [
21225 listener
21226 ]
21227 }
21228 });
21229 arrayEvents.forEach((key)=>{
21230 const method = '_onData' + _capitalize(key);
21231 const base = array[key];
21232 Object.defineProperty(array, key, {
21233 configurable: true,
21234 enumerable: false,
21235 value (...args) {
21236 const res = base.apply(this, args);
21237 array._chartjs.listeners.forEach((object)=>{
21238 if (typeof object[method] === 'function') {
21239 object[method](...args);
21240 }
21241 });
21242 return res;
21243 }
21244 });
21245 });
21246 }
21247 function unlistenArrayEvents(array, listener) {
21248 const stub = array._chartjs;
21249 if (!stub) {
21250 return;
21251 }
21252 const listeners = stub.listeners;
21253 const index = listeners.indexOf(listener);
21254 if (index !== -1) {
21255 listeners.splice(index, 1);
21256 }
21257 if (listeners.length > 0) {
21258 return;
21259 }
21260 arrayEvents.forEach((key)=>{
21261 delete array[key];
21262 });
21263 delete array._chartjs;
21264 }
21265 /**
21266 * @param items
21267 */ function _arrayUnique(items) {
21268 const set = new Set(items);
21269 if (set.size === items.length) {
21270 return items;
21271 }
21272 return Array.from(set);
21273 }
21274
21275 function fontString(pixelSize, fontStyle, fontFamily) {
21276 return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
21277 }
21278 /**
21279 * Request animation polyfill
21280 */ const requestAnimFrame = function() {
21281 if (typeof window === 'undefined') {
21282 return function(callback) {
21283 return callback();
21284 };
21285 }
21286 return window.requestAnimationFrame;
21287 }();
21288 /**
21289 * Throttles calling `fn` once per animation frame
21290 * Latest arguments are used on the actual call
21291 */ function throttled(fn, thisArg) {
21292 let argsToUse = [];
21293 let ticking = false;
21294 return function(...args) {
21295 // Save the args for use later
21296 argsToUse = args;
21297 if (!ticking) {
21298 ticking = true;
21299 requestAnimFrame.call(window, ()=>{
21300 ticking = false;
21301 fn.apply(thisArg, argsToUse);
21302 });
21303 }
21304 };
21305 }
21306 /**
21307 * Debounces calling `fn` for `delay` ms
21308 */ function debounce(fn, delay) {
21309 let timeout;
21310 return function(...args) {
21311 if (delay) {
21312 clearTimeout(timeout);
21313 timeout = setTimeout(fn, delay, args);
21314 } else {
21315 fn.apply(this, args);
21316 }
21317 return delay;
21318 };
21319 }
21320 /**
21321 * Converts 'start' to 'left', 'end' to 'right' and others to 'center'
21322 * @private
21323 */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
21324 /**
21325 * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`
21326 * @private
21327 */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
21328 /**
21329 * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`
21330 * @private
21331 */ const _textX = (align, left, right, rtl)=>{
21332 const check = rtl ? 'left' : 'right';
21333 return align === check ? right : align === 'center' ? (left + right) / 2 : left;
21334 };
21335 /**
21336 * Return start and count of visible points.
21337 * @private
21338 */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
21339 const pointCount = points.length;
21340 let start = 0;
21341 let count = pointCount;
21342 if (meta._sorted) {
21343 const { iScale , vScale , _parsed } = meta;
21344 const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null;
21345 const axis = iScale.axis;
21346 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
21347 if (minDefined) {
21348 start = Math.min(// @ts-expect-error Need to type _parsed
21349 _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey
21350 animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo);
21351 if (spanGaps) {
21352 const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21353 start -= Math.max(0, distanceToDefinedLo);
21354 }
21355 start = _limitValue(start, 0, pointCount - 1);
21356 }
21357 if (maxDefined) {
21358 let end = Math.max(// @ts-expect-error Need to type _parsed
21359 _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey
21360 animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1);
21361 if (spanGaps) {
21362 const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21363 end += Math.max(0, distanceToDefinedHi);
21364 }
21365 count = _limitValue(end, start, pointCount) - start;
21366 } else {
21367 count = pointCount - start;
21368 }
21369 }
21370 return {
21371 start,
21372 count
21373 };
21374 }
21375 /**
21376 * Checks if the scale ranges have changed.
21377 * @param {object} meta - dataset meta.
21378 * @returns {boolean}
21379 * @private
21380 */ function _scaleRangesChanged(meta) {
21381 const { xScale , yScale , _scaleRanges } = meta;
21382 const newRanges = {
21383 xmin: xScale.min,
21384 xmax: xScale.max,
21385 ymin: yScale.min,
21386 ymax: yScale.max
21387 };
21388 if (!_scaleRanges) {
21389 meta._scaleRanges = newRanges;
21390 return true;
21391 }
21392 const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max;
21393 Object.assign(_scaleRanges, newRanges);
21394 return changed;
21395 }
21396
21397 const atEdge = (t)=>t === 0 || t === 1;
21398 const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
21399 const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
21400 /**
21401 * Easing functions adapted from Robert Penner's easing equations.
21402 * @namespace Chart.helpers.easing.effects
21403 * @see http://www.robertpenner.com/easing/
21404 */ const effects = {
21405 linear: (t)=>t,
21406 easeInQuad: (t)=>t * t,
21407 easeOutQuad: (t)=>-t * (t - 2),
21408 easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),
21409 easeInCubic: (t)=>t * t * t,
21410 easeOutCubic: (t)=>(t -= 1) * t * t + 1,
21411 easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),
21412 easeInQuart: (t)=>t * t * t * t,
21413 easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),
21414 easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),
21415 easeInQuint: (t)=>t * t * t * t * t,
21416 easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,
21417 easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),
21418 easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,
21419 easeOutSine: (t)=>Math.sin(t * HALF_PI),
21420 easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),
21421 easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
21422 easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,
21423 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),
21424 easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),
21425 easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),
21426 easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
21427 easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
21428 easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
21429 easeInOutElastic (t) {
21430 const s = 0.1125;
21431 const p = 0.45;
21432 return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
21433 },
21434 easeInBack (t) {
21435 const s = 1.70158;
21436 return t * t * ((s + 1) * t - s);
21437 },
21438 easeOutBack (t) {
21439 const s = 1.70158;
21440 return (t -= 1) * t * ((s + 1) * t + s) + 1;
21441 },
21442 easeInOutBack (t) {
21443 let s = 1.70158;
21444 if ((t /= 0.5) < 1) {
21445 return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
21446 }
21447 return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
21448 },
21449 easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),
21450 easeOutBounce (t) {
21451 const m = 7.5625;
21452 const d = 2.75;
21453 if (t < 1 / d) {
21454 return m * t * t;
21455 }
21456 if (t < 2 / d) {
21457 return m * (t -= 1.5 / d) * t + 0.75;
21458 }
21459 if (t < 2.5 / d) {
21460 return m * (t -= 2.25 / d) * t + 0.9375;
21461 }
21462 return m * (t -= 2.625 / d) * t + 0.984375;
21463 },
21464 easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5
21465 };
21466
21467 function isPatternOrGradient(value) {
21468 if (value && typeof value === 'object') {
21469 const type = value.toString();
21470 return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
21471 }
21472 return false;
21473 }
21474 function color(value) {
21475 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value);
21476 }
21477 function getHoverColor(value) {
21478 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value).saturate(0.5).darken(0.1).hexString();
21479 }
21480
21481 const numbers = [
21482 'x',
21483 'y',
21484 'borderWidth',
21485 'radius',
21486 'tension'
21487 ];
21488 const colors = [
21489 'color',
21490 'borderColor',
21491 'backgroundColor'
21492 ];
21493 function applyAnimationsDefaults(defaults) {
21494 defaults.set('animation', {
21495 delay: undefined,
21496 duration: 1000,
21497 easing: 'easeOutQuart',
21498 fn: undefined,
21499 from: undefined,
21500 loop: undefined,
21501 to: undefined,
21502 type: undefined
21503 });
21504 defaults.describe('animation', {
21505 _fallback: false,
21506 _indexable: false,
21507 _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'
21508 });
21509 defaults.set('animations', {
21510 colors: {
21511 type: 'color',
21512 properties: colors
21513 },
21514 numbers: {
21515 type: 'number',
21516 properties: numbers
21517 }
21518 });
21519 defaults.describe('animations', {
21520 _fallback: 'animation'
21521 });
21522 defaults.set('transitions', {
21523 active: {
21524 animation: {
21525 duration: 400
21526 }
21527 },
21528 resize: {
21529 animation: {
21530 duration: 0
21531 }
21532 },
21533 show: {
21534 animations: {
21535 colors: {
21536 from: 'transparent'
21537 },
21538 visible: {
21539 type: 'boolean',
21540 duration: 0
21541 }
21542 }
21543 },
21544 hide: {
21545 animations: {
21546 colors: {
21547 to: 'transparent'
21548 },
21549 visible: {
21550 type: 'boolean',
21551 easing: 'linear',
21552 fn: (v)=>v | 0
21553 }
21554 }
21555 }
21556 });
21557 }
21558
21559 function applyLayoutsDefaults(defaults) {
21560 defaults.set('layout', {
21561 autoPadding: true,
21562 padding: {
21563 top: 0,
21564 right: 0,
21565 bottom: 0,
21566 left: 0
21567 }
21568 });
21569 }
21570
21571 const intlCache = new Map();
21572 function getNumberFormat(locale, options) {
21573 options = options || {};
21574 const cacheKey = locale + JSON.stringify(options);
21575 let formatter = intlCache.get(cacheKey);
21576 if (!formatter) {
21577 formatter = new Intl.NumberFormat(locale, options);
21578 intlCache.set(cacheKey, formatter);
21579 }
21580 return formatter;
21581 }
21582 function formatNumber(num, locale, options) {
21583 return getNumberFormat(locale, options).format(num);
21584 }
21585
21586 const formatters = {
21587 values (value) {
21588 return isArray(value) ? value : '' + value;
21589 },
21590 numeric (tickValue, index, ticks) {
21591 if (tickValue === 0) {
21592 return '0';
21593 }
21594 const locale = this.chart.options.locale;
21595 let notation;
21596 let delta = tickValue;
21597 if (ticks.length > 1) {
21598 const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
21599 if (maxTick < 1e-4 || maxTick > 1e+15) {
21600 notation = 'scientific';
21601 }
21602 delta = calculateDelta(tickValue, ticks);
21603 }
21604 const logDelta = log10(Math.abs(delta));
21605 const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
21606 const options = {
21607 notation,
21608 minimumFractionDigits: numDecimal,
21609 maximumFractionDigits: numDecimal
21610 };
21611 Object.assign(options, this.options.ticks.format);
21612 return formatNumber(tickValue, locale, options);
21613 },
21614 logarithmic (tickValue, index, ticks) {
21615 if (tickValue === 0) {
21616 return '0';
21617 }
21618 const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
21619 if ([
21620 1,
21621 2,
21622 3,
21623 5,
21624 10,
21625 15
21626 ].includes(remain) || index > 0.8 * ticks.length) {
21627 return formatters.numeric.call(this, tickValue, index, ticks);
21628 }
21629 return '';
21630 }
21631 };
21632 function calculateDelta(tickValue, ticks) {
21633 let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
21634 if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
21635 delta = tickValue - Math.floor(tickValue);
21636 }
21637 return delta;
21638 }
21639 var Ticks = {
21640 formatters
21641 };
21642
21643 function applyScaleDefaults(defaults) {
21644 defaults.set('scale', {
21645 display: true,
21646 offset: false,
21647 reverse: false,
21648 beginAtZero: false,
21649 bounds: 'ticks',
21650 clip: true,
21651 grace: 0,
21652 grid: {
21653 display: true,
21654 lineWidth: 1,
21655 drawOnChartArea: true,
21656 drawTicks: true,
21657 tickLength: 8,
21658 tickWidth: (_ctx, options)=>options.lineWidth,
21659 tickColor: (_ctx, options)=>options.color,
21660 offset: false
21661 },
21662 border: {
21663 display: true,
21664 dash: [],
21665 dashOffset: 0.0,
21666 width: 1
21667 },
21668 title: {
21669 display: false,
21670 text: '',
21671 padding: {
21672 top: 4,
21673 bottom: 4
21674 }
21675 },
21676 ticks: {
21677 minRotation: 0,
21678 maxRotation: 50,
21679 mirror: false,
21680 textStrokeWidth: 0,
21681 textStrokeColor: '',
21682 padding: 3,
21683 display: true,
21684 autoSkip: true,
21685 autoSkipPadding: 3,
21686 labelOffset: 0,
21687 callback: Ticks.formatters.values,
21688 minor: {},
21689 major: {},
21690 align: 'center',
21691 crossAlign: 'near',
21692 showLabelBackdrop: false,
21693 backdropColor: 'rgba(255, 255, 255, 0.75)',
21694 backdropPadding: 2
21695 }
21696 });
21697 defaults.route('scale.ticks', 'color', '', 'color');
21698 defaults.route('scale.grid', 'color', '', 'borderColor');
21699 defaults.route('scale.border', 'color', '', 'borderColor');
21700 defaults.route('scale.title', 'color', '', 'color');
21701 defaults.describe('scale', {
21702 _fallback: false,
21703 _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
21704 _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'
21705 });
21706 defaults.describe('scales', {
21707 _fallback: 'scale'
21708 });
21709 defaults.describe('scale.ticks', {
21710 _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',
21711 _indexable: (name)=>name !== 'backdropPadding'
21712 });
21713 }
21714
21715 const overrides = Object.create(null);
21716 const descriptors = Object.create(null);
21717 function getScope$1(node, key) {
21718 if (!key) {
21719 return node;
21720 }
21721 const keys = key.split('.');
21722 for(let i = 0, n = keys.length; i < n; ++i){
21723 const k = keys[i];
21724 node = node[k] || (node[k] = Object.create(null));
21725 }
21726 return node;
21727 }
21728 function set(root, scope, values) {
21729 if (typeof scope === 'string') {
21730 return merge(getScope$1(root, scope), values);
21731 }
21732 return merge(getScope$1(root, ''), scope);
21733 }
21734 class Defaults {
21735 constructor(_descriptors, _appliers){
21736 this.animation = undefined;
21737 this.backgroundColor = 'rgba(0,0,0,0.1)';
21738 this.borderColor = 'rgba(0,0,0,0.1)';
21739 this.color = '#666';
21740 this.datasets = {};
21741 this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio();
21742 this.elements = {};
21743 this.events = [
21744 'mousemove',
21745 'mouseout',
21746 'click',
21747 'touchstart',
21748 'touchmove'
21749 ];
21750 this.font = {
21751 family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
21752 size: 12,
21753 style: 'normal',
21754 lineHeight: 1.2,
21755 weight: null
21756 };
21757 this.hover = {};
21758 this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor);
21759 this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor);
21760 this.hoverColor = (ctx, options)=>getHoverColor(options.color);
21761 this.indexAxis = 'x';
21762 this.interaction = {
21763 mode: 'nearest',
21764 intersect: true,
21765 includeInvisible: false
21766 };
21767 this.maintainAspectRatio = true;
21768 this.onHover = null;
21769 this.onClick = null;
21770 this.parsing = true;
21771 this.plugins = {};
21772 this.responsive = true;
21773 this.scale = undefined;
21774 this.scales = {};
21775 this.showLine = true;
21776 this.drawActiveElementsOnTop = true;
21777 this.describe(_descriptors);
21778 this.apply(_appliers);
21779 }
21780 set(scope, values) {
21781 return set(this, scope, values);
21782 }
21783 get(scope) {
21784 return getScope$1(this, scope);
21785 }
21786 describe(scope, values) {
21787 return set(descriptors, scope, values);
21788 }
21789 override(scope, values) {
21790 return set(overrides, scope, values);
21791 }
21792 route(scope, name, targetScope, targetName) {
21793 const scopeObject = getScope$1(this, scope);
21794 const targetScopeObject = getScope$1(this, targetScope);
21795 const privateName = '_' + name;
21796 Object.defineProperties(scopeObject, {
21797 [privateName]: {
21798 value: scopeObject[name],
21799 writable: true
21800 },
21801 [name]: {
21802 enumerable: true,
21803 get () {
21804 const local = this[privateName];
21805 const target = targetScopeObject[targetName];
21806 if (isObject(local)) {
21807 return Object.assign({}, target, local);
21808 }
21809 return valueOrDefault(local, target);
21810 },
21811 set (value) {
21812 this[privateName] = value;
21813 }
21814 }
21815 });
21816 }
21817 apply(appliers) {
21818 appliers.forEach((apply)=>apply(this));
21819 }
21820 }
21821 var defaults = /* #__PURE__ */ new Defaults({
21822 _scriptable: (name)=>!name.startsWith('on'),
21823 _indexable: (name)=>name !== 'events',
21824 hover: {
21825 _fallback: 'interaction'
21826 },
21827 interaction: {
21828 _scriptable: false,
21829 _indexable: false
21830 }
21831 }, [
21832 applyAnimationsDefaults,
21833 applyLayoutsDefaults,
21834 applyScaleDefaults
21835 ]);
21836
21837 /**
21838 * Converts the given font object into a CSS font string.
21839 * @param font - A font object.
21840 * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
21841 * @private
21842 */ function toFontString(font) {
21843 if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
21844 return null;
21845 }
21846 return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family;
21847 }
21848 /**
21849 * @private
21850 */ function _measureText(ctx, data, gc, longest, string) {
21851 let textWidth = data[string];
21852 if (!textWidth) {
21853 textWidth = data[string] = ctx.measureText(string).width;
21854 gc.push(string);
21855 }
21856 if (textWidth > longest) {
21857 longest = textWidth;
21858 }
21859 return longest;
21860 }
21861 /**
21862 * @private
21863 */ // eslint-disable-next-line complexity
21864 function _longestText(ctx, font, arrayOfThings, cache) {
21865 cache = cache || {};
21866 let data = cache.data = cache.data || {};
21867 let gc = cache.garbageCollect = cache.garbageCollect || [];
21868 if (cache.font !== font) {
21869 data = cache.data = {};
21870 gc = cache.garbageCollect = [];
21871 cache.font = font;
21872 }
21873 ctx.save();
21874 ctx.font = font;
21875 let longest = 0;
21876 const ilen = arrayOfThings.length;
21877 let i, j, jlen, thing, nestedThing;
21878 for(i = 0; i < ilen; i++){
21879 thing = arrayOfThings[i];
21880 // Undefined strings and arrays should not be measured
21881 if (thing !== undefined && thing !== null && !isArray(thing)) {
21882 longest = _measureText(ctx, data, gc, longest, thing);
21883 } else if (isArray(thing)) {
21884 // if it is an array lets measure each element
21885 // to do maybe simplify this function a bit so we can do this more recursively?
21886 for(j = 0, jlen = thing.length; j < jlen; j++){
21887 nestedThing = thing[j];
21888 // Undefined strings and arrays should not be measured
21889 if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
21890 longest = _measureText(ctx, data, gc, longest, nestedThing);
21891 }
21892 }
21893 }
21894 }
21895 ctx.restore();
21896 const gcLen = gc.length / 2;
21897 if (gcLen > arrayOfThings.length) {
21898 for(i = 0; i < gcLen; i++){
21899 delete data[gc[i]];
21900 }
21901 gc.splice(0, gcLen);
21902 }
21903 return longest;
21904 }
21905 /**
21906 * Returns the aligned pixel value to avoid anti-aliasing blur
21907 * @param chart - The chart instance.
21908 * @param pixel - A pixel value.
21909 * @param width - The width of the element.
21910 * @returns The aligned pixel value.
21911 * @private
21912 */ function _alignPixel(chart, pixel, width) {
21913 const devicePixelRatio = chart.currentDevicePixelRatio;
21914 const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
21915 return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
21916 }
21917 /**
21918 * Clears the entire canvas.
21919 */ function clearCanvas(canvas, ctx) {
21920 if (!ctx && !canvas) {
21921 return;
21922 }
21923 ctx = ctx || canvas.getContext('2d');
21924 ctx.save();
21925 // canvas.width and canvas.height do not consider the canvas transform,
21926 // while clearRect does
21927 ctx.resetTransform();
21928 ctx.clearRect(0, 0, canvas.width, canvas.height);
21929 ctx.restore();
21930 }
21931 function drawPoint(ctx, options, x, y) {
21932 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21933 drawPointLegend(ctx, options, x, y, null);
21934 }
21935 // eslint-disable-next-line complexity
21936 function drawPointLegend(ctx, options, x, y, w) {
21937 let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;
21938 const style = options.pointStyle;
21939 const rotation = options.rotation;
21940 const radius = options.radius;
21941 let rad = (rotation || 0) * RAD_PER_DEG;
21942 if (style && typeof style === 'object') {
21943 type = style.toString();
21944 if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
21945 ctx.save();
21946 ctx.translate(x, y);
21947 ctx.rotate(rad);
21948 ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
21949 ctx.restore();
21950 return;
21951 }
21952 }
21953 if (isNaN(radius) || radius <= 0) {
21954 return;
21955 }
21956 ctx.beginPath();
21957 switch(style){
21958 // Default includes circle
21959 default:
21960 if (w) {
21961 ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);
21962 } else {
21963 ctx.arc(x, y, radius, 0, TAU);
21964 }
21965 ctx.closePath();
21966 break;
21967 case 'triangle':
21968 width = w ? w / 2 : radius;
21969 ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
21970 rad += TWO_THIRDS_PI;
21971 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
21972 rad += TWO_THIRDS_PI;
21973 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
21974 ctx.closePath();
21975 break;
21976 case 'rectRounded':
21977 // NOTE: the rounded rect implementation changed to use `arc` instead of
21978 // `quadraticCurveTo` since it generates better results when rect is
21979 // almost a circle. 0.516 (instead of 0.5) produces results with visually
21980 // closer proportion to the previous impl and it is inscribed in the
21981 // circle with `radius`. For more details, see the following PRs:
21982 // https://github.com/chartjs/Chart.js/issues/5597
21983 // https://github.com/chartjs/Chart.js/issues/5858
21984 cornerRadius = radius * 0.516;
21985 size = radius - cornerRadius;
21986 xOffset = Math.cos(rad + QUARTER_PI) * size;
21987 xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
21988 yOffset = Math.sin(rad + QUARTER_PI) * size;
21989 yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
21990 ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
21991 ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);
21992 ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);
21993 ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
21994 ctx.closePath();
21995 break;
21996 case 'rect':
21997 if (!rotation) {
21998 size = Math.SQRT1_2 * radius;
21999 width = w ? w / 2 : size;
22000 ctx.rect(x - width, y - size, 2 * width, 2 * size);
22001 break;
22002 }
22003 rad += QUARTER_PI;
22004 /* falls through */ case 'rectRot':
22005 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22006 xOffset = Math.cos(rad) * radius;
22007 yOffset = Math.sin(rad) * radius;
22008 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22009 ctx.moveTo(x - xOffsetW, y - yOffset);
22010 ctx.lineTo(x + yOffsetW, y - xOffset);
22011 ctx.lineTo(x + xOffsetW, y + yOffset);
22012 ctx.lineTo(x - yOffsetW, y + xOffset);
22013 ctx.closePath();
22014 break;
22015 case 'crossRot':
22016 rad += QUARTER_PI;
22017 /* falls through */ case 'cross':
22018 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22019 xOffset = Math.cos(rad) * radius;
22020 yOffset = Math.sin(rad) * radius;
22021 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22022 ctx.moveTo(x - xOffsetW, y - yOffset);
22023 ctx.lineTo(x + xOffsetW, y + yOffset);
22024 ctx.moveTo(x + yOffsetW, y - xOffset);
22025 ctx.lineTo(x - yOffsetW, y + xOffset);
22026 break;
22027 case 'star':
22028 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22029 xOffset = Math.cos(rad) * radius;
22030 yOffset = Math.sin(rad) * radius;
22031 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22032 ctx.moveTo(x - xOffsetW, y - yOffset);
22033 ctx.lineTo(x + xOffsetW, y + yOffset);
22034 ctx.moveTo(x + yOffsetW, y - xOffset);
22035 ctx.lineTo(x - yOffsetW, y + xOffset);
22036 rad += QUARTER_PI;
22037 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22038 xOffset = Math.cos(rad) * radius;
22039 yOffset = Math.sin(rad) * radius;
22040 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22041 ctx.moveTo(x - xOffsetW, y - yOffset);
22042 ctx.lineTo(x + xOffsetW, y + yOffset);
22043 ctx.moveTo(x + yOffsetW, y - xOffset);
22044 ctx.lineTo(x - yOffsetW, y + xOffset);
22045 break;
22046 case 'line':
22047 xOffset = w ? w / 2 : Math.cos(rad) * radius;
22048 yOffset = Math.sin(rad) * radius;
22049 ctx.moveTo(x - xOffset, y - yOffset);
22050 ctx.lineTo(x + xOffset, y + yOffset);
22051 break;
22052 case 'dash':
22053 ctx.moveTo(x, y);
22054 ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);
22055 break;
22056 case false:
22057 ctx.closePath();
22058 break;
22059 }
22060 ctx.fill();
22061 if (options.borderWidth > 0) {
22062 ctx.stroke();
22063 }
22064 }
22065 /**
22066 * Returns true if the point is inside the rectangle
22067 * @param point - The point to test
22068 * @param area - The rectangle
22069 * @param margin - allowed margin
22070 * @private
22071 */ function _isPointInArea(point, area, margin) {
22072 margin = margin || 0.5; // margin - default is to match rounded decimals
22073 return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;
22074 }
22075 function clipArea(ctx, area) {
22076 ctx.save();
22077 ctx.beginPath();
22078 ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
22079 ctx.clip();
22080 }
22081 function unclipArea(ctx) {
22082 ctx.restore();
22083 }
22084 /**
22085 * @private
22086 */ function _steppedLineTo(ctx, previous, target, flip, mode) {
22087 if (!previous) {
22088 return ctx.lineTo(target.x, target.y);
22089 }
22090 if (mode === 'middle') {
22091 const midpoint = (previous.x + target.x) / 2.0;
22092 ctx.lineTo(midpoint, previous.y);
22093 ctx.lineTo(midpoint, target.y);
22094 } else if (mode === 'after' !== !!flip) {
22095 ctx.lineTo(previous.x, target.y);
22096 } else {
22097 ctx.lineTo(target.x, previous.y);
22098 }
22099 ctx.lineTo(target.x, target.y);
22100 }
22101 /**
22102 * @private
22103 */ function _bezierCurveTo(ctx, previous, target, flip) {
22104 if (!previous) {
22105 return ctx.lineTo(target.x, target.y);
22106 }
22107 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);
22108 }
22109 function setRenderOpts(ctx, opts) {
22110 if (opts.translation) {
22111 ctx.translate(opts.translation[0], opts.translation[1]);
22112 }
22113 if (!isNullOrUndef(opts.rotation)) {
22114 ctx.rotate(opts.rotation);
22115 }
22116 if (opts.color) {
22117 ctx.fillStyle = opts.color;
22118 }
22119 if (opts.textAlign) {
22120 ctx.textAlign = opts.textAlign;
22121 }
22122 if (opts.textBaseline) {
22123 ctx.textBaseline = opts.textBaseline;
22124 }
22125 }
22126 function decorateText(ctx, x, y, line, opts) {
22127 if (opts.strikethrough || opts.underline) {
22128 /**
22129 * Now that IE11 support has been dropped, we can use more
22130 * of the TextMetrics object. The actual bounding boxes
22131 * are unflagged in Chrome, Firefox, Edge, and Safari so they
22132 * can be safely used.
22133 * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
22134 */ const metrics = ctx.measureText(line);
22135 const left = x - metrics.actualBoundingBoxLeft;
22136 const right = x + metrics.actualBoundingBoxRight;
22137 const top = y - metrics.actualBoundingBoxAscent;
22138 const bottom = y + metrics.actualBoundingBoxDescent;
22139 const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
22140 ctx.strokeStyle = ctx.fillStyle;
22141 ctx.beginPath();
22142 ctx.lineWidth = opts.decorationWidth || 2;
22143 ctx.moveTo(left, yDecoration);
22144 ctx.lineTo(right, yDecoration);
22145 ctx.stroke();
22146 }
22147 }
22148 function drawBackdrop(ctx, opts) {
22149 const oldColor = ctx.fillStyle;
22150 ctx.fillStyle = opts.color;
22151 ctx.fillRect(opts.left, opts.top, opts.width, opts.height);
22152 ctx.fillStyle = oldColor;
22153 }
22154 /**
22155 * Render text onto the canvas
22156 */ function renderText(ctx, text, x, y, font, opts = {}) {
22157 const lines = isArray(text) ? text : [
22158 text
22159 ];
22160 const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
22161 let i, line;
22162 ctx.save();
22163 ctx.font = font.string;
22164 setRenderOpts(ctx, opts);
22165 for(i = 0; i < lines.length; ++i){
22166 line = lines[i];
22167 if (opts.backdrop) {
22168 drawBackdrop(ctx, opts.backdrop);
22169 }
22170 if (stroke) {
22171 if (opts.strokeColor) {
22172 ctx.strokeStyle = opts.strokeColor;
22173 }
22174 if (!isNullOrUndef(opts.strokeWidth)) {
22175 ctx.lineWidth = opts.strokeWidth;
22176 }
22177 ctx.strokeText(line, x, y, opts.maxWidth);
22178 }
22179 ctx.fillText(line, x, y, opts.maxWidth);
22180 decorateText(ctx, x, y, line, opts);
22181 y += Number(font.lineHeight);
22182 }
22183 ctx.restore();
22184 }
22185 /**
22186 * Add a path of a rectangle with rounded corners to the current sub-path
22187 * @param ctx - Context
22188 * @param rect - Bounding rect
22189 */ function addRoundedRectPath(ctx, rect) {
22190 const { x , y , w , h , radius } = rect;
22191 // top left arc
22192 ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
22193 // line from top left to bottom left
22194 ctx.lineTo(x, y + h - radius.bottomLeft);
22195 // bottom left arc
22196 ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
22197 // line from bottom left to bottom right
22198 ctx.lineTo(x + w - radius.bottomRight, y + h);
22199 // bottom right arc
22200 ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
22201 // line from bottom right to top right
22202 ctx.lineTo(x + w, y + radius.topRight);
22203 // top right arc
22204 ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
22205 // line from top right to top left
22206 ctx.lineTo(x + radius.topLeft, y);
22207 }
22208
22209 const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
22210 const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
22211 /**
22212 * @alias Chart.helpers.options
22213 * @namespace
22214 */ /**
22215 * Converts the given line height `value` in pixels for a specific font `size`.
22216 * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
22217 * @param size - The font size (in pixels) used to resolve relative `value`.
22218 * @returns The effective line height in pixels (size * 1.2 if value is invalid).
22219 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
22220 * @since 2.7.0
22221 */ function toLineHeight(value, size) {
22222 const matches = ('' + value).match(LINE_HEIGHT);
22223 if (!matches || matches[1] === 'normal') {
22224 return size * 1.2;
22225 }
22226 value = +matches[2];
22227 switch(matches[3]){
22228 case 'px':
22229 return value;
22230 case '%':
22231 value /= 100;
22232 break;
22233 }
22234 return size * value;
22235 }
22236 const numberOrZero = (v)=>+v || 0;
22237 function _readValueToProps(value, props) {
22238 const ret = {};
22239 const objProps = isObject(props);
22240 const keys = objProps ? Object.keys(props) : props;
22241 const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value;
22242 for (const prop of keys){
22243 ret[prop] = numberOrZero(read(prop));
22244 }
22245 return ret;
22246 }
22247 /**
22248 * Converts the given value into a TRBL object.
22249 * @param value - If a number, set the value to all TRBL component,
22250 * else, if an object, use defined properties and sets undefined ones to 0.
22251 * x / y are shorthands for same value for left/right and top/bottom.
22252 * @returns The padding values (top, right, bottom, left)
22253 * @since 3.0.0
22254 */ function toTRBL(value) {
22255 return _readValueToProps(value, {
22256 top: 'y',
22257 right: 'x',
22258 bottom: 'y',
22259 left: 'x'
22260 });
22261 }
22262 /**
22263 * Converts the given value into a TRBL corners object (similar with css border-radius).
22264 * @param value - If a number, set the value to all TRBL corner components,
22265 * else, if an object, use defined properties and sets undefined ones to 0.
22266 * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)
22267 * @since 3.0.0
22268 */ function toTRBLCorners(value) {
22269 return _readValueToProps(value, [
22270 'topLeft',
22271 'topRight',
22272 'bottomLeft',
22273 'bottomRight'
22274 ]);
22275 }
22276 /**
22277 * Converts the given value into a padding object with pre-computed width/height.
22278 * @param value - If a number, set the value to all TRBL component,
22279 * else, if an object, use defined properties and sets undefined ones to 0.
22280 * x / y are shorthands for same value for left/right and top/bottom.
22281 * @returns The padding values (top, right, bottom, left, width, height)
22282 * @since 2.7.0
22283 */ function toPadding(value) {
22284 const obj = toTRBL(value);
22285 obj.width = obj.left + obj.right;
22286 obj.height = obj.top + obj.bottom;
22287 return obj;
22288 }
22289 /**
22290 * Parses font options and returns the font object.
22291 * @param options - A object that contains font options to be parsed.
22292 * @param fallback - A object that contains fallback font options.
22293 * @return The font object.
22294 * @private
22295 */ function toFont(options, fallback) {
22296 options = options || {};
22297 fallback = fallback || defaults.font;
22298 let size = valueOrDefault(options.size, fallback.size);
22299 if (typeof size === 'string') {
22300 size = parseInt(size, 10);
22301 }
22302 let style = valueOrDefault(options.style, fallback.style);
22303 if (style && !('' + style).match(FONT_STYLE)) {
22304 console.warn('Invalid font style specified: "' + style + '"');
22305 style = undefined;
22306 }
22307 const font = {
22308 family: valueOrDefault(options.family, fallback.family),
22309 lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
22310 size,
22311 style,
22312 weight: valueOrDefault(options.weight, fallback.weight),
22313 string: ''
22314 };
22315 font.string = toFontString(font);
22316 return font;
22317 }
22318 /**
22319 * Evaluates the given `inputs` sequentially and returns the first defined value.
22320 * @param inputs - An array of values, falling back to the last value.
22321 * @param context - If defined and the current value is a function, the value
22322 * is called with `context` as first argument and the result becomes the new input.
22323 * @param index - If defined and the current value is an array, the value
22324 * at `index` become the new input.
22325 * @param info - object to return information about resolution in
22326 * @param info.cacheable - Will be set to `false` if option is not cacheable.
22327 * @since 2.7.0
22328 */ function resolve(inputs, context, index, info) {
22329 let cacheable = true;
22330 let i, ilen, value;
22331 for(i = 0, ilen = inputs.length; i < ilen; ++i){
22332 value = inputs[i];
22333 if (value === undefined) {
22334 continue;
22335 }
22336 if (context !== undefined && typeof value === 'function') {
22337 value = value(context);
22338 cacheable = false;
22339 }
22340 if (index !== undefined && isArray(value)) {
22341 value = value[index % value.length];
22342 cacheable = false;
22343 }
22344 if (value !== undefined) {
22345 if (info && !cacheable) {
22346 info.cacheable = false;
22347 }
22348 return value;
22349 }
22350 }
22351 }
22352 /**
22353 * @param minmax
22354 * @param grace
22355 * @param beginAtZero
22356 * @private
22357 */ function _addGrace(minmax, grace, beginAtZero) {
22358 const { min , max } = minmax;
22359 const change = toDimension(grace, (max - min) / 2);
22360 const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;
22361 return {
22362 min: keepZero(min, -Math.abs(change)),
22363 max: keepZero(max, change)
22364 };
22365 }
22366 function createContext(parentContext, context) {
22367 return Object.assign(Object.create(parentContext), context);
22368 }
22369
22370 /**
22371 * Creates a Proxy for resolving raw values for options.
22372 * @param scopes - The option scopes to look for values, in resolution order
22373 * @param prefixes - The prefixes for values, in resolution order.
22374 * @param rootScopes - The root option scopes
22375 * @param fallback - Parent scopes fallback
22376 * @param getTarget - callback for getting the target for changed values
22377 * @returns Proxy
22378 * @private
22379 */ function _createResolver(scopes, prefixes = [
22380 ''
22381 ], rootScopes, fallback, getTarget = ()=>scopes[0]) {
22382 const finalRootScopes = rootScopes || scopes;
22383 if (typeof fallback === 'undefined') {
22384 fallback = _resolve('_fallback', scopes);
22385 }
22386 const cache = {
22387 [Symbol.toStringTag]: 'Object',
22388 _cacheable: true,
22389 _scopes: scopes,
22390 _rootScopes: finalRootScopes,
22391 _fallback: fallback,
22392 _getTarget: getTarget,
22393 override: (scope)=>_createResolver([
22394 scope,
22395 ...scopes
22396 ], prefixes, finalRootScopes, fallback)
22397 };
22398 return new Proxy(cache, {
22399 /**
22400 * A trap for the delete operator.
22401 */ deleteProperty (target, prop) {
22402 delete target[prop]; // remove from cache
22403 delete target._keys; // remove cached keys
22404 delete scopes[0][prop]; // remove from top level scope
22405 return true;
22406 },
22407 /**
22408 * A trap for getting property values.
22409 */ get (target, prop) {
22410 return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));
22411 },
22412 /**
22413 * A trap for Object.getOwnPropertyDescriptor.
22414 * Also used by Object.hasOwnProperty.
22415 */ getOwnPropertyDescriptor (target, prop) {
22416 return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
22417 },
22418 /**
22419 * A trap for Object.getPrototypeOf.
22420 */ getPrototypeOf () {
22421 return Reflect.getPrototypeOf(scopes[0]);
22422 },
22423 /**
22424 * A trap for the in operator.
22425 */ has (target, prop) {
22426 return getKeysFromAllScopes(target).includes(prop);
22427 },
22428 /**
22429 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22430 */ ownKeys (target) {
22431 return getKeysFromAllScopes(target);
22432 },
22433 /**
22434 * A trap for setting property values.
22435 */ set (target, prop, value) {
22436 const storage = target._storage || (target._storage = getTarget());
22437 target[prop] = storage[prop] = value; // set to top level scope + cache
22438 delete target._keys; // remove cached keys
22439 return true;
22440 }
22441 });
22442 }
22443 /**
22444 * Returns an Proxy for resolving option values with context.
22445 * @param proxy - The Proxy returned by `_createResolver`
22446 * @param context - Context object for scriptable/indexable options
22447 * @param subProxy - The proxy provided for scriptable options
22448 * @param descriptorDefaults - Defaults for descriptors
22449 * @private
22450 */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {
22451 const cache = {
22452 _cacheable: false,
22453 _proxy: proxy,
22454 _context: context,
22455 _subProxy: subProxy,
22456 _stack: new Set(),
22457 _descriptors: _descriptors(proxy, descriptorDefaults),
22458 setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),
22459 override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
22460 };
22461 return new Proxy(cache, {
22462 /**
22463 * A trap for the delete operator.
22464 */ deleteProperty (target, prop) {
22465 delete target[prop]; // remove from cache
22466 delete proxy[prop]; // remove from proxy
22467 return true;
22468 },
22469 /**
22470 * A trap for getting property values.
22471 */ get (target, prop, receiver) {
22472 return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));
22473 },
22474 /**
22475 * A trap for Object.getOwnPropertyDescriptor.
22476 * Also used by Object.hasOwnProperty.
22477 */ getOwnPropertyDescriptor (target, prop) {
22478 return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
22479 enumerable: true,
22480 configurable: true
22481 } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);
22482 },
22483 /**
22484 * A trap for Object.getPrototypeOf.
22485 */ getPrototypeOf () {
22486 return Reflect.getPrototypeOf(proxy);
22487 },
22488 /**
22489 * A trap for the in operator.
22490 */ has (target, prop) {
22491 return Reflect.has(proxy, prop);
22492 },
22493 /**
22494 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22495 */ ownKeys () {
22496 return Reflect.ownKeys(proxy);
22497 },
22498 /**
22499 * A trap for setting property values.
22500 */ set (target, prop, value) {
22501 proxy[prop] = value; // set to proxy
22502 delete target[prop]; // remove from cache
22503 return true;
22504 }
22505 });
22506 }
22507 /**
22508 * @private
22509 */ function _descriptors(proxy, defaults = {
22510 scriptable: true,
22511 indexable: true
22512 }) {
22513 const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;
22514 return {
22515 allKeys: _allKeys,
22516 scriptable: _scriptable,
22517 indexable: _indexable,
22518 isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,
22519 isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable
22520 };
22521 }
22522 const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;
22523 const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);
22524 function _cached(target, prop, resolve) {
22525 if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {
22526 return target[prop];
22527 }
22528 const value = resolve();
22529 // cache the resolved value
22530 target[prop] = value;
22531 return value;
22532 }
22533 function _resolveWithContext(target, prop, receiver) {
22534 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22535 let value = _proxy[prop]; // resolve from proxy
22536 // resolve with context
22537 if (isFunction(value) && descriptors.isScriptable(prop)) {
22538 value = _resolveScriptable(prop, value, target, receiver);
22539 }
22540 if (isArray(value) && value.length) {
22541 value = _resolveArray(prop, value, target, descriptors.isIndexable);
22542 }
22543 if (needsSubResolver(prop, value)) {
22544 // if the resolved value is an object, create a sub resolver for it
22545 value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
22546 }
22547 return value;
22548 }
22549 function _resolveScriptable(prop, getValue, target, receiver) {
22550 const { _proxy , _context , _subProxy , _stack } = target;
22551 if (_stack.has(prop)) {
22552 throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
22553 }
22554 _stack.add(prop);
22555 let value = getValue(_context, _subProxy || receiver);
22556 _stack.delete(prop);
22557 if (needsSubResolver(prop, value)) {
22558 // When scriptable option returns an object, create a resolver on that.
22559 value = createSubResolver(_proxy._scopes, _proxy, prop, value);
22560 }
22561 return value;
22562 }
22563 function _resolveArray(prop, value, target, isIndexable) {
22564 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22565 if (typeof _context.index !== 'undefined' && isIndexable(prop)) {
22566 return value[_context.index % value.length];
22567 } else if (isObject(value[0])) {
22568 // Array of objects, return array or resolvers
22569 const arr = value;
22570 const scopes = _proxy._scopes.filter((s)=>s !== arr);
22571 value = [];
22572 for (const item of arr){
22573 const resolver = createSubResolver(scopes, _proxy, prop, item);
22574 value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
22575 }
22576 }
22577 return value;
22578 }
22579 function resolveFallback(fallback, prop, value) {
22580 return isFunction(fallback) ? fallback(prop, value) : fallback;
22581 }
22582 const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
22583 function addScopes(set, parentScopes, key, parentFallback, value) {
22584 for (const parent of parentScopes){
22585 const scope = getScope(key, parent);
22586 if (scope) {
22587 set.add(scope);
22588 const fallback = resolveFallback(scope._fallback, key, value);
22589 if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {
22590 // When we reach the descriptor that defines a new _fallback, return that.
22591 // The fallback will resume to that new scope.
22592 return fallback;
22593 }
22594 } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {
22595 // Fallback to `false` results to `false`, when falling back to different key.
22596 // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`
22597 return null;
22598 }
22599 }
22600 return false;
22601 }
22602 function createSubResolver(parentScopes, resolver, prop, value) {
22603 const rootScopes = resolver._rootScopes;
22604 const fallback = resolveFallback(resolver._fallback, prop, value);
22605 const allScopes = [
22606 ...parentScopes,
22607 ...rootScopes
22608 ];
22609 const set = new Set();
22610 set.add(value);
22611 let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
22612 if (key === null) {
22613 return false;
22614 }
22615 if (typeof fallback !== 'undefined' && fallback !== prop) {
22616 key = addScopesFromKey(set, allScopes, fallback, key, value);
22617 if (key === null) {
22618 return false;
22619 }
22620 }
22621 return _createResolver(Array.from(set), [
22622 ''
22623 ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));
22624 }
22625 function addScopesFromKey(set, allScopes, key, fallback, item) {
22626 while(key){
22627 key = addScopes(set, allScopes, key, fallback, item);
22628 }
22629 return key;
22630 }
22631 function subGetTarget(resolver, prop, value) {
22632 const parent = resolver._getTarget();
22633 if (!(prop in parent)) {
22634 parent[prop] = {};
22635 }
22636 const target = parent[prop];
22637 if (isArray(target) && isObject(value)) {
22638 // For array of objects, the object is used to store updated values
22639 return value;
22640 }
22641 return target || {};
22642 }
22643 function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
22644 let value;
22645 for (const prefix of prefixes){
22646 value = _resolve(readKey(prefix, prop), scopes);
22647 if (typeof value !== 'undefined') {
22648 return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
22649 }
22650 }
22651 }
22652 function _resolve(key, scopes) {
22653 for (const scope of scopes){
22654 if (!scope) {
22655 continue;
22656 }
22657 const value = scope[key];
22658 if (typeof value !== 'undefined') {
22659 return value;
22660 }
22661 }
22662 }
22663 function getKeysFromAllScopes(target) {
22664 let keys = target._keys;
22665 if (!keys) {
22666 keys = target._keys = resolveKeysFromAllScopes(target._scopes);
22667 }
22668 return keys;
22669 }
22670 function resolveKeysFromAllScopes(scopes) {
22671 const set = new Set();
22672 for (const scope of scopes){
22673 for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){
22674 set.add(key);
22675 }
22676 }
22677 return Array.from(set);
22678 }
22679 function _parseObjectDataRadialScale(meta, data, start, count) {
22680 const { iScale } = meta;
22681 const { key ='r' } = this._parsing;
22682 const parsed = new Array(count);
22683 let i, ilen, index, item;
22684 for(i = 0, ilen = count; i < ilen; ++i){
22685 index = i + start;
22686 item = data[index];
22687 parsed[i] = {
22688 r: iScale.parse(resolveObjectKey(item, key), index)
22689 };
22690 }
22691 return parsed;
22692 }
22693
22694 const EPSILON = Number.EPSILON || 1e-14;
22695 const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];
22696 const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';
22697 function splineCurve(firstPoint, middlePoint, afterPoint, t) {
22698 // Props to Rob Spencer at scaled innovation for his post on splining between points
22699 // http://scaledinnovation.com/analytics/splines/aboutSplines.html
22700 // This function must also respect "skipped" points
22701 const previous = firstPoint.skip ? middlePoint : firstPoint;
22702 const current = middlePoint;
22703 const next = afterPoint.skip ? middlePoint : afterPoint;
22704 const d01 = distanceBetweenPoints(current, previous);
22705 const d12 = distanceBetweenPoints(next, current);
22706 let s01 = d01 / (d01 + d12);
22707 let s12 = d12 / (d01 + d12);
22708 // If all points are the same, s01 & s02 will be inf
22709 s01 = isNaN(s01) ? 0 : s01;
22710 s12 = isNaN(s12) ? 0 : s12;
22711 const fa = t * s01; // scaling factor for triangle Ta
22712 const fb = t * s12;
22713 return {
22714 previous: {
22715 x: current.x - fa * (next.x - previous.x),
22716 y: current.y - fa * (next.y - previous.y)
22717 },
22718 next: {
22719 x: current.x + fb * (next.x - previous.x),
22720 y: current.y + fb * (next.y - previous.y)
22721 }
22722 };
22723 }
22724 /**
22725 * Adjust tangents to ensure monotonic properties
22726 */ function monotoneAdjust(points, deltaK, mK) {
22727 const pointsLen = points.length;
22728 let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
22729 let pointAfter = getPoint(points, 0);
22730 for(let i = 0; i < pointsLen - 1; ++i){
22731 pointCurrent = pointAfter;
22732 pointAfter = getPoint(points, i + 1);
22733 if (!pointCurrent || !pointAfter) {
22734 continue;
22735 }
22736 if (almostEquals(deltaK[i], 0, EPSILON)) {
22737 mK[i] = mK[i + 1] = 0;
22738 continue;
22739 }
22740 alphaK = mK[i] / deltaK[i];
22741 betaK = mK[i + 1] / deltaK[i];
22742 squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
22743 if (squaredMagnitude <= 9) {
22744 continue;
22745 }
22746 tauK = 3 / Math.sqrt(squaredMagnitude);
22747 mK[i] = alphaK * tauK * deltaK[i];
22748 mK[i + 1] = betaK * tauK * deltaK[i];
22749 }
22750 }
22751 function monotoneCompute(points, mK, indexAxis = 'x') {
22752 const valueAxis = getValueAxis(indexAxis);
22753 const pointsLen = points.length;
22754 let delta, pointBefore, pointCurrent;
22755 let pointAfter = getPoint(points, 0);
22756 for(let i = 0; i < pointsLen; ++i){
22757 pointBefore = pointCurrent;
22758 pointCurrent = pointAfter;
22759 pointAfter = getPoint(points, i + 1);
22760 if (!pointCurrent) {
22761 continue;
22762 }
22763 const iPixel = pointCurrent[indexAxis];
22764 const vPixel = pointCurrent[valueAxis];
22765 if (pointBefore) {
22766 delta = (iPixel - pointBefore[indexAxis]) / 3;
22767 pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
22768 pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
22769 }
22770 if (pointAfter) {
22771 delta = (pointAfter[indexAxis] - iPixel) / 3;
22772 pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
22773 pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
22774 }
22775 }
22776 }
22777 /**
22778 * This function calculates Bézier control points in a similar way than |splineCurve|,
22779 * but preserves monotonicity of the provided data and ensures no local extremums are added
22780 * between the dataset discrete points due to the interpolation.
22781 * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
22782 */ function splineCurveMonotone(points, indexAxis = 'x') {
22783 const valueAxis = getValueAxis(indexAxis);
22784 const pointsLen = points.length;
22785 const deltaK = Array(pointsLen).fill(0);
22786 const mK = Array(pointsLen);
22787 // Calculate slopes (deltaK) and initialize tangents (mK)
22788 let i, pointBefore, pointCurrent;
22789 let pointAfter = getPoint(points, 0);
22790 for(i = 0; i < pointsLen; ++i){
22791 pointBefore = pointCurrent;
22792 pointCurrent = pointAfter;
22793 pointAfter = getPoint(points, i + 1);
22794 if (!pointCurrent) {
22795 continue;
22796 }
22797 if (pointAfter) {
22798 const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
22799 // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
22800 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
22801 }
22802 mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;
22803 }
22804 monotoneAdjust(points, deltaK, mK);
22805 monotoneCompute(points, mK, indexAxis);
22806 }
22807 function capControlPoint(pt, min, max) {
22808 return Math.max(Math.min(pt, max), min);
22809 }
22810 function capBezierPoints(points, area) {
22811 let i, ilen, point, inArea, inAreaPrev;
22812 let inAreaNext = _isPointInArea(points[0], area);
22813 for(i = 0, ilen = points.length; i < ilen; ++i){
22814 inAreaPrev = inArea;
22815 inArea = inAreaNext;
22816 inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
22817 if (!inArea) {
22818 continue;
22819 }
22820 point = points[i];
22821 if (inAreaPrev) {
22822 point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
22823 point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
22824 }
22825 if (inAreaNext) {
22826 point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
22827 point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
22828 }
22829 }
22830 }
22831 /**
22832 * @private
22833 */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
22834 let i, ilen, point, controlPoints;
22835 // Only consider points that are drawn in case the spanGaps option is used
22836 if (options.spanGaps) {
22837 points = points.filter((pt)=>!pt.skip);
22838 }
22839 if (options.cubicInterpolationMode === 'monotone') {
22840 splineCurveMonotone(points, indexAxis);
22841 } else {
22842 let prev = loop ? points[points.length - 1] : points[0];
22843 for(i = 0, ilen = points.length; i < ilen; ++i){
22844 point = points[i];
22845 controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);
22846 point.cp1x = controlPoints.previous.x;
22847 point.cp1y = controlPoints.previous.y;
22848 point.cp2x = controlPoints.next.x;
22849 point.cp2y = controlPoints.next.y;
22850 prev = point;
22851 }
22852 }
22853 if (options.capBezierPoints) {
22854 capBezierPoints(points, area);
22855 }
22856 }
22857
22858 /**
22859 * @private
22860 */ function _isDomSupported() {
22861 return typeof window !== 'undefined' && typeof document !== 'undefined';
22862 }
22863 /**
22864 * @private
22865 */ function _getParentNode(domNode) {
22866 let parent = domNode.parentNode;
22867 if (parent && parent.toString() === '[object ShadowRoot]') {
22868 parent = parent.host;
22869 }
22870 return parent;
22871 }
22872 /**
22873 * convert max-width/max-height values that may be percentages into a number
22874 * @private
22875 */ function parseMaxStyle(styleValue, node, parentProperty) {
22876 let valueInPixels;
22877 if (typeof styleValue === 'string') {
22878 valueInPixels = parseInt(styleValue, 10);
22879 if (styleValue.indexOf('%') !== -1) {
22880 // percentage * size in dimension
22881 valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
22882 }
22883 } else {
22884 valueInPixels = styleValue;
22885 }
22886 return valueInPixels;
22887 }
22888 const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);
22889 function getStyle(el, property) {
22890 return getComputedStyle(el).getPropertyValue(property);
22891 }
22892 const positions = [
22893 'top',
22894 'right',
22895 'bottom',
22896 'left'
22897 ];
22898 function getPositionedStyle(styles, style, suffix) {
22899 const result = {};
22900 suffix = suffix ? '-' + suffix : '';
22901 for(let i = 0; i < 4; i++){
22902 const pos = positions[i];
22903 result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
22904 }
22905 result.width = result.left + result.right;
22906 result.height = result.top + result.bottom;
22907 return result;
22908 }
22909 const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);
22910 /**
22911 * @param e
22912 * @param canvas
22913 * @returns Canvas position
22914 */ function getCanvasPosition(e, canvas) {
22915 const touches = e.touches;
22916 const source = touches && touches.length ? touches[0] : e;
22917 const { offsetX , offsetY } = source;
22918 let box = false;
22919 let x, y;
22920 if (useOffsetPos(offsetX, offsetY, e.target)) {
22921 x = offsetX;
22922 y = offsetY;
22923 } else {
22924 const rect = canvas.getBoundingClientRect();
22925 x = source.clientX - rect.left;
22926 y = source.clientY - rect.top;
22927 box = true;
22928 }
22929 return {
22930 x,
22931 y,
22932 box
22933 };
22934 }
22935 /**
22936 * Gets an event's x, y coordinates, relative to the chart area
22937 * @param event
22938 * @param chart
22939 * @returns x and y coordinates of the event
22940 */ function getRelativePosition(event, chart) {
22941 if ('native' in event) {
22942 return event;
22943 }
22944 const { canvas , currentDevicePixelRatio } = chart;
22945 const style = getComputedStyle(canvas);
22946 const borderBox = style.boxSizing === 'border-box';
22947 const paddings = getPositionedStyle(style, 'padding');
22948 const borders = getPositionedStyle(style, 'border', 'width');
22949 const { x , y , box } = getCanvasPosition(event, canvas);
22950 const xOffset = paddings.left + (box && borders.left);
22951 const yOffset = paddings.top + (box && borders.top);
22952 let { width , height } = chart;
22953 if (borderBox) {
22954 width -= paddings.width + borders.width;
22955 height -= paddings.height + borders.height;
22956 }
22957 return {
22958 x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
22959 y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
22960 };
22961 }
22962 function getContainerSize(canvas, width, height) {
22963 let maxWidth, maxHeight;
22964 if (width === undefined || height === undefined) {
22965 const container = canvas && _getParentNode(canvas);
22966 if (!container) {
22967 width = canvas.clientWidth;
22968 height = canvas.clientHeight;
22969 } else {
22970 const rect = container.getBoundingClientRect(); // this is the border box of the container
22971 const containerStyle = getComputedStyle(container);
22972 const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
22973 const containerPadding = getPositionedStyle(containerStyle, 'padding');
22974 width = rect.width - containerPadding.width - containerBorder.width;
22975 height = rect.height - containerPadding.height - containerBorder.height;
22976 maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
22977 maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
22978 }
22979 }
22980 return {
22981 width,
22982 height,
22983 maxWidth: maxWidth || INFINITY,
22984 maxHeight: maxHeight || INFINITY
22985 };
22986 }
22987 const round1 = (v)=>Math.round(v * 10) / 10;
22988 // eslint-disable-next-line complexity
22989 function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
22990 const style = getComputedStyle(canvas);
22991 const margins = getPositionedStyle(style, 'margin');
22992 const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
22993 const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
22994 const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
22995 let { width , height } = containerSize;
22996 if (style.boxSizing === 'content-box') {
22997 const borders = getPositionedStyle(style, 'border', 'width');
22998 const paddings = getPositionedStyle(style, 'padding');
22999 width -= paddings.width + borders.width;
23000 height -= paddings.height + borders.height;
23001 }
23002 width = Math.max(0, width - margins.width);
23003 height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
23004 width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
23005 height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
23006 if (width && !height) {
23007 // https://github.com/chartjs/Chart.js/issues/4659
23008 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)
23009 height = round1(width / 2);
23010 }
23011 const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;
23012 if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
23013 height = containerSize.height;
23014 width = round1(Math.floor(height * aspectRatio));
23015 }
23016 return {
23017 width,
23018 height
23019 };
23020 }
23021 /**
23022 * @param chart
23023 * @param forceRatio
23024 * @param forceStyle
23025 * @returns True if the canvas context size or transformation has changed.
23026 */ function retinaScale(chart, forceRatio, forceStyle) {
23027 const pixelRatio = forceRatio || 1;
23028 const deviceHeight = round1(chart.height * pixelRatio);
23029 const deviceWidth = round1(chart.width * pixelRatio);
23030 chart.height = round1(chart.height);
23031 chart.width = round1(chart.width);
23032 const canvas = chart.canvas;
23033 // If no style has been set on the canvas, the render size is used as display size,
23034 // making the chart visually bigger, so let's enforce it to the "correct" values.
23035 // See https://github.com/chartjs/Chart.js/issues/3575
23036 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
23037 canvas.style.height = `${chart.height}px`;
23038 canvas.style.width = `${chart.width}px`;
23039 }
23040 if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
23041 chart.currentDevicePixelRatio = pixelRatio;
23042 canvas.height = deviceHeight;
23043 canvas.width = deviceWidth;
23044 chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
23045 return true;
23046 }
23047 return false;
23048 }
23049 /**
23050 * Detects support for options object argument in addEventListener.
23051 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
23052 * @private
23053 */ const supportsEventListenerOptions = function() {
23054 let passiveSupported = false;
23055 try {
23056 const options = {
23057 get passive () {
23058 passiveSupported = true;
23059 return false;
23060 }
23061 };
23062 if (_isDomSupported()) {
23063 window.addEventListener('test', null, options);
23064 window.removeEventListener('test', null, options);
23065 }
23066 } catch (e) {
23067 // continue regardless of error
23068 }
23069 return passiveSupported;
23070 }();
23071 /**
23072 * The "used" size is the final value of a dimension property after all calculations have
23073 * been performed. This method uses the computed style of `element` but returns undefined
23074 * if the computed style is not expressed in pixels. That can happen in some cases where
23075 * `element` has a size relative to its parent and this last one is not yet displayed,
23076 * for example because of `display: none` on a parent node.
23077 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
23078 * @returns Size in pixels or undefined if unknown.
23079 */ function readUsedSize(element, property) {
23080 const value = getStyle(element, property);
23081 const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
23082 return matches ? +matches[1] : undefined;
23083 }
23084
23085 /**
23086 * @private
23087 */ function _pointInLine(p1, p2, t, mode) {
23088 return {
23089 x: p1.x + t * (p2.x - p1.x),
23090 y: p1.y + t * (p2.y - p1.y)
23091 };
23092 }
23093 /**
23094 * @private
23095 */ function _steppedInterpolation(p1, p2, t, mode) {
23096 return {
23097 x: p1.x + t * (p2.x - p1.x),
23098 y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y
23099 };
23100 }
23101 /**
23102 * @private
23103 */ function _bezierInterpolation(p1, p2, t, mode) {
23104 const cp1 = {
23105 x: p1.cp2x,
23106 y: p1.cp2y
23107 };
23108 const cp2 = {
23109 x: p2.cp1x,
23110 y: p2.cp1y
23111 };
23112 const a = _pointInLine(p1, cp1, t);
23113 const b = _pointInLine(cp1, cp2, t);
23114 const c = _pointInLine(cp2, p2, t);
23115 const d = _pointInLine(a, b, t);
23116 const e = _pointInLine(b, c, t);
23117 return _pointInLine(d, e, t);
23118 }
23119
23120 const getRightToLeftAdapter = function(rectX, width) {
23121 return {
23122 x (x) {
23123 return rectX + rectX + width - x;
23124 },
23125 setWidth (w) {
23126 width = w;
23127 },
23128 textAlign (align) {
23129 if (align === 'center') {
23130 return align;
23131 }
23132 return align === 'right' ? 'left' : 'right';
23133 },
23134 xPlus (x, value) {
23135 return x - value;
23136 },
23137 leftForLtr (x, itemWidth) {
23138 return x - itemWidth;
23139 }
23140 };
23141 };
23142 const getLeftToRightAdapter = function() {
23143 return {
23144 x (x) {
23145 return x;
23146 },
23147 setWidth (w) {},
23148 textAlign (align) {
23149 return align;
23150 },
23151 xPlus (x, value) {
23152 return x + value;
23153 },
23154 leftForLtr (x, _itemWidth) {
23155 return x;
23156 }
23157 };
23158 };
23159 function getRtlAdapter(rtl, rectX, width) {
23160 return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
23161 }
23162 function overrideTextDirection(ctx, direction) {
23163 let style, original;
23164 if (direction === 'ltr' || direction === 'rtl') {
23165 style = ctx.canvas.style;
23166 original = [
23167 style.getPropertyValue('direction'),
23168 style.getPropertyPriority('direction')
23169 ];
23170 style.setProperty('direction', direction, 'important');
23171 ctx.prevTextDirection = original;
23172 }
23173 }
23174 function restoreTextDirection(ctx, original) {
23175 if (original !== undefined) {
23176 delete ctx.prevTextDirection;
23177 ctx.canvas.style.setProperty('direction', original[0], original[1]);
23178 }
23179 }
23180
23181 function propertyFn(property) {
23182 if (property === 'angle') {
23183 return {
23184 between: _angleBetween,
23185 compare: _angleDiff,
23186 normalize: _normalizeAngle
23187 };
23188 }
23189 return {
23190 between: _isBetween,
23191 compare: (a, b)=>a - b,
23192 normalize: (x)=>x
23193 };
23194 }
23195 function normalizeSegment({ start , end , count , loop , style }) {
23196 return {
23197 start: start % count,
23198 end: end % count,
23199 loop: loop && (end - start + 1) % count === 0,
23200 style
23201 };
23202 }
23203 function getSegment(segment, points, bounds) {
23204 const { property , start: startBound , end: endBound } = bounds;
23205 const { between , normalize } = propertyFn(property);
23206 const count = points.length;
23207 let { start , end , loop } = segment;
23208 let i, ilen;
23209 if (loop) {
23210 start += count;
23211 end += count;
23212 for(i = 0, ilen = count; i < ilen; ++i){
23213 if (!between(normalize(points[start % count][property]), startBound, endBound)) {
23214 break;
23215 }
23216 start--;
23217 end--;
23218 }
23219 start %= count;
23220 end %= count;
23221 }
23222 if (end < start) {
23223 end += count;
23224 }
23225 return {
23226 start,
23227 end,
23228 loop,
23229 style: segment.style
23230 };
23231 }
23232 function _boundSegment(segment, points, bounds) {
23233 if (!bounds) {
23234 return [
23235 segment
23236 ];
23237 }
23238 const { property , start: startBound , end: endBound } = bounds;
23239 const count = points.length;
23240 const { compare , between , normalize } = propertyFn(property);
23241 const { start , end , loop , style } = getSegment(segment, points, bounds);
23242 const result = [];
23243 let inside = false;
23244 let subStart = null;
23245 let value, point, prevValue;
23246 const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
23247 const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);
23248 const shouldStart = ()=>inside || startIsBefore();
23249 const shouldStop = ()=>!inside || endIsBefore();
23250 for(let i = start, prev = start; i <= end; ++i){
23251 point = points[i % count];
23252 if (point.skip) {
23253 continue;
23254 }
23255 value = normalize(point[property]);
23256 if (value === prevValue) {
23257 continue;
23258 }
23259 inside = between(value, startBound, endBound);
23260 if (subStart === null && shouldStart()) {
23261 subStart = compare(value, startBound) === 0 ? i : prev;
23262 }
23263 if (subStart !== null && shouldStop()) {
23264 result.push(normalizeSegment({
23265 start: subStart,
23266 end: i,
23267 loop,
23268 count,
23269 style
23270 }));
23271 subStart = null;
23272 }
23273 prev = i;
23274 prevValue = value;
23275 }
23276 if (subStart !== null) {
23277 result.push(normalizeSegment({
23278 start: subStart,
23279 end,
23280 loop,
23281 count,
23282 style
23283 }));
23284 }
23285 return result;
23286 }
23287 function _boundSegments(line, bounds) {
23288 const result = [];
23289 const segments = line.segments;
23290 for(let i = 0; i < segments.length; i++){
23291 const sub = _boundSegment(segments[i], line.points, bounds);
23292 if (sub.length) {
23293 result.push(...sub);
23294 }
23295 }
23296 return result;
23297 }
23298 function findStartAndEnd(points, count, loop, spanGaps) {
23299 let start = 0;
23300 let end = count - 1;
23301 if (loop && !spanGaps) {
23302 while(start < count && !points[start].skip){
23303 start++;
23304 }
23305 }
23306 while(start < count && points[start].skip){
23307 start++;
23308 }
23309 start %= count;
23310 if (loop) {
23311 end += start;
23312 }
23313 while(end > start && points[end % count].skip){
23314 end--;
23315 }
23316 end %= count;
23317 return {
23318 start,
23319 end
23320 };
23321 }
23322 function solidSegments(points, start, max, loop) {
23323 const count = points.length;
23324 const result = [];
23325 let last = start;
23326 let prev = points[start];
23327 let end;
23328 for(end = start + 1; end <= max; ++end){
23329 const cur = points[end % count];
23330 if (cur.skip || cur.stop) {
23331 if (!prev.skip) {
23332 loop = false;
23333 result.push({
23334 start: start % count,
23335 end: (end - 1) % count,
23336 loop
23337 });
23338 start = last = cur.stop ? end : null;
23339 }
23340 } else {
23341 last = end;
23342 if (prev.skip) {
23343 start = end;
23344 }
23345 }
23346 prev = cur;
23347 }
23348 if (last !== null) {
23349 result.push({
23350 start: start % count,
23351 end: last % count,
23352 loop
23353 });
23354 }
23355 return result;
23356 }
23357 function _computeSegments(line, segmentOptions) {
23358 const points = line.points;
23359 const spanGaps = line.options.spanGaps;
23360 const count = points.length;
23361 if (!count) {
23362 return [];
23363 }
23364 const loop = !!line._loop;
23365 const { start , end } = findStartAndEnd(points, count, loop, spanGaps);
23366 if (spanGaps === true) {
23367 return splitByStyles(line, [
23368 {
23369 start,
23370 end,
23371 loop
23372 }
23373 ], points, segmentOptions);
23374 }
23375 const max = end < start ? end + count : end;
23376 const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
23377 return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
23378 }
23379 function splitByStyles(line, segments, points, segmentOptions) {
23380 if (!segmentOptions || !segmentOptions.setContext || !points) {
23381 return segments;
23382 }
23383 return doSplitByStyles(line, segments, points, segmentOptions);
23384 }
23385 function doSplitByStyles(line, segments, points, segmentOptions) {
23386 const chartContext = line._chart.getContext();
23387 const baseStyle = readStyle(line.options);
23388 const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;
23389 const count = points.length;
23390 const result = [];
23391 let prevStyle = baseStyle;
23392 let start = segments[0].start;
23393 let i = start;
23394 function addStyle(s, e, l, st) {
23395 const dir = spanGaps ? -1 : 1;
23396 if (s === e) {
23397 return;
23398 }
23399 s += count;
23400 while(points[s % count].skip){
23401 s -= dir;
23402 }
23403 while(points[e % count].skip){
23404 e += dir;
23405 }
23406 if (s % count !== e % count) {
23407 result.push({
23408 start: s % count,
23409 end: e % count,
23410 loop: l,
23411 style: st
23412 });
23413 prevStyle = st;
23414 start = e % count;
23415 }
23416 }
23417 for (const segment of segments){
23418 start = spanGaps ? start : segment.start;
23419 let prev = points[start % count];
23420 let style;
23421 for(i = start + 1; i <= segment.end; i++){
23422 const pt = points[i % count];
23423 style = readStyle(segmentOptions.setContext(createContext(chartContext, {
23424 type: 'segment',
23425 p0: prev,
23426 p1: pt,
23427 p0DataIndex: (i - 1) % count,
23428 p1DataIndex: i % count,
23429 datasetIndex
23430 })));
23431 if (styleChanged(style, prevStyle)) {
23432 addStyle(start, i - 1, segment.loop, prevStyle);
23433 }
23434 prev = pt;
23435 prevStyle = style;
23436 }
23437 if (start < i - 1) {
23438 addStyle(start, i - 1, segment.loop, prevStyle);
23439 }
23440 }
23441 return result;
23442 }
23443 function readStyle(options) {
23444 return {
23445 backgroundColor: options.backgroundColor,
23446 borderCapStyle: options.borderCapStyle,
23447 borderDash: options.borderDash,
23448 borderDashOffset: options.borderDashOffset,
23449 borderJoinStyle: options.borderJoinStyle,
23450 borderWidth: options.borderWidth,
23451 borderColor: options.borderColor
23452 };
23453 }
23454 function styleChanged(style, prevStyle) {
23455 if (!prevStyle) {
23456 return false;
23457 }
23458 const cache = [];
23459 const replacer = function(key, value) {
23460 if (!isPatternOrGradient(value)) {
23461 return value;
23462 }
23463 if (!cache.includes(value)) {
23464 cache.push(value);
23465 }
23466 return cache.indexOf(value);
23467 };
23468 return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);
23469 }
23470
23471 function getSizeForArea(scale, chartArea, field) {
23472 return scale.options.clip ? scale[field] : chartArea[field];
23473 }
23474 function getDatasetArea(meta, chartArea) {
23475 const { xScale , yScale } = meta;
23476 if (xScale && yScale) {
23477 return {
23478 left: getSizeForArea(xScale, chartArea, 'left'),
23479 right: getSizeForArea(xScale, chartArea, 'right'),
23480 top: getSizeForArea(yScale, chartArea, 'top'),
23481 bottom: getSizeForArea(yScale, chartArea, 'bottom')
23482 };
23483 }
23484 return chartArea;
23485 }
23486 function getDatasetClipArea(chart, meta) {
23487 const clip = meta._clip;
23488 if (clip.disabled) {
23489 return false;
23490 }
23491 const area = getDatasetArea(meta, chart.chartArea);
23492 return {
23493 left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left),
23494 right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right),
23495 top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top),
23496 bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom)
23497 };
23498 }
23499
23500
23501 //# sourceMappingURL=helpers.dataset.js.map
23502
23503
23504 /***/ }
23505
23506 /******/ });
23507 /************************************************************************/
23508 /******/ // The module cache
23509 /******/ const __webpack_module_cache__ = {};
23510 /******/
23511 /******/ // The require function
23512 /******/ function __webpack_require__(moduleId) {
23513 /******/ // Check if module is in cache
23514 /******/ const cachedModule = __webpack_module_cache__[moduleId];
23515 /******/ if (cachedModule !== undefined) {
23516 /******/ return cachedModule.exports;
23517 /******/ }
23518 /******/ // Create a new module (and put it into the cache)
23519 /******/ const module = __webpack_module_cache__[moduleId] = {
23520 /******/ // no module.id needed
23521 /******/ // no module.loaded needed
23522 /******/ exports: {}
23523 /******/ };
23524 /******/
23525 /******/ // Execute the module function
23526 /******/ if (!(moduleId in __webpack_modules__)) {
23527 /******/ delete __webpack_module_cache__[moduleId];
23528 /******/ const e = new Error("Cannot find module '" + moduleId + "'");
23529 /******/ e.code = 'MODULE_NOT_FOUND';
23530 /******/ throw e;
23531 /******/ }
23532 /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
23533 /******/
23534 /******/ // Return the exports of the module
23535 /******/ return module.exports;
23536 /******/ }
23537 /******/
23538 /************************************************************************/
23539 /******/ /* webpack/runtime/compat get default export */
23540 /******/ (() => {
23541 /******/ // getDefaultExport function for compatibility with non-harmony modules
23542 /******/ __webpack_require__.n = (module) => {
23543 /******/ const getter = module && module.__esModule ?
23544 /******/ () => (module['default']) :
23545 /******/ () => (module);
23546 /******/ __webpack_require__.d(getter, { a: getter });
23547 /******/ return getter;
23548 /******/ };
23549 /******/ })();
23550 /******/
23551 /******/ /* webpack/runtime/define property getters */
23552 /******/ (() => {
23553 /******/ // define getter/value functions for harmony exports
23554 /******/ __webpack_require__.d = (exports, definition) => {
23555 /******/ if(Array.isArray(definition)) {
23556 /******/ var i = 0;
23557 /******/ while(i < definition.length) {
23558 /******/ var key = definition[i++];
23559 /******/ var binding = definition[i++];
23560 /******/ if(!__webpack_require__.o(exports, key)) {
23561 /******/ if(binding === 0) {
23562 /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
23563 /******/ } else {
23564 /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
23565 /******/ }
23566 /******/ } else if(binding === 0) { i++; }
23567 /******/ }
23568 /******/ } else {
23569 /******/ for(var key in definition) {
23570 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
23571 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
23572 /******/ }
23573 /******/ }
23574 /******/ }
23575 /******/ };
23576 /******/ })();
23577 /******/
23578 /******/ /* webpack/runtime/hasOwnProperty shorthand */
23579 /******/ (() => {
23580 /******/ __webpack_require__.o = (obj, prop) => (Object.hasOwn(obj, prop))
23581 /******/ })();
23582 /******/
23583 /******/ /* webpack/runtime/make namespace object */
23584 /******/ (() => {
23585 /******/ // define __esModule on exports
23586 /******/ __webpack_require__.r = (exports) => {
23587 /******/ if(Symbol.toStringTag) {
23588 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
23589 /******/ }
23590 /******/ Object.defineProperty(exports, '__esModule', { value: true });
23591 /******/ };
23592 /******/ })();
23593 /******/
23594 /************************************************************************/
23595 let __webpack_exports__ = {};
23596 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
23597 (() => {
23598 "use strict";
23599 /*!************************************************!*\
23600 !*** ./assets/src/js/admin/admin-statistic.js ***!
23601 \************************************************/
23602 __webpack_require__.r(__webpack_exports__);
23603 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
23604 /* 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");
23605 /* 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");
23606 /* 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");
23607 /* 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");
23608 /* 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");
23609 /* 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");
23610 /* 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");
23611 /**
23612 * Statistics dashboard entry — bootstraps the per-tab modules.
23613 *
23614 * All four tabs run on the statistics/* module stack (state, api, chart,
23615 * data-table, report-modal); the legacy per-tab loaders are gone.
23616 *
23617 * @since 4.2.5.5
23618 * @version 2.0.0
23619 */
23620
23621
23622
23623
23624
23625
23626
23627
23628
23629 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.LpStatsFilterBar.selectors.elContainer, () => {
23630 _statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsFilterBar.init();
23631 });
23632 // SweetAlert2 popup: delegated events only, no rendered container to wait for.
23633 _statistics_report_modal_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsReportModal.init();
23634 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.LpStatsTabOverview.selectors.elContainer, () => {
23635 _statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.lpStatsTabOverview.init();
23636 });
23637 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.LpStatsTabOrders.selectors.elContainer, () => {
23638 _statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.lpStatsTabOrders.init();
23639 });
23640 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.LpStatsTabCourses.selectors.elContainer, () => {
23641 _statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.lpStatsTabCourses.init();
23642 });
23643 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.LpStatsTabUsers.selectors.elContainer, () => {
23644 _statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsTabUsers.init();
23645 });
23646 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.LpStatsTabInstructors.selectors.elContainer, () => {
23647 _statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.lpStatsTabInstructors.init();
23648 });
23649 })();
23650
23651 /******/ })()
23652 ;
23653 //# sourceMappingURL=admin-statistic.js.map