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

23,814 lines 863.1 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 */ fullScreenView: () => (/* binding */ fullScreenView),
3078 /* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm),
3079 /* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm),
3080 /* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated),
3081 /* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed),
3082 /* harmony export */ lpAddQueryArgs: () => (/* binding */ lpAddQueryArgs),
3083 /* harmony export */ lpAjaxParseJsonOld: () => (/* binding */ lpAjaxParseJsonOld),
3084 /* harmony export */ lpClassName: () => (/* binding */ lpClassName),
3085 /* harmony export */ lpFetchAPI: () => (/* binding */ lpFetchAPI),
3086 /* harmony export */ lpGetCurrentURLNoParam: () => (/* binding */ lpGetCurrentURLNoParam),
3087 /* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady),
3088 /* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl),
3089 /* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl),
3090 /* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm),
3091 /* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse),
3092 /* harmony export */ toggleEnable: () => (/* binding */ toggleEnable)
3093 /* harmony export */ });
3094 /**
3095 * Utils functions
3096 *
3097 * @param url
3098 * @param data
3099 * @param functions
3100 * @since 4.2.5.1
3101 * @version 1.0.7
3102 */
3103 const lpClassName = {
3104 hidden: 'lp-hidden',
3105 loading: 'loading',
3106 elCollapse: 'lp-collapse',
3107 elSectionToggle: '.lp-section-toggle',
3108 elTriggerToggle: '.lp-trigger-toggle',
3109 elBtnFullScreen: '.lp-btn-full-screen-view',
3110 elFullScreen: 'lp-full-screen-view',
3111 elBtnFullScreenClose: 'lp-full-screen-view__close'
3112 };
3113 const lpFetchAPI = (url, data = {}, functions = {}) => {
3114 if ('function' === typeof functions.before) {
3115 functions.before();
3116 }
3117 fetch(url, {
3118 method: 'GET',
3119 ...data
3120 }).then(response => response.json()).then(response => {
3121 if ('function' === typeof functions.success) {
3122 functions.success(response);
3123 }
3124 }).catch(err => {
3125 if ('function' === typeof functions.error) {
3126 functions.error(err);
3127 }
3128 }).finally(() => {
3129 if ('function' === typeof functions.completed) {
3130 functions.completed();
3131 }
3132 });
3133 };
3134
3135 /**
3136 * Get current URL without params.
3137 *
3138 * @since 4.2.5.1
3139 */
3140 const lpGetCurrentURLNoParam = () => {
3141 let currentUrl = window.location.href;
3142 const hasParams = currentUrl.includes('?');
3143 if (hasParams) {
3144 currentUrl = currentUrl.split('?')[0];
3145 }
3146 return currentUrl;
3147 };
3148 const lpAddQueryArgs = (endpoint, args) => {
3149 const url = new URL(endpoint);
3150 Object.keys(args).forEach(arg => {
3151 url.searchParams.set(arg, args[arg]);
3152 });
3153 return url;
3154 };
3155
3156 /**
3157 * Listen element viewed.
3158 *
3159 * @param el
3160 * @param callback
3161 * @since 4.2.5.8
3162 */
3163 const listenElementViewed = (el, callback) => {
3164 const observerSeeItem = new IntersectionObserver(function (entries) {
3165 for (const entry of entries) {
3166 if (entry.isIntersecting) {
3167 callback(entry);
3168 }
3169 }
3170 });
3171 observerSeeItem.observe(el);
3172 };
3173
3174 /**
3175 * Listen element created.
3176 *
3177 * @param callback
3178 * @since 4.2.5.8
3179 */
3180 const listenElementCreated = callback => {
3181 const observerCreateItem = new MutationObserver(function (mutations) {
3182 mutations.forEach(function (mutation) {
3183 if (mutation.addedNodes) {
3184 mutation.addedNodes.forEach(function (node) {
3185 if (node.nodeType === 1) {
3186 callback(node);
3187 }
3188 });
3189 }
3190 });
3191 });
3192 observerCreateItem.observe(document, {
3193 childList: true,
3194 subtree: true
3195 });
3196 // End.
3197 };
3198
3199 /**
3200 * Listen element created.
3201 *
3202 * @param selector
3203 * @param callback
3204 * @since 4.2.7.1
3205 */
3206 const lpOnElementReady = (selector, callback) => {
3207 const element = document.querySelector(selector);
3208 if (element) {
3209 callback(element);
3210 return;
3211 }
3212 const observer = new MutationObserver((mutations, obs) => {
3213 const element = document.querySelector(selector);
3214 if (element) {
3215 obs.disconnect();
3216 callback(element);
3217 }
3218 });
3219 observer.observe(document.documentElement, {
3220 childList: true,
3221 subtree: true
3222 });
3223 };
3224
3225 // Parse JSON from string with content include LP_AJAX_START.
3226 const lpAjaxParseJsonOld = data => {
3227 if (typeof data !== 'string') {
3228 return data;
3229 }
3230 const m = String.raw({
3231 raw: data
3232 }).match(/<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s);
3233 try {
3234 if (m) {
3235 data = JSON.parse(m[1].replace(/(?:\r\n|\r|\n)/g, ''));
3236 } else {
3237 data = JSON.parse(data);
3238 }
3239 } catch (e) {
3240 data = {};
3241 }
3242 return data;
3243 };
3244
3245 // status 0: hide, 1: show
3246 const lpShowHideEl = (el, status = 0) => {
3247 if (!el) {
3248 return;
3249 }
3250 if (!status) {
3251 el.classList.add(lpClassName.hidden);
3252 } else {
3253 el.classList.remove(lpClassName.hidden);
3254 }
3255 };
3256
3257 // status 0: hide, 1: show
3258 const lpSetLoadingEl = (el, status) => {
3259 if (!el) {
3260 return;
3261 }
3262 if (!status) {
3263 el.classList.remove(lpClassName.loading);
3264 } else {
3265 el.classList.add(lpClassName.loading);
3266 }
3267 };
3268
3269 // Toggle collapse section
3270 const toggleCollapse = (e, target, elTriggerClassName = '', elsExclude = [], callback) => {
3271 if (!elTriggerClassName) {
3272 elTriggerClassName = lpClassName.elTriggerToggle;
3273 }
3274
3275 // Exclude elements, which should not trigger the collapse toggle
3276 if (elsExclude && elsExclude.length > 0) {
3277 for (const elExclude of elsExclude) {
3278 if (target.closest(elExclude)) {
3279 return;
3280 }
3281 }
3282 }
3283 const elTrigger = target.closest(elTriggerClassName);
3284 if (!elTrigger) {
3285 return;
3286 }
3287
3288 //console.log( 'elTrigger', elTrigger );
3289
3290 const elSectionToggle = elTrigger.closest(`${lpClassName.elSectionToggle}`);
3291 if (!elSectionToggle) {
3292 return;
3293 }
3294 elSectionToggle.classList.toggle(`${lpClassName.elCollapse}`);
3295 if ('function' === typeof callback) {
3296 callback(elSectionToggle);
3297 }
3298 };
3299
3300 // Get data of form
3301 const getDataOfForm = form => {
3302 const dataSend = {};
3303 const formData = new FormData(form);
3304 for (const pair of formData.entries()) {
3305 const key = pair[0];
3306 const value = formData.getAll(key);
3307 if (!dataSend.hasOwnProperty(key)) {
3308 // Convert value array to string.
3309 dataSend[key] = value.join(',');
3310 }
3311 }
3312 return dataSend;
3313 };
3314
3315 // Get field keys of form
3316 const getFieldKeysOfForm = form => {
3317 const keys = [];
3318 const elements = form.elements;
3319 for (let i = 0; i < elements.length; i++) {
3320 const name = elements[i].name;
3321 if (name && !keys.includes(name)) {
3322 keys.push(name);
3323 }
3324 }
3325 return keys;
3326 };
3327
3328 // Merge data handle with data form.
3329 const mergeDataWithDatForm = (elForm, dataHandle) => {
3330 const dataForm = getDataOfForm(elForm);
3331 const keys = getFieldKeysOfForm(elForm);
3332 keys.forEach(key => {
3333 if (!dataForm.hasOwnProperty(key)) {
3334 delete dataHandle[key];
3335 } else if (dataForm[key][0] === '') {
3336 delete dataForm[key];
3337 delete dataHandle[key];
3338 }
3339 });
3340 dataHandle = {
3341 ...dataHandle,
3342 ...dataForm
3343 };
3344 return dataHandle;
3345 };
3346
3347 /**
3348 * Event trigger
3349 * For each list of event handlers, listen event on document.
3350 *
3351 * eventName: 'click', 'change', ...
3352 * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
3353 *
3354 * @param eventName
3355 * @param eventHandlers
3356 */
3357 const eventHandlers = (eventName, eventHandlers) => {
3358 document.addEventListener(eventName, e => {
3359 const target = e.target;
3360 let args = {
3361 e,
3362 target
3363 };
3364 eventHandlers.forEach(eventHandler => {
3365 args = {
3366 ...args,
3367 ...eventHandler
3368 };
3369
3370 //console.log( args );
3371
3372 // Check condition before call back
3373 if (eventHandler.conditionBeforeCallBack) {
3374 if (eventHandler.conditionBeforeCallBack(args) !== true) {
3375 return;
3376 }
3377 }
3378
3379 // Special check for keydown event with checkIsEventEnter = true
3380 if (eventName === 'keydown' && eventHandler.checkIsEventEnter) {
3381 if (e.key !== 'Enter') {
3382 return;
3383 }
3384 }
3385 if (target.closest(eventHandler.selector)) {
3386 if (eventHandler.class) {
3387 // Call method of class, function callBack will understand exactly {this} is class object.
3388 eventHandler.class[eventHandler.callBack](args);
3389 } else {
3390 // For send args is objected, {this} is eventHandler object, not class object.
3391 eventHandler.callBack(args);
3392 }
3393 }
3394 });
3395 });
3396 };
3397
3398 /**
3399 * Debounce - delays function execution until after `wait` ms of inactivity.
3400 *
3401 * Each call resets the timer. Only the last call in a burst executes.
3402 *
3403 * USE CASES:
3404 * - Search inputs, form validation, window resize
3405 * - Multiple elements need independent timers
3406 * - When you need to call with different arguments
3407 *
3408 * EXAMPLES:
3409 * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
3410 * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
3411 *
3412 * const debouncedResize = debounce( recalculateLayout, 250 );
3413 * window.addEventListener('resize', debouncedResize);
3414 *
3415 * ⚠️ Create ONCE outside event handlers, not inside.
3416 *
3417 * @param {Function} func - Function to debounce (can be anonymous)
3418 * @param {number} wait - Milliseconds to wait (default: 500)
3419 * @return {Function} Debounced wrapper function
3420 * @since 4.3.7
3421 * @version 1.0.0
3422 */
3423 const debounce = (func, wait = 500) => {
3424 let timer;
3425 return args => {
3426 clearTimeout(timer);
3427 timer = setTimeout(() => func(args), wait);
3428 };
3429 };
3430
3431 /**
3432 * Initialize lp-toggle-enable components.
3433 *
3434 * Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
3435 * Reads initial state from `data-enabled` attribute ("true"/"false").
3436 * Calls `data-on-toggle` callback (if provided via options) on state change.
3437 *
3438 * HTML structure:
3439 * <label class="lp-toggle-enable" data-enabled="true">
3440 * <input type="checkbox" class="lp-toggle-enable__input" />
3441 * <span class="lp-toggle-enable__track"></span>
3442 * </label>
3443 *
3444 * @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
3445 * @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
3446 * @since 4.4.5
3447 * @version 1.0.0
3448 */
3449 window.lpToggleEnableInit = 0;
3450 const toggleEnable = (onToggle = null) => {
3451 if (window.lpToggleEnableInit) {
3452 return;
3453 }
3454 window.lpToggleEnableInit = 1;
3455 const selector = '.lp-toggle-enable';
3456 const updateUI = (toggle, isEnabled) => {
3457 toggle.classList.toggle('is-enabled', isEnabled);
3458 const input = toggle.querySelector('.lp-toggle-enable__input');
3459 if (input) {
3460 input.checked = isEnabled;
3461 input.value = isEnabled ? '1' : '0';
3462 }
3463 };
3464
3465 // Delegate click handling via eventHandlers.
3466 eventHandlers('click', [{
3467 selector,
3468 callBack: args => {
3469 const {
3470 e,
3471 target
3472 } = args;
3473 const toggle = target.closest(selector);
3474 if (!toggle || toggle.classList.contains('is-disabled')) {
3475 return;
3476 }
3477 e.preventDefault();
3478 const isEnabled = !toggle.classList.contains('is-enabled');
3479 updateUI(toggle, isEnabled);
3480 if ('function' === typeof onToggle) {
3481 onToggle(toggle, isEnabled);
3482 }
3483 }
3484 }]);
3485 };
3486
3487 /**
3488 * Initialize custom fullscreen view buttons.
3489 *
3490 * Delegates clicks on `.lp-btn-full-screen-view` buttons to
3491 * `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
3492 * target element. Falls back to the button's parent element when
3493 * `data-target` is not provided.
3494 *
3495 * @since 4.4.5
3496 * @version 1.0.0
3497 */
3498 window.lpFullScreenViewInit = 0;
3499 const fullScreenView = () => {
3500 if (window.lpFullScreenViewInit) {
3501 return;
3502 }
3503 window.lpFullScreenViewInit = 1;
3504 let lastScrollY = 0;
3505 const lpToggleFullscreenView = (elTarget, elBtnFullScreen = null) => {
3506 const isFullscreen = elTarget.classList.contains(lpClassName.elFullScreen);
3507 if (isFullscreen) {
3508 elTarget.classList.remove(lpClassName.elFullScreen);
3509 document.documentElement.classList.remove('lp-full-screen-active');
3510 window.scrollTo(0, lastScrollY);
3511 } else {
3512 lastScrollY = window.scrollY;
3513 elTarget.classList.add(lpClassName.elFullScreen);
3514 document.documentElement.classList.add('lp-full-screen-active');
3515 }
3516 if (!isFullscreen) {
3517 if (!elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`)) {
3518 const closeButton = document.createElement('button');
3519 closeButton.type = 'button';
3520 closeButton.className = lpClassName.elBtnFullScreenClose;
3521 closeButton.setAttribute('aria-label', 'Close');
3522 closeButton.innerHTML = lpData.i18n.closeButtonFullScreen || 'Close &times;';
3523 closeButton.addEventListener('click', e => {
3524 e.preventDefault();
3525 lpToggleFullscreenView(elTarget);
3526 });
3527 elTarget.appendChild(closeButton);
3528 }
3529 } else {
3530 const closeButton = elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`);
3531 if (closeButton) {
3532 closeButton.remove();
3533 }
3534 }
3535 };
3536 eventHandlers('click', [{
3537 selector: lpClassName.elBtnFullScreen,
3538 callBack: args => {
3539 const {
3540 e,
3541 target
3542 } = args;
3543 const elBtnFullScreen = target.closest(lpClassName.elBtnFullScreen);
3544 if (!elBtnFullScreen) {
3545 console.log('No full screen button found');
3546 return;
3547 }
3548 e.preventDefault();
3549 let elTarget = null;
3550 const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
3551 console.log(targetSelector);
3552 if (targetSelector) {
3553 elTarget = document.querySelector(targetSelector);
3554 }
3555 if (!elTarget) {
3556 console.log('No target element found');
3557 return;
3558 }
3559 lpToggleFullscreenView(elTarget, elBtnFullScreen);
3560 }
3561 }]);
3562 };
3563
3564 /***/ },
3565
3566 /***/ "./node_modules/sweetalert2/dist/sweetalert2.all.js"
3567 /*!**********************************************************!*\
3568 !*** ./node_modules/sweetalert2/dist/sweetalert2.all.js ***!
3569 \**********************************************************/
3570 (module) {
3571
3572 /*!
3573 * sweetalert2 v11.26.17
3574 * Released under the MIT License.
3575 */
3576 (function (global, factory) {
3577 true ? module.exports = factory() :
3578 0;
3579 })(this, (function () { 'use strict';
3580
3581 function _assertClassBrand(e, t, n) {
3582 if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
3583 throw new TypeError("Private element is not present on this object");
3584 }
3585 function _checkPrivateRedeclaration(e, t) {
3586 if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
3587 }
3588 function _classPrivateFieldGet2(s, a) {
3589 return s.get(_assertClassBrand(s, a));
3590 }
3591 function _classPrivateFieldInitSpec(e, t, a) {
3592 _checkPrivateRedeclaration(e, t), t.set(e, a);
3593 }
3594 function _classPrivateFieldSet2(s, a, r) {
3595 return s.set(_assertClassBrand(s, a), r), r;
3596 }
3597
3598 const RESTORE_FOCUS_TIMEOUT = 100;
3599
3600 /** @type {GlobalState} */
3601 const globalState = {};
3602 const focusPreviousActiveElement = () => {
3603 if (globalState.previousActiveElement instanceof HTMLElement) {
3604 globalState.previousActiveElement.focus();
3605 globalState.previousActiveElement = null;
3606 } else if (document.body) {
3607 document.body.focus();
3608 }
3609 };
3610
3611 /**
3612 * Restore previous active (focused) element
3613 *
3614 * @param {boolean} returnFocus
3615 * @returns {Promise<void>}
3616 */
3617 const restoreActiveElement = returnFocus => {
3618 return new Promise(resolve => {
3619 if (!returnFocus) {
3620 return resolve();
3621 }
3622 const x = window.scrollX;
3623 const y = window.scrollY;
3624 globalState.restoreFocusTimeout = setTimeout(() => {
3625 focusPreviousActiveElement();
3626 resolve();
3627 }, RESTORE_FOCUS_TIMEOUT); // issues/900
3628
3629 window.scrollTo(x, y);
3630 });
3631 };
3632
3633 const swalPrefix = 'swal2-';
3634
3635 /**
3636 * @typedef {Record<SwalClass, string>} SwalClasses
3637 */
3638
3639 /**
3640 * @typedef {'success' | 'warning' | 'info' | 'question' | 'error'} SwalIcon
3641 * @typedef {Record<SwalIcon, string>} SwalIcons
3642 */
3643
3644 /** @type {SwalClass[]} */
3645 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'];
3646 const swalClasses = classNames.reduce((acc, className) => {
3647 acc[className] = swalPrefix + className;
3648 return acc;
3649 }, /** @type {SwalClasses} */{});
3650
3651 /** @type {SwalIcon[]} */
3652 const icons = ['success', 'warning', 'info', 'question', 'error'];
3653 const iconTypes = icons.reduce((acc, icon) => {
3654 acc[icon] = swalPrefix + icon;
3655 return acc;
3656 }, /** @type {SwalIcons} */{});
3657
3658 const consolePrefix = 'SweetAlert2:';
3659
3660 /**
3661 * Capitalize the first letter of a string
3662 *
3663 * @param {string} str
3664 * @returns {string}
3665 */
3666 const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);
3667
3668 /**
3669 * Standardize console warnings
3670 *
3671 * @param {string | string[]} message
3672 */
3673 const warn = message => {
3674 console.warn(`${consolePrefix} ${typeof message === 'object' ? message.join(' ') : message}`);
3675 };
3676
3677 /**
3678 * Standardize console errors
3679 *
3680 * @param {string} message
3681 */
3682 const error = message => {
3683 console.error(`${consolePrefix} ${message}`);
3684 };
3685
3686 /**
3687 * Private global state for `warnOnce`
3688 *
3689 * @type {string[]}
3690 * @private
3691 */
3692 const previousWarnOnceMessages = [];
3693
3694 /**
3695 * Show a console warning, but only if it hasn't already been shown
3696 *
3697 * @param {string} message
3698 */
3699 const warnOnce = message => {
3700 if (!previousWarnOnceMessages.includes(message)) {
3701 previousWarnOnceMessages.push(message);
3702 warn(message);
3703 }
3704 };
3705
3706 /**
3707 * Show a one-time console warning about deprecated params/methods
3708 *
3709 * @param {string} deprecatedParam
3710 * @param {string?} useInstead
3711 */
3712 const warnAboutDeprecation = (deprecatedParam, useInstead = null) => {
3713 warnOnce(`"${deprecatedParam}" is deprecated and will be removed in the next major release.${useInstead ? ` Use "${useInstead}" instead.` : ''}`);
3714 };
3715
3716 /**
3717 * If `arg` is a function, call it (with no arguments or context) and return the result.
3718 * Otherwise, just pass the value through
3719 *
3720 * @param {(() => *) | *} arg
3721 * @returns {*}
3722 */
3723 const callIfFunction = arg => typeof arg === 'function' ? arg() : arg;
3724
3725 /**
3726 * @param {*} arg
3727 * @returns {boolean}
3728 */
3729 const hasToPromiseFn = arg => arg && typeof arg.toPromise === 'function';
3730
3731 /**
3732 * @param {*} arg
3733 * @returns {Promise<*>}
3734 */
3735 const asPromise = arg => hasToPromiseFn(arg) ? arg.toPromise() : Promise.resolve(arg);
3736
3737 /**
3738 * @param {*} arg
3739 * @returns {boolean}
3740 */
3741 const isPromise = arg => arg && Promise.resolve(arg) === arg;
3742
3743 /**
3744 * Gets the popup container which contains the backdrop and the popup itself.
3745 *
3746 * @returns {HTMLElement | null}
3747 */
3748 const getContainer = () => document.body.querySelector(`.${swalClasses.container}`);
3749
3750 /**
3751 * @param {string} selectorString
3752 * @returns {HTMLElement | null}
3753 */
3754 const elementBySelector = selectorString => {
3755 const container = getContainer();
3756 return container ? container.querySelector(selectorString) : null;
3757 };
3758
3759 /**
3760 * @param {string} className
3761 * @returns {HTMLElement | null}
3762 */
3763 const elementByClass = className => {
3764 return elementBySelector(`.${className}`);
3765 };
3766
3767 /**
3768 * @returns {HTMLElement | null}
3769 */
3770 const getPopup = () => elementByClass(swalClasses.popup);
3771
3772 /**
3773 * @returns {HTMLElement | null}
3774 */
3775 const getIcon = () => elementByClass(swalClasses.icon);
3776
3777 /**
3778 * @returns {HTMLElement | null}
3779 */
3780 const getIconContent = () => elementByClass(swalClasses['icon-content']);
3781
3782 /**
3783 * @returns {HTMLElement | null}
3784 */
3785 const getTitle = () => elementByClass(swalClasses.title);
3786
3787 /**
3788 * @returns {HTMLElement | null}
3789 */
3790 const getHtmlContainer = () => elementByClass(swalClasses['html-container']);
3791
3792 /**
3793 * @returns {HTMLElement | null}
3794 */
3795 const getImage = () => elementByClass(swalClasses.image);
3796
3797 /**
3798 * @returns {HTMLElement | null}
3799 */
3800 const getProgressSteps = () => elementByClass(swalClasses['progress-steps']);
3801
3802 /**
3803 * @returns {HTMLElement | null}
3804 */
3805 const getValidationMessage = () => elementByClass(swalClasses['validation-message']);
3806
3807 /**
3808 * @returns {HTMLButtonElement | null}
3809 */
3810 const getConfirmButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.confirm}`));
3811
3812 /**
3813 * @returns {HTMLButtonElement | null}
3814 */
3815 const getCancelButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.cancel}`));
3816
3817 /**
3818 * @returns {HTMLButtonElement | null}
3819 */
3820 const getDenyButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.deny}`));
3821
3822 /**
3823 * @returns {HTMLElement | null}
3824 */
3825 const getInputLabel = () => elementByClass(swalClasses['input-label']);
3826
3827 /**
3828 * @returns {HTMLElement | null}
3829 */
3830 const getLoader = () => elementBySelector(`.${swalClasses.loader}`);
3831
3832 /**
3833 * @returns {HTMLElement | null}
3834 */
3835 const getActions = () => elementByClass(swalClasses.actions);
3836
3837 /**
3838 * @returns {HTMLElement | null}
3839 */
3840 const getFooter = () => elementByClass(swalClasses.footer);
3841
3842 /**
3843 * @returns {HTMLElement | null}
3844 */
3845 const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']);
3846
3847 /**
3848 * @returns {HTMLElement | null}
3849 */
3850 const getCloseButton = () => elementByClass(swalClasses.close);
3851
3852 // https://github.com/jkup/focusable/blob/master/index.js
3853 const focusable = `
3854 a[href],
3855 area[href],
3856 input:not([disabled]),
3857 select:not([disabled]),
3858 textarea:not([disabled]),
3859 button:not([disabled]),
3860 iframe,
3861 object,
3862 embed,
3863 [tabindex="0"],
3864 [contenteditable],
3865 audio[controls],
3866 video[controls],
3867 summary
3868 `;
3869 /**
3870 * @returns {HTMLElement[]}
3871 */
3872 const getFocusableElements = () => {
3873 const popup = getPopup();
3874 if (!popup) {
3875 return [];
3876 }
3877 /** @type {NodeListOf<HTMLElement>} */
3878 const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])');
3879 const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex)
3880 // sort according to tabindex
3881 .sort((a, b) => {
3882 const tabindexA = parseInt(a.getAttribute('tabindex') || '0');
3883 const tabindexB = parseInt(b.getAttribute('tabindex') || '0');
3884 if (tabindexA > tabindexB) {
3885 return 1;
3886 } else if (tabindexA < tabindexB) {
3887 return -1;
3888 }
3889 return 0;
3890 });
3891
3892 /** @type {NodeListOf<HTMLElement>} */
3893 const otherFocusableElements = popup.querySelectorAll(focusable);
3894 const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1');
3895 return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el));
3896 };
3897
3898 /**
3899 * @returns {boolean}
3900 */
3901 const isModal = () => {
3902 return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']);
3903 };
3904
3905 /**
3906 * @returns {boolean}
3907 */
3908 const isToast = () => {
3909 const popup = getPopup();
3910 if (!popup) {
3911 return false;
3912 }
3913 return hasClass(popup, swalClasses.toast);
3914 };
3915
3916 /**
3917 * @returns {boolean}
3918 */
3919 const isLoading = () => {
3920 const popup = getPopup();
3921 if (!popup) {
3922 return false;
3923 }
3924 return popup.hasAttribute('data-loading');
3925 };
3926
3927 /**
3928 * Securely set innerHTML of an element
3929 * https://github.com/sweetalert2/sweetalert2/issues/1926
3930 *
3931 * @param {HTMLElement} elem
3932 * @param {string} html
3933 */
3934 const setInnerHtml = (elem, html) => {
3935 elem.textContent = '';
3936 if (html) {
3937 const parser = new DOMParser();
3938 const parsed = parser.parseFromString(html, `text/html`);
3939 const head = parsed.querySelector('head');
3940 if (head) {
3941 Array.from(head.childNodes).forEach(child => {
3942 elem.appendChild(child);
3943 });
3944 }
3945 const body = parsed.querySelector('body');
3946 if (body) {
3947 Array.from(body.childNodes).forEach(child => {
3948 if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) {
3949 elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507
3950 } else {
3951 elem.appendChild(child);
3952 }
3953 });
3954 }
3955 }
3956 };
3957
3958 /**
3959 * @param {HTMLElement} elem
3960 * @param {string} className
3961 * @returns {boolean}
3962 */
3963 const hasClass = (elem, className) => {
3964 if (!className) {
3965 return false;
3966 }
3967 const classList = className.split(/\s+/);
3968 for (let i = 0; i < classList.length; i++) {
3969 if (!elem.classList.contains(classList[i])) {
3970 return false;
3971 }
3972 }
3973 return true;
3974 };
3975
3976 /**
3977 * @param {HTMLElement} elem
3978 * @param {SweetAlertOptions} params
3979 */
3980 const removeCustomClasses = (elem, params) => {
3981 Array.from(elem.classList).forEach(className => {
3982 if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) {
3983 elem.classList.remove(className);
3984 }
3985 });
3986 };
3987
3988 /**
3989 * @param {HTMLElement} elem
3990 * @param {SweetAlertOptions} params
3991 * @param {string} className
3992 */
3993 const applyCustomClass = (elem, params, className) => {
3994 removeCustomClasses(elem, params);
3995 if (!params.customClass) {
3996 return;
3997 }
3998 const customClass = params.customClass[(/** @type {keyof SweetAlertCustomClass} */className)];
3999 if (!customClass) {
4000 return;
4001 }
4002 if (typeof customClass !== 'string' && !customClass.forEach) {
4003 warn(`Invalid type of customClass.${className}! Expected string or iterable object, got "${typeof customClass}"`);
4004 return;
4005 }
4006 addClass(elem, customClass);
4007 };
4008
4009 /**
4010 * @param {HTMLElement} popup
4011 * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass
4012 * @returns {HTMLInputElement | null}
4013 */
4014 const getInput$1 = (popup, inputClass) => {
4015 if (!inputClass) {
4016 return null;
4017 }
4018 switch (inputClass) {
4019 case 'select':
4020 case 'textarea':
4021 case 'file':
4022 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses[inputClass]}`);
4023 case 'checkbox':
4024 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.checkbox} input`);
4025 case 'radio':
4026 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:checked`) || popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:first-child`);
4027 case 'range':
4028 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.range} input`);
4029 default:
4030 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.input}`);
4031 }
4032 };
4033
4034 /**
4035 * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input
4036 */
4037 const focusInput = input => {
4038 input.focus();
4039
4040 // place cursor at end of text in text input
4041 if (input.type !== 'file') {
4042 // http://stackoverflow.com/a/2345915
4043 const val = input.value;
4044 input.value = '';
4045 input.value = val;
4046 }
4047 };
4048
4049 /**
4050 * @param {HTMLElement | HTMLElement[] | null} target
4051 * @param {string | string[] | readonly string[] | undefined} classList
4052 * @param {boolean} condition
4053 */
4054 const toggleClass = (target, classList, condition) => {
4055 if (!target || !classList) {
4056 return;
4057 }
4058 if (typeof classList === 'string') {
4059 classList = classList.split(/\s+/).filter(Boolean);
4060 }
4061 classList.forEach(className => {
4062 if (Array.isArray(target)) {
4063 target.forEach(elem => {
4064 if (condition) {
4065 elem.classList.add(className);
4066 } else {
4067 elem.classList.remove(className);
4068 }
4069 });
4070 } else {
4071 if (condition) {
4072 target.classList.add(className);
4073 } else {
4074 target.classList.remove(className);
4075 }
4076 }
4077 });
4078 };
4079
4080 /**
4081 * @param {HTMLElement | HTMLElement[] | null} target
4082 * @param {string | string[] | readonly string[] | undefined} classList
4083 */
4084 const addClass = (target, classList) => {
4085 toggleClass(target, classList, true);
4086 };
4087
4088 /**
4089 * @param {HTMLElement | HTMLElement[] | null} target
4090 * @param {string | string[] | readonly string[] | undefined} classList
4091 */
4092 const removeClass = (target, classList) => {
4093 toggleClass(target, classList, false);
4094 };
4095
4096 /**
4097 * Get direct child of an element by class name
4098 *
4099 * @param {HTMLElement} elem
4100 * @param {string} className
4101 * @returns {HTMLElement | undefined}
4102 */
4103 const getDirectChildByClass = (elem, className) => {
4104 const children = Array.from(elem.children);
4105 for (let i = 0; i < children.length; i++) {
4106 const child = children[i];
4107 if (child instanceof HTMLElement && hasClass(child, className)) {
4108 return child;
4109 }
4110 }
4111 };
4112
4113 /**
4114 * @param {HTMLElement} elem
4115 * @param {string} property
4116 * @param {string | number | null | undefined} value
4117 */
4118 const applyNumericalStyle = (elem, property, value) => {
4119 if (value === `${parseInt(`${value}`)}`) {
4120 value = parseInt(value);
4121 }
4122 if (value || parseInt(`${value}`) === 0) {
4123 elem.style.setProperty(property, typeof value === 'number' ? `${value}px` : (/** @type {string} */value));
4124 } else {
4125 elem.style.removeProperty(property);
4126 }
4127 };
4128
4129 /**
4130 * @param {HTMLElement | null} elem
4131 * @param {string} display
4132 */
4133 const show = (elem, display = 'flex') => {
4134 if (!elem) {
4135 return;
4136 }
4137 elem.style.display = display;
4138 };
4139
4140 /**
4141 * @param {HTMLElement | null} elem
4142 */
4143 const hide = elem => {
4144 if (!elem) {
4145 return;
4146 }
4147 elem.style.display = 'none';
4148 };
4149
4150 /**
4151 * @param {HTMLElement | null} elem
4152 * @param {string} display
4153 */
4154 const showWhenInnerHtmlPresent = (elem, display = 'block') => {
4155 if (!elem) {
4156 return;
4157 }
4158 new MutationObserver(() => {
4159 toggle(elem, elem.innerHTML, display);
4160 }).observe(elem, {
4161 childList: true,
4162 subtree: true
4163 });
4164 };
4165
4166 /**
4167 * @param {HTMLElement} parent
4168 * @param {string} selector
4169 * @param {string} property
4170 * @param {string} value
4171 */
4172 const setStyle = (parent, selector, property, value) => {
4173 /** @type {HTMLElement | null} */
4174 const el = parent.querySelector(selector);
4175 if (el) {
4176 el.style.setProperty(property, value);
4177 }
4178 };
4179
4180 /**
4181 * @param {HTMLElement} elem
4182 * @param {boolean | string | null | undefined} condition
4183 * @param {string} display
4184 */
4185 const toggle = (elem, condition, display = 'flex') => {
4186 if (condition) {
4187 show(elem, display);
4188 } else {
4189 hide(elem);
4190 }
4191 };
4192
4193 /**
4194 * borrowed from jquery $(elem).is(':visible') implementation
4195 *
4196 * @param {HTMLElement | null} elem
4197 * @returns {boolean}
4198 */
4199 const isVisible$1 = elem => Boolean(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length));
4200
4201 /**
4202 * @returns {boolean}
4203 */
4204 const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton());
4205
4206 /**
4207 * @param {HTMLElement} elem
4208 * @returns {boolean}
4209 */
4210 const isScrollable = elem => Boolean(elem.scrollHeight > elem.clientHeight);
4211
4212 /**
4213 * @param {HTMLElement} element
4214 * @param {HTMLElement} stopElement
4215 * @returns {boolean}
4216 */
4217 const selfOrParentIsScrollable = (element, stopElement) => {
4218 let parent = /** @type {HTMLElement | null} */element;
4219 while (parent && parent !== stopElement) {
4220 if (isScrollable(parent)) {
4221 return true;
4222 }
4223 parent = parent.parentElement;
4224 }
4225 return false;
4226 };
4227
4228 /**
4229 * borrowed from https://stackoverflow.com/a/46352119
4230 *
4231 * @param {HTMLElement} elem
4232 * @returns {boolean}
4233 */
4234 const hasCssAnimation = elem => {
4235 const style = window.getComputedStyle(elem);
4236 const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0');
4237 const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0');
4238 return animDuration > 0 || transDuration > 0;
4239 };
4240
4241 /**
4242 * @param {number} timer
4243 * @param {boolean} reset
4244 */
4245 const animateTimerProgressBar = (timer, reset = false) => {
4246 const timerProgressBar = getTimerProgressBar();
4247 if (!timerProgressBar) {
4248 return;
4249 }
4250 if (isVisible$1(timerProgressBar)) {
4251 if (reset) {
4252 timerProgressBar.style.transition = 'none';
4253 timerProgressBar.style.width = '100%';
4254 }
4255 setTimeout(() => {
4256 timerProgressBar.style.transition = `width ${timer / 1000}s linear`;
4257 timerProgressBar.style.width = '0%';
4258 }, 10);
4259 }
4260 };
4261 const stopTimerProgressBar = () => {
4262 const timerProgressBar = getTimerProgressBar();
4263 if (!timerProgressBar) {
4264 return;
4265 }
4266 const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4267 timerProgressBar.style.removeProperty('transition');
4268 timerProgressBar.style.width = '100%';
4269 const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4270 const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100;
4271 timerProgressBar.style.width = `${timerProgressBarPercent}%`;
4272 };
4273
4274 /**
4275 * Detect Node env
4276 *
4277 * @returns {boolean}
4278 */
4279 const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
4280
4281 const sweetHTML = `
4282 <div aria-labelledby="${swalClasses.title}" aria-describedby="${swalClasses['html-container']}" class="${swalClasses.popup}" tabindex="-1">
4283 <button type="button" class="${swalClasses.close}"></button>
4284 <ul class="${swalClasses['progress-steps']}"></ul>
4285 <div class="${swalClasses.icon}"></div>
4286 <img class="${swalClasses.image}" />
4287 <h2 class="${swalClasses.title}" id="${swalClasses.title}"></h2>
4288 <div class="${swalClasses['html-container']}" id="${swalClasses['html-container']}"></div>
4289 <input class="${swalClasses.input}" id="${swalClasses.input}" />
4290 <input type="file" class="${swalClasses.file}" />
4291 <div class="${swalClasses.range}">
4292 <input type="range" />
4293 <output></output>
4294 </div>
4295 <select class="${swalClasses.select}" id="${swalClasses.select}"></select>
4296 <div class="${swalClasses.radio}"></div>
4297 <label class="${swalClasses.checkbox}">
4298 <input type="checkbox" id="${swalClasses.checkbox}" />
4299 <span class="${swalClasses.label}"></span>
4300 </label>
4301 <textarea class="${swalClasses.textarea}" id="${swalClasses.textarea}"></textarea>
4302 <div class="${swalClasses['validation-message']}" id="${swalClasses['validation-message']}"></div>
4303 <div class="${swalClasses.actions}">
4304 <div class="${swalClasses.loader}"></div>
4305 <button type="button" class="${swalClasses.confirm}"></button>
4306 <button type="button" class="${swalClasses.deny}"></button>
4307 <button type="button" class="${swalClasses.cancel}"></button>
4308 </div>
4309 <div class="${swalClasses.footer}"></div>
4310 <div class="${swalClasses['timer-progress-bar-container']}">
4311 <div class="${swalClasses['timer-progress-bar']}"></div>
4312 </div>
4313 </div>
4314 `.replace(/(^|\n)\s*/g, '');
4315
4316 /**
4317 * @returns {boolean}
4318 */
4319 const resetOldContainer = () => {
4320 const oldContainer = getContainer();
4321 if (!oldContainer) {
4322 return false;
4323 }
4324 oldContainer.remove();
4325 removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'],
4326 // @ts-ignore: 'has-column' is not defined in swalClasses but may be set dynamically
4327 swalClasses['has-column']]);
4328 return true;
4329 };
4330 const resetValidationMessage$1 = () => {
4331 if (globalState.currentInstance) {
4332 globalState.currentInstance.resetValidationMessage();
4333 }
4334 };
4335 const addInputChangeListeners = () => {
4336 const popup = getPopup();
4337 if (!popup) {
4338 return;
4339 }
4340 const input = getDirectChildByClass(popup, swalClasses.input);
4341 const file = getDirectChildByClass(popup, swalClasses.file);
4342 /** @type {HTMLInputElement | null} */
4343 const range = popup.querySelector(`.${swalClasses.range} input`);
4344 /** @type {HTMLOutputElement | null} */
4345 const rangeOutput = popup.querySelector(`.${swalClasses.range} output`);
4346 const select = getDirectChildByClass(popup, swalClasses.select);
4347 /** @type {HTMLInputElement | null} */
4348 const checkbox = popup.querySelector(`.${swalClasses.checkbox} input`);
4349 const textarea = getDirectChildByClass(popup, swalClasses.textarea);
4350 if (input) {
4351 input.oninput = resetValidationMessage$1;
4352 }
4353 if (file) {
4354 file.onchange = resetValidationMessage$1;
4355 }
4356 if (select) {
4357 select.onchange = resetValidationMessage$1;
4358 }
4359 if (checkbox) {
4360 checkbox.onchange = resetValidationMessage$1;
4361 }
4362 if (textarea) {
4363 textarea.oninput = resetValidationMessage$1;
4364 }
4365 if (range && rangeOutput) {
4366 range.oninput = () => {
4367 resetValidationMessage$1();
4368 rangeOutput.value = range.value;
4369 };
4370 range.onchange = () => {
4371 resetValidationMessage$1();
4372 rangeOutput.value = range.value;
4373 };
4374 }
4375 };
4376
4377 /**
4378 * @param {string | HTMLElement} target
4379 * @returns {HTMLElement}
4380 */
4381 const getTarget = target => {
4382 if (typeof target === 'string') {
4383 const element = document.querySelector(target);
4384 if (!element) {
4385 throw new Error(`Target element "${target}" not found`);
4386 }
4387 return /** @type {HTMLElement} */element;
4388 }
4389 return target;
4390 };
4391
4392 /**
4393 * @param {SweetAlertOptions} params
4394 */
4395 const setupAccessibility = params => {
4396 const popup = getPopup();
4397 if (!popup) {
4398 return;
4399 }
4400 popup.setAttribute('role', params.toast ? 'alert' : 'dialog');
4401 popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive');
4402 if (!params.toast) {
4403 popup.setAttribute('aria-modal', 'true');
4404 }
4405 };
4406
4407 /**
4408 * @param {HTMLElement} targetElement
4409 */
4410 const setupRTL = targetElement => {
4411 if (window.getComputedStyle(targetElement).direction === 'rtl') {
4412 addClass(getContainer(), swalClasses.rtl);
4413 globalState.isRTL = true;
4414 }
4415 };
4416
4417 /**
4418 * Add modal + backdrop to DOM
4419 *
4420 * @param {SweetAlertOptions} params
4421 */
4422 const init = params => {
4423 // Clean up the old popup container if it exists
4424 const oldContainerExisted = resetOldContainer();
4425 if (isNodeEnv()) {
4426 error('SweetAlert2 requires document to initialize');
4427 return;
4428 }
4429 const container = document.createElement('div');
4430 container.className = swalClasses.container;
4431 if (oldContainerExisted) {
4432 addClass(container, swalClasses['no-transition']);
4433 }
4434 setInnerHtml(container, sweetHTML);
4435 container.dataset['swal2Theme'] = params.theme;
4436 const targetElement = getTarget(params.target || 'body');
4437 targetElement.appendChild(container);
4438 if (params.topLayer) {
4439 container.setAttribute('popover', '');
4440 container.showPopover();
4441 }
4442 setupAccessibility(params);
4443 setupRTL(targetElement);
4444 addInputChangeListeners();
4445 };
4446
4447 /**
4448 * @param {HTMLElement | object | string} param
4449 * @param {HTMLElement} target
4450 */
4451 const parseHtmlToContainer = (param, target) => {
4452 // DOM element
4453 if (param instanceof HTMLElement) {
4454 target.appendChild(param);
4455 }
4456
4457 // Object
4458 else if (typeof param === 'object') {
4459 handleObject(param, target);
4460 }
4461
4462 // Plain string
4463 else if (param) {
4464 setInnerHtml(target, param);
4465 }
4466 };
4467
4468 /**
4469 * @param {object} param
4470 * @param {HTMLElement} target
4471 */
4472 const handleObject = (param, target) => {
4473 // JQuery element(s)
4474 if ('jquery' in param) {
4475 handleJqueryElem(target, param);
4476 }
4477
4478 // For other objects use their string representation
4479 else {
4480 setInnerHtml(target, param.toString());
4481 }
4482 };
4483
4484 /**
4485 * @param {HTMLElement} target
4486 * @param {any} elem
4487 */
4488 const handleJqueryElem = (target, elem) => {
4489 target.textContent = '';
4490 if (0 in elem) {
4491 for (let i = 0; i in elem; i++) {
4492 target.appendChild(elem[i].cloneNode(true));
4493 }
4494 } else {
4495 target.appendChild(elem.cloneNode(true));
4496 }
4497 };
4498
4499 /**
4500 * @param {SweetAlert} instance
4501 * @param {SweetAlertOptions} params
4502 */
4503 const renderActions = (instance, params) => {
4504 const actions = getActions();
4505 const loader = getLoader();
4506 if (!actions || !loader) {
4507 return;
4508 }
4509
4510 // Actions (buttons) wrapper
4511 if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) {
4512 hide(actions);
4513 } else {
4514 show(actions);
4515 }
4516
4517 // Custom class
4518 applyCustomClass(actions, params, 'actions');
4519
4520 // Render all the buttons
4521 renderButtons(actions, loader, params);
4522
4523 // Loader
4524 setInnerHtml(loader, params.loaderHtml || '');
4525 applyCustomClass(loader, params, 'loader');
4526 };
4527
4528 /**
4529 * @param {HTMLElement} actions
4530 * @param {HTMLElement} loader
4531 * @param {SweetAlertOptions} params
4532 */
4533 function renderButtons(actions, loader, params) {
4534 const confirmButton = getConfirmButton();
4535 const denyButton = getDenyButton();
4536 const cancelButton = getCancelButton();
4537 if (!confirmButton || !denyButton || !cancelButton) {
4538 return;
4539 }
4540
4541 // Render buttons
4542 renderButton(confirmButton, 'confirm', params);
4543 renderButton(denyButton, 'deny', params);
4544 renderButton(cancelButton, 'cancel', params);
4545 handleButtonsStyling(confirmButton, denyButton, cancelButton, params);
4546 if (params.reverseButtons) {
4547 if (params.toast) {
4548 actions.insertBefore(cancelButton, confirmButton);
4549 actions.insertBefore(denyButton, confirmButton);
4550 } else {
4551 actions.insertBefore(cancelButton, loader);
4552 actions.insertBefore(denyButton, loader);
4553 actions.insertBefore(confirmButton, loader);
4554 }
4555 }
4556 }
4557
4558 /**
4559 * @param {HTMLElement} confirmButton
4560 * @param {HTMLElement} denyButton
4561 * @param {HTMLElement} cancelButton
4562 * @param {SweetAlertOptions} params
4563 */
4564 function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) {
4565 if (!params.buttonsStyling) {
4566 removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4567 return;
4568 }
4569 addClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4570
4571 // Apply custom background colors to action buttons
4572 if (params.confirmButtonColor) {
4573 confirmButton.style.setProperty('--swal2-confirm-button-background-color', params.confirmButtonColor);
4574 }
4575 if (params.denyButtonColor) {
4576 denyButton.style.setProperty('--swal2-deny-button-background-color', params.denyButtonColor);
4577 }
4578 if (params.cancelButtonColor) {
4579 cancelButton.style.setProperty('--swal2-cancel-button-background-color', params.cancelButtonColor);
4580 }
4581
4582 // Apply the outline color to action buttons
4583 applyOutlineColor(confirmButton);
4584 applyOutlineColor(denyButton);
4585 applyOutlineColor(cancelButton);
4586 }
4587
4588 /**
4589 * @param {HTMLElement} button
4590 */
4591 function applyOutlineColor(button) {
4592 const buttonStyle = window.getComputedStyle(button);
4593 if (buttonStyle.getPropertyValue('--swal2-action-button-focus-box-shadow')) {
4594 // If the button already has a custom outline color, no need to change it
4595 return;
4596 }
4597 const outlineColor = buttonStyle.backgroundColor.replace(/rgba?\((\d+), (\d+), (\d+).*/, 'rgba($1, $2, $3, 0.5)');
4598 button.style.setProperty('--swal2-action-button-focus-box-shadow', buttonStyle.getPropertyValue('--swal2-outline').replace(/ rgba\(.*/, ` ${outlineColor}`));
4599 }
4600
4601 /**
4602 * @param {HTMLElement} button
4603 * @param {'confirm' | 'deny' | 'cancel'} buttonType
4604 * @param {SweetAlertOptions} params
4605 */
4606 function renderButton(button, buttonType, params) {
4607 const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType);
4608 toggle(button, params[`show${buttonName}Button`], 'inline-block');
4609 setInnerHtml(button, params[`${buttonType}ButtonText`] || ''); // Set caption text
4610 button.setAttribute('aria-label', params[`${buttonType}ButtonAriaLabel`] || ''); // ARIA label
4611
4612 // Add buttons custom classes
4613 button.className = swalClasses[buttonType];
4614 applyCustomClass(button, params, `${buttonType}Button`);
4615 }
4616
4617 /**
4618 * @param {SweetAlert} instance
4619 * @param {SweetAlertOptions} params
4620 */
4621 const renderCloseButton = (instance, params) => {
4622 const closeButton = getCloseButton();
4623 if (!closeButton) {
4624 return;
4625 }
4626 setInnerHtml(closeButton, params.closeButtonHtml || '');
4627
4628 // Custom class
4629 applyCustomClass(closeButton, params, 'closeButton');
4630 toggle(closeButton, params.showCloseButton);
4631 closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || '');
4632 };
4633
4634 /**
4635 * @param {SweetAlert} instance
4636 * @param {SweetAlertOptions} params
4637 */
4638 const renderContainer = (instance, params) => {
4639 const container = getContainer();
4640 if (!container) {
4641 return;
4642 }
4643 handleBackdropParam(container, params.backdrop);
4644 handlePositionParam(container, params.position);
4645 handleGrowParam(container, params.grow);
4646
4647 // Custom class
4648 applyCustomClass(container, params, 'container');
4649 };
4650
4651 /**
4652 * @param {HTMLElement} container
4653 * @param {SweetAlertOptions['backdrop']} backdrop
4654 */
4655 function handleBackdropParam(container, backdrop) {
4656 if (typeof backdrop === 'string') {
4657 container.style.background = backdrop;
4658 } else if (!backdrop) {
4659 addClass([document.documentElement, document.body], swalClasses['no-backdrop']);
4660 }
4661 }
4662
4663 /**
4664 * @param {HTMLElement} container
4665 * @param {SweetAlertOptions['position']} position
4666 */
4667 function handlePositionParam(container, position) {
4668 if (!position) {
4669 return;
4670 }
4671 if (position in swalClasses) {
4672 addClass(container, swalClasses[position]);
4673 } else {
4674 warn('The "position" parameter is not valid, defaulting to "center"');
4675 addClass(container, swalClasses.center);
4676 }
4677 }
4678
4679 /**
4680 * @param {HTMLElement} container
4681 * @param {SweetAlertOptions['grow']} grow
4682 */
4683 function handleGrowParam(container, grow) {
4684 if (!grow) {
4685 return;
4686 }
4687 addClass(container, swalClasses[`grow-${grow}`]);
4688 }
4689
4690 /**
4691 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
4692 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
4693 * This is the approach that Babel will probably take to implement private methods/fields
4694 * https://github.com/tc39/proposal-private-methods
4695 * https://github.com/babel/babel/pull/7555
4696 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
4697 * then we can use that language feature.
4698 */
4699
4700 var privateProps = {
4701 innerParams: new WeakMap(),
4702 domCache: new WeakMap()
4703 };
4704
4705 /// <reference path="../../../../sweetalert2.d.ts"/>
4706
4707
4708 /** @type {InputClass[]} */
4709 const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
4710
4711 /**
4712 * @param {SweetAlert} instance
4713 * @param {SweetAlertOptions} params
4714 */
4715 const renderInput = (instance, params) => {
4716 const popup = getPopup();
4717 if (!popup) {
4718 return;
4719 }
4720 const innerParams = privateProps.innerParams.get(instance);
4721 const rerender = !innerParams || params.input !== innerParams.input;
4722 inputClasses.forEach(inputClass => {
4723 const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]);
4724 if (!inputContainer) {
4725 return;
4726 }
4727
4728 // set attributes
4729 setAttributes(inputClass, params.inputAttributes);
4730
4731 // set class
4732 inputContainer.className = swalClasses[inputClass];
4733 if (rerender) {
4734 hide(inputContainer);
4735 }
4736 });
4737 if (params.input) {
4738 if (rerender) {
4739 showInput(params);
4740 }
4741 // set custom class
4742 setCustomClass(params);
4743 }
4744 };
4745
4746 /**
4747 * @param {SweetAlertOptions} params
4748 */
4749 const showInput = params => {
4750 if (!params.input) {
4751 return;
4752 }
4753 if (!renderInputType[params.input]) {
4754 error(`Unexpected type of input! Expected ${Object.keys(renderInputType).join(' | ')}, got "${params.input}"`);
4755 return;
4756 }
4757 const inputContainer = getInputContainer(params.input);
4758 if (!inputContainer) {
4759 return;
4760 }
4761 const input = renderInputType[params.input](inputContainer, params);
4762 show(inputContainer);
4763
4764 // input autofocus
4765 if (params.inputAutoFocus) {
4766 setTimeout(() => {
4767 focusInput(input);
4768 });
4769 }
4770 };
4771
4772 /**
4773 * @param {HTMLInputElement} input
4774 */
4775 const removeAttributes = input => {
4776 for (let i = 0; i < input.attributes.length; i++) {
4777 const attrName = input.attributes[i].name;
4778 if (!['id', 'type', 'value', 'style'].includes(attrName)) {
4779 input.removeAttribute(attrName);
4780 }
4781 }
4782 };
4783
4784 /**
4785 * @param {InputClass} inputClass
4786 * @param {SweetAlertOptions['inputAttributes']} inputAttributes
4787 */
4788 const setAttributes = (inputClass, inputAttributes) => {
4789 const popup = getPopup();
4790 if (!popup) {
4791 return;
4792 }
4793 const input = getInput$1(popup, inputClass);
4794 if (!input) {
4795 return;
4796 }
4797 removeAttributes(input);
4798 for (const attr in inputAttributes) {
4799 input.setAttribute(attr, inputAttributes[attr]);
4800 }
4801 };
4802
4803 /**
4804 * @param {SweetAlertOptions} params
4805 */
4806 const setCustomClass = params => {
4807 if (!params.input) {
4808 return;
4809 }
4810 const inputContainer = getInputContainer(params.input);
4811 if (inputContainer) {
4812 applyCustomClass(inputContainer, params, 'input');
4813 }
4814 };
4815
4816 /**
4817 * @param {HTMLInputElement | HTMLTextAreaElement} input
4818 * @param {SweetAlertOptions} params
4819 */
4820 const setInputPlaceholder = (input, params) => {
4821 if (!input.placeholder && params.inputPlaceholder) {
4822 input.placeholder = params.inputPlaceholder;
4823 }
4824 };
4825
4826 /**
4827 * @param {Input} input
4828 * @param {Input} prependTo
4829 * @param {SweetAlertOptions} params
4830 */
4831 const setInputLabel = (input, prependTo, params) => {
4832 if (params.inputLabel) {
4833 const label = document.createElement('label');
4834 const labelClass = swalClasses['input-label'];
4835 label.setAttribute('for', input.id);
4836 label.className = labelClass;
4837 if (typeof params.customClass === 'object') {
4838 addClass(label, params.customClass.inputLabel);
4839 }
4840 label.innerText = params.inputLabel;
4841 prependTo.insertAdjacentElement('beforebegin', label);
4842 }
4843 };
4844
4845 /**
4846 * @param {SweetAlertInput} inputType
4847 * @returns {HTMLElement | undefined}
4848 */
4849 const getInputContainer = inputType => {
4850 const popup = getPopup();
4851 if (!popup) {
4852 return;
4853 }
4854 return getDirectChildByClass(popup, swalClasses[(/** @type {SwalClass} */inputType)] || swalClasses.input);
4855 };
4856
4857 /**
4858 * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input
4859 * @param {SweetAlertOptions['inputValue']} inputValue
4860 */
4861 const checkAndSetInputValue = (input, inputValue) => {
4862 if (['string', 'number'].includes(typeof inputValue)) {
4863 input.value = `${inputValue}`;
4864 } else if (!isPromise(inputValue)) {
4865 warn(`Unexpected type of inputValue! Expected "string", "number" or "Promise", got "${typeof inputValue}"`);
4866 }
4867 };
4868
4869 /** @type {Record<SweetAlertInput, (input: Input | HTMLElement, params: SweetAlertOptions) => Input>} */
4870 const renderInputType = {};
4871
4872 /**
4873 * @param {Input | HTMLElement} input
4874 * @param {SweetAlertOptions} params
4875 * @returns {Input}
4876 */
4877 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} */
4878 (input, params) => {
4879 const inputElement = /** @type {HTMLInputElement} */input;
4880 checkAndSetInputValue(inputElement, params.inputValue);
4881 setInputLabel(inputElement, inputElement, params);
4882 setInputPlaceholder(inputElement, params);
4883 inputElement.type = /** @type {string} */params.input;
4884 return inputElement;
4885 };
4886
4887 /**
4888 * @param {Input | HTMLElement} input
4889 * @param {SweetAlertOptions} params
4890 * @returns {Input}
4891 */
4892 renderInputType.file = (input, params) => {
4893 const inputElement = /** @type {HTMLInputElement} */input;
4894 setInputLabel(inputElement, inputElement, params);
4895 setInputPlaceholder(inputElement, params);
4896 return inputElement;
4897 };
4898
4899 /**
4900 * @param {Input | HTMLElement} range
4901 * @param {SweetAlertOptions} params
4902 * @returns {Input}
4903 */
4904 renderInputType.range = (range, params) => {
4905 const rangeContainer = /** @type {HTMLElement} */range;
4906 const rangeInput = rangeContainer.querySelector('input');
4907 const rangeOutput = rangeContainer.querySelector('output');
4908 if (rangeInput) {
4909 checkAndSetInputValue(rangeInput, params.inputValue);
4910 rangeInput.type = /** @type {string} */params.input;
4911 setInputLabel(rangeInput, /** @type {Input} */range, params);
4912 }
4913 if (rangeOutput) {
4914 checkAndSetInputValue(rangeOutput, params.inputValue);
4915 }
4916 return /** @type {Input} */range;
4917 };
4918
4919 /**
4920 * @param {Input | HTMLElement} select
4921 * @param {SweetAlertOptions} params
4922 * @returns {Input}
4923 */
4924 renderInputType.select = (select, params) => {
4925 const selectElement = /** @type {HTMLSelectElement} */select;
4926 selectElement.textContent = '';
4927 if (params.inputPlaceholder) {
4928 const placeholder = document.createElement('option');
4929 setInnerHtml(placeholder, params.inputPlaceholder);
4930 placeholder.value = '';
4931 placeholder.disabled = true;
4932 placeholder.selected = true;
4933 selectElement.appendChild(placeholder);
4934 }
4935 setInputLabel(selectElement, selectElement, params);
4936 return selectElement;
4937 };
4938
4939 /**
4940 * @param {Input | HTMLElement} radio
4941 * @returns {Input}
4942 */
4943 renderInputType.radio = radio => {
4944 const radioElement = /** @type {HTMLElement} */radio;
4945 radioElement.textContent = '';
4946 return /** @type {Input} */radio;
4947 };
4948
4949 /**
4950 * @param {Input | HTMLElement} checkboxContainer
4951 * @param {SweetAlertOptions} params
4952 * @returns {Input}
4953 */
4954 renderInputType.checkbox = (checkboxContainer, params) => {
4955 const popup = getPopup();
4956 if (!popup) {
4957 throw new Error('Popup not found');
4958 }
4959 const checkbox = getInput$1(popup, 'checkbox');
4960 if (!checkbox) {
4961 throw new Error('Checkbox input not found');
4962 }
4963 checkbox.value = '1';
4964 checkbox.checked = Boolean(params.inputValue);
4965 const containerElement = /** @type {HTMLElement} */checkboxContainer;
4966 const label = containerElement.querySelector('span');
4967 if (label) {
4968 const placeholderOrLabel = params.inputPlaceholder || params.inputLabel;
4969 if (placeholderOrLabel) {
4970 setInnerHtml(label, placeholderOrLabel);
4971 }
4972 }
4973 return checkbox;
4974 };
4975
4976 /**
4977 * @param {Input | HTMLElement} textarea
4978 * @param {SweetAlertOptions} params
4979 * @returns {Input}
4980 */
4981 renderInputType.textarea = (textarea, params) => {
4982 const textareaElement = /** @type {HTMLTextAreaElement} */textarea;
4983 checkAndSetInputValue(textareaElement, params.inputValue);
4984 setInputPlaceholder(textareaElement, params);
4985 setInputLabel(textareaElement, textareaElement, params);
4986
4987 /**
4988 * @param {HTMLElement} el
4989 * @returns {number}
4990 */
4991 const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight);
4992
4993 // https://github.com/sweetalert2/sweetalert2/issues/2291
4994 setTimeout(() => {
4995 // https://github.com/sweetalert2/sweetalert2/issues/1699
4996 if ('MutationObserver' in window) {
4997 const popup = getPopup();
4998 if (!popup) {
4999 return;
5000 }
5001 const initialPopupWidth = parseInt(window.getComputedStyle(popup).width);
5002 const textareaResizeHandler = () => {
5003 // check if texarea is still in document (i.e. popup wasn't closed in the meantime)
5004 if (!document.body.contains(textareaElement)) {
5005 return;
5006 }
5007 const textareaWidth = textareaElement.offsetWidth + getMargin(textareaElement);
5008 const popupElement = getPopup();
5009 if (popupElement) {
5010 if (textareaWidth > initialPopupWidth) {
5011 popupElement.style.width = `${textareaWidth}px`;
5012 } else {
5013 applyNumericalStyle(popupElement, 'width', params.width);
5014 }
5015 }
5016 };
5017 new MutationObserver(textareaResizeHandler).observe(textareaElement, {
5018 attributes: true,
5019 attributeFilter: ['style']
5020 });
5021 }
5022 });
5023 return textareaElement;
5024 };
5025
5026 /**
5027 * @param {SweetAlert} instance
5028 * @param {SweetAlertOptions} params
5029 */
5030 const renderContent = (instance, params) => {
5031 const htmlContainer = getHtmlContainer();
5032 if (!htmlContainer) {
5033 return;
5034 }
5035 showWhenInnerHtmlPresent(htmlContainer);
5036 applyCustomClass(htmlContainer, params, 'htmlContainer');
5037
5038 // Content as HTML
5039 if (params.html) {
5040 parseHtmlToContainer(params.html, htmlContainer);
5041 show(htmlContainer, 'block');
5042 }
5043
5044 // Content as plain text
5045 else if (params.text) {
5046 htmlContainer.textContent = params.text;
5047 show(htmlContainer, 'block');
5048 }
5049
5050 // No content
5051 else {
5052 hide(htmlContainer);
5053 }
5054 renderInput(instance, params);
5055 };
5056
5057 /**
5058 * @param {SweetAlert} instance
5059 * @param {SweetAlertOptions} params
5060 */
5061 const renderFooter = (instance, params) => {
5062 const footer = getFooter();
5063 if (!footer) {
5064 return;
5065 }
5066 showWhenInnerHtmlPresent(footer);
5067 toggle(footer, Boolean(params.footer), 'block');
5068 if (params.footer) {
5069 parseHtmlToContainer(params.footer, footer);
5070 }
5071
5072 // Custom class
5073 applyCustomClass(footer, params, 'footer');
5074 };
5075
5076 /**
5077 * @param {SweetAlert} instance
5078 * @param {SweetAlertOptions} params
5079 */
5080 const renderIcon = (instance, params) => {
5081 const innerParams = privateProps.innerParams.get(instance);
5082 const icon = getIcon();
5083 if (!icon) {
5084 return;
5085 }
5086
5087 // if the given icon already rendered, apply the styling without re-rendering the icon
5088 if (innerParams && params.icon === innerParams.icon) {
5089 // Custom or default content
5090 setContent(icon, params);
5091 applyStyles(icon, params);
5092 return;
5093 }
5094 if (!params.icon && !params.iconHtml) {
5095 hide(icon);
5096 return;
5097 }
5098 if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) {
5099 error(`Unknown icon! Expected "success", "error", "warning", "info" or "question", got "${params.icon}"`);
5100 hide(icon);
5101 return;
5102 }
5103 show(icon);
5104
5105 // Custom or default content
5106 setContent(icon, params);
5107 applyStyles(icon, params);
5108
5109 // Animate icon
5110 addClass(icon, params.showClass && params.showClass.icon);
5111
5112 // Re-adjust the success icon on system theme change
5113 const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
5114 colorSchemeQueryList.addEventListener('change', adjustSuccessIconBackgroundColor);
5115 };
5116
5117 /**
5118 * @param {HTMLElement} icon
5119 * @param {SweetAlertOptions} params
5120 */
5121 const applyStyles = (icon, params) => {
5122 for (const [iconType, iconClassName] of Object.entries(iconTypes)) {
5123 if (params.icon !== iconType) {
5124 removeClass(icon, iconClassName);
5125 }
5126 }
5127 addClass(icon, params.icon && iconTypes[params.icon]);
5128
5129 // Icon color
5130 setColor(icon, params);
5131
5132 // Success icon background color
5133 adjustSuccessIconBackgroundColor();
5134
5135 // Custom class
5136 applyCustomClass(icon, params, 'icon');
5137 };
5138
5139 // Adjust success icon background color to match the popup background color
5140 const adjustSuccessIconBackgroundColor = () => {
5141 const popup = getPopup();
5142 if (!popup) {
5143 return;
5144 }
5145 const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color');
5146 /** @type {NodeListOf<HTMLElement>} */
5147 const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix');
5148 for (let i = 0; i < successIconParts.length; i++) {
5149 successIconParts[i].style.backgroundColor = popupBackgroundColor;
5150 }
5151 };
5152
5153 /**
5154 *
5155 * @param {SweetAlertOptions} params
5156 * @returns {string}
5157 */
5158 const successIconHtml = params => `
5159 ${params.animation ? '<div class="swal2-success-circular-line-left"></div>' : ''}
5160 <span class="swal2-success-line-tip"></span> <span class="swal2-success-line-long"></span>
5161 <div class="swal2-success-ring"></div>
5162 ${params.animation ? '<div class="swal2-success-fix"></div>' : ''}
5163 ${params.animation ? '<div class="swal2-success-circular-line-right"></div>' : ''}
5164 `;
5165 const errorIconHtml = `
5166 <span class="swal2-x-mark">
5167 <span class="swal2-x-mark-line-left"></span>
5168 <span class="swal2-x-mark-line-right"></span>
5169 </span>
5170 `;
5171
5172 /**
5173 * @param {HTMLElement} icon
5174 * @param {SweetAlertOptions} params
5175 */
5176 const setContent = (icon, params) => {
5177 if (!params.icon && !params.iconHtml) {
5178 return;
5179 }
5180 let oldContent = icon.innerHTML;
5181 let newContent = '';
5182 if (params.iconHtml) {
5183 newContent = iconContent(params.iconHtml);
5184 } else if (params.icon === 'success') {
5185 newContent = successIconHtml(params);
5186 oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor()
5187 } else if (params.icon === 'error') {
5188 newContent = errorIconHtml;
5189 } else if (params.icon) {
5190 const defaultIconHtml = {
5191 question: '?',
5192 warning: '!',
5193 info: 'i'
5194 };
5195 newContent = iconContent(defaultIconHtml[params.icon]);
5196 }
5197 if (oldContent.trim() !== newContent.trim()) {
5198 setInnerHtml(icon, newContent);
5199 }
5200 };
5201
5202 /**
5203 * @param {HTMLElement} icon
5204 * @param {SweetAlertOptions} params
5205 */
5206 const setColor = (icon, params) => {
5207 if (!params.iconColor) {
5208 return;
5209 }
5210 icon.style.color = params.iconColor;
5211 icon.style.borderColor = params.iconColor;
5212 for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) {
5213 setStyle(icon, sel, 'background-color', params.iconColor);
5214 }
5215 setStyle(icon, '.swal2-success-ring', 'border-color', params.iconColor);
5216 };
5217
5218 /**
5219 * @param {string} content
5220 * @returns {string}
5221 */
5222 const iconContent = content => `<div class="${swalClasses['icon-content']}">${content}</div>`;
5223
5224 /**
5225 * @param {SweetAlert} instance
5226 * @param {SweetAlertOptions} params
5227 */
5228 const renderImage = (instance, params) => {
5229 const image = getImage();
5230 if (!image) {
5231 return;
5232 }
5233 if (!params.imageUrl) {
5234 hide(image);
5235 return;
5236 }
5237 show(image, '');
5238
5239 // Src, alt
5240 image.setAttribute('src', params.imageUrl);
5241 image.setAttribute('alt', params.imageAlt || '');
5242
5243 // Width, height
5244 applyNumericalStyle(image, 'width', params.imageWidth);
5245 applyNumericalStyle(image, 'height', params.imageHeight);
5246
5247 // Class
5248 image.className = swalClasses.image;
5249 applyCustomClass(image, params, 'image');
5250 };
5251
5252 let dragging = false;
5253 let mousedownX = 0;
5254 let mousedownY = 0;
5255 let initialX = 0;
5256 let initialY = 0;
5257
5258 /**
5259 * @param {HTMLElement} popup
5260 */
5261 const addDraggableListeners = popup => {
5262 popup.addEventListener('mousedown', down);
5263 document.body.addEventListener('mousemove', move);
5264 popup.addEventListener('mouseup', up);
5265 popup.addEventListener('touchstart', down);
5266 document.body.addEventListener('touchmove', move);
5267 popup.addEventListener('touchend', up);
5268 };
5269
5270 /**
5271 * @param {HTMLElement} popup
5272 */
5273 const removeDraggableListeners = popup => {
5274 popup.removeEventListener('mousedown', down);
5275 document.body.removeEventListener('mousemove', move);
5276 popup.removeEventListener('mouseup', up);
5277 popup.removeEventListener('touchstart', down);
5278 document.body.removeEventListener('touchmove', move);
5279 popup.removeEventListener('touchend', up);
5280 };
5281
5282 /**
5283 * @param {MouseEvent | TouchEvent} event
5284 */
5285 const down = event => {
5286 const popup = getPopup();
5287 if (!popup) {
5288 return;
5289 }
5290 const icon = getIcon();
5291 if (event.target === popup || icon && icon.contains(/** @type {HTMLElement} */event.target)) {
5292 dragging = true;
5293 const clientXY = getClientXY(event);
5294 mousedownX = clientXY.clientX;
5295 mousedownY = clientXY.clientY;
5296 initialX = parseInt(popup.style.insetInlineStart) || 0;
5297 initialY = parseInt(popup.style.insetBlockStart) || 0;
5298 addClass(popup, 'swal2-dragging');
5299 }
5300 };
5301
5302 /**
5303 * @param {MouseEvent | TouchEvent} event
5304 */
5305 const move = event => {
5306 const popup = getPopup();
5307 if (!popup) {
5308 return;
5309 }
5310 if (dragging) {
5311 let {
5312 clientX,
5313 clientY
5314 } = getClientXY(event);
5315 const deltaX = clientX - mousedownX;
5316 // In RTL mode, negate the horizontal delta since insetInlineStart refers to the right edge
5317 popup.style.insetInlineStart = `${initialX + (globalState.isRTL ? -deltaX : deltaX)}px`;
5318 popup.style.insetBlockStart = `${initialY + (clientY - mousedownY)}px`;
5319 }
5320 };
5321 const up = () => {
5322 const popup = getPopup();
5323 dragging = false;
5324 removeClass(popup, 'swal2-dragging');
5325 };
5326
5327 /**
5328 * @param {MouseEvent | TouchEvent} event
5329 * @returns {{ clientX: number, clientY: number }}
5330 */
5331 const getClientXY = event => {
5332 let clientX = 0,
5333 clientY = 0;
5334 if (event.type.startsWith('mouse')) {
5335 clientX = /** @type {MouseEvent} */event.clientX;
5336 clientY = /** @type {MouseEvent} */event.clientY;
5337 } else if (event.type.startsWith('touch')) {
5338 clientX = /** @type {TouchEvent} */event.touches[0].clientX;
5339 clientY = /** @type {TouchEvent} */event.touches[0].clientY;
5340 }
5341 return {
5342 clientX,
5343 clientY
5344 };
5345 };
5346
5347 /**
5348 * @param {SweetAlert} instance
5349 * @param {SweetAlertOptions} params
5350 */
5351 const renderPopup = (instance, params) => {
5352 const container = getContainer();
5353 const popup = getPopup();
5354 if (!container || !popup) {
5355 return;
5356 }
5357
5358 // Width
5359 // https://github.com/sweetalert2/sweetalert2/issues/2170
5360 if (params.toast) {
5361 applyNumericalStyle(container, 'width', params.width);
5362 popup.style.width = '100%';
5363 const loader = getLoader();
5364 if (loader) {
5365 popup.insertBefore(loader, getIcon());
5366 }
5367 } else {
5368 applyNumericalStyle(popup, 'width', params.width);
5369 }
5370
5371 // Padding
5372 applyNumericalStyle(popup, 'padding', params.padding);
5373
5374 // Color
5375 if (params.color) {
5376 popup.style.color = params.color;
5377 }
5378
5379 // Background
5380 if (params.background) {
5381 popup.style.background = params.background;
5382 }
5383 hide(getValidationMessage());
5384
5385 // Classes
5386 addClasses$1(popup, params);
5387 if (params.draggable && !params.toast) {
5388 addClass(popup, swalClasses.draggable);
5389 addDraggableListeners(popup);
5390 } else {
5391 removeClass(popup, swalClasses.draggable);
5392 removeDraggableListeners(popup);
5393 }
5394 };
5395
5396 /**
5397 * @param {HTMLElement} popup
5398 * @param {SweetAlertOptions} params
5399 */
5400 const addClasses$1 = (popup, params) => {
5401 const showClass = params.showClass || {};
5402 // Default Class + showClass when updating Swal.update({})
5403 popup.className = `${swalClasses.popup} ${isVisible$1(popup) ? showClass.popup : ''}`;
5404 if (params.toast) {
5405 addClass([document.documentElement, document.body], swalClasses['toast-shown']);
5406 addClass(popup, swalClasses.toast);
5407 } else {
5408 addClass(popup, swalClasses.modal);
5409 }
5410
5411 // Custom class
5412 applyCustomClass(popup, params, 'popup');
5413 // TODO: remove in the next major
5414 if (typeof params.customClass === 'string') {
5415 addClass(popup, params.customClass);
5416 }
5417
5418 // Icon class (#1842)
5419 if (params.icon) {
5420 addClass(popup, swalClasses[`icon-${params.icon}`]);
5421 }
5422 };
5423
5424 /**
5425 * @param {SweetAlert} instance
5426 * @param {SweetAlertOptions} params
5427 */
5428 const renderProgressSteps = (instance, params) => {
5429 const progressStepsContainer = getProgressSteps();
5430 if (!progressStepsContainer) {
5431 return;
5432 }
5433 const {
5434 progressSteps,
5435 currentProgressStep
5436 } = params;
5437 if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) {
5438 hide(progressStepsContainer);
5439 return;
5440 }
5441 show(progressStepsContainer);
5442 progressStepsContainer.textContent = '';
5443 if (currentProgressStep >= progressSteps.length) {
5444 warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)');
5445 }
5446 progressSteps.forEach((step, index) => {
5447 const stepEl = createStepElement(step);
5448 progressStepsContainer.appendChild(stepEl);
5449 if (index === currentProgressStep) {
5450 addClass(stepEl, swalClasses['active-progress-step']);
5451 }
5452 if (index !== progressSteps.length - 1) {
5453 const lineEl = createLineElement(params);
5454 progressStepsContainer.appendChild(lineEl);
5455 }
5456 });
5457 };
5458
5459 /**
5460 * @param {string} step
5461 * @returns {HTMLLIElement}
5462 */
5463 const createStepElement = step => {
5464 const stepEl = document.createElement('li');
5465 addClass(stepEl, swalClasses['progress-step']);
5466 setInnerHtml(stepEl, step);
5467 return stepEl;
5468 };
5469
5470 /**
5471 * @param {SweetAlertOptions} params
5472 * @returns {HTMLLIElement}
5473 */
5474 const createLineElement = params => {
5475 const lineEl = document.createElement('li');
5476 addClass(lineEl, swalClasses['progress-step-line']);
5477 if (params.progressStepsDistance) {
5478 applyNumericalStyle(lineEl, 'width', params.progressStepsDistance);
5479 }
5480 return lineEl;
5481 };
5482
5483 /**
5484 * @param {SweetAlert} instance
5485 * @param {SweetAlertOptions} params
5486 */
5487 const renderTitle = (instance, params) => {
5488 const title = getTitle();
5489 if (!title) {
5490 return;
5491 }
5492 showWhenInnerHtmlPresent(title);
5493 toggle(title, Boolean(params.title || params.titleText), 'block');
5494 if (params.title) {
5495 parseHtmlToContainer(params.title, title);
5496 }
5497 if (params.titleText) {
5498 title.innerText = params.titleText;
5499 }
5500
5501 // Custom class
5502 applyCustomClass(title, params, 'title');
5503 };
5504
5505 /**
5506 * @param {SweetAlert} instance
5507 * @param {SweetAlertOptions} params
5508 */
5509 const render = (instance, params) => {
5510 var _globalState$eventEmi;
5511 renderPopup(instance, params);
5512 renderContainer(instance, params);
5513 renderProgressSteps(instance, params);
5514 renderIcon(instance, params);
5515 renderImage(instance, params);
5516 renderTitle(instance, params);
5517 renderCloseButton(instance, params);
5518 renderContent(instance, params);
5519 renderActions(instance, params);
5520 renderFooter(instance, params);
5521 const popup = getPopup();
5522 if (typeof params.didRender === 'function' && popup) {
5523 params.didRender(popup);
5524 }
5525 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didRender', popup);
5526 };
5527
5528 /*
5529 * Global function to determine if SweetAlert2 popup is shown
5530 */
5531 const isVisible = () => {
5532 return isVisible$1(getPopup());
5533 };
5534
5535 /*
5536 * Global function to click 'Confirm' button
5537 */
5538 const clickConfirm = () => {
5539 var _dom$getConfirmButton;
5540 return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click();
5541 };
5542
5543 /*
5544 * Global function to click 'Deny' button
5545 */
5546 const clickDeny = () => {
5547 var _dom$getDenyButton;
5548 return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click();
5549 };
5550
5551 /*
5552 * Global function to click 'Cancel' button
5553 */
5554 const clickCancel = () => {
5555 var _dom$getCancelButton;
5556 return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click();
5557 };
5558
5559 /** @type {Record<DismissReason, DismissReason>} */
5560 const DismissReason = Object.freeze({
5561 cancel: 'cancel',
5562 backdrop: 'backdrop',
5563 close: 'close',
5564 esc: 'esc',
5565 timer: 'timer'
5566 });
5567
5568 /**
5569 * @param {GlobalState} globalState
5570 */
5571 const removeKeydownHandler = globalState => {
5572 if (globalState.keydownTarget && globalState.keydownHandlerAdded && globalState.keydownHandler) {
5573 const handler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */globalState.keydownHandler;
5574 globalState.keydownTarget.removeEventListener('keydown', handler, {
5575 capture: globalState.keydownListenerCapture
5576 });
5577 globalState.keydownHandlerAdded = false;
5578 }
5579 };
5580
5581 /**
5582 * @param {GlobalState} globalState
5583 * @param {SweetAlertOptions} innerParams
5584 * @param {(dismiss: DismissReason) => void} dismissWith
5585 */
5586 const addKeydownHandler = (globalState, innerParams, dismissWith) => {
5587 removeKeydownHandler(globalState);
5588 if (!innerParams.toast) {
5589 /** @type {(this: HTMLElement, event: KeyboardEvent) => void} */
5590 const handler = e => keydownHandler(innerParams, e, dismissWith);
5591 globalState.keydownHandler = handler;
5592 const target = innerParams.keydownListenerCapture ? window : getPopup();
5593 if (target) {
5594 globalState.keydownTarget = target;
5595 globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
5596 const eventHandler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */handler;
5597 globalState.keydownTarget.addEventListener('keydown', eventHandler, {
5598 capture: globalState.keydownListenerCapture
5599 });
5600 globalState.keydownHandlerAdded = true;
5601 }
5602 }
5603 };
5604
5605 /**
5606 * @param {number} index
5607 * @param {number} increment
5608 */
5609 const setFocus = (index, increment) => {
5610 var _dom$getPopup;
5611 const focusableElements = getFocusableElements();
5612 // search for visible elements and select the next possible match
5613 if (focusableElements.length) {
5614 index = index + increment;
5615
5616 // shift + tab when .swal2-popup is focused
5617 if (index === -2) {
5618 index = focusableElements.length - 1;
5619 }
5620
5621 // rollover to first item
5622 if (index === focusableElements.length) {
5623 index = 0;
5624
5625 // go to last item
5626 } else if (index === -1) {
5627 index = focusableElements.length - 1;
5628 }
5629 focusableElements[index].focus();
5630 return;
5631 }
5632 // no visible focusable elements, focus the popup
5633 (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus();
5634 };
5635 const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
5636 const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
5637
5638 /**
5639 * @param {SweetAlertOptions} innerParams
5640 * @param {KeyboardEvent} event
5641 * @param {(dismiss: DismissReason) => void} dismissWith
5642 */
5643 const keydownHandler = (innerParams, event, dismissWith) => {
5644 if (!innerParams) {
5645 return; // This instance has already been destroyed
5646 }
5647
5648 // Ignore keydown during IME composition
5649 // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
5650 // https://github.com/sweetalert2/sweetalert2/issues/720
5651 // https://github.com/sweetalert2/sweetalert2/issues/2406
5652 if (event.isComposing || event.keyCode === 229) {
5653 return;
5654 }
5655 if (innerParams.stopKeydownPropagation) {
5656 event.stopPropagation();
5657 }
5658
5659 // ENTER
5660 if (event.key === 'Enter') {
5661 handleEnter(event, innerParams);
5662 }
5663
5664 // TAB
5665 else if (event.key === 'Tab') {
5666 handleTab(event);
5667 }
5668
5669 // ARROWS - switch focus between buttons
5670 else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) {
5671 handleArrows(event.key);
5672 }
5673
5674 // ESC
5675 else if (event.key === 'Escape') {
5676 handleEsc(event, innerParams, dismissWith);
5677 }
5678 };
5679
5680 /**
5681 * @param {KeyboardEvent} event
5682 * @param {SweetAlertOptions} innerParams
5683 */
5684 const handleEnter = (event, innerParams) => {
5685 // https://github.com/sweetalert2/sweetalert2/issues/2386
5686 if (!callIfFunction(innerParams.allowEnterKey)) {
5687 return;
5688 }
5689 const popup = getPopup();
5690 if (!popup || !innerParams.input) {
5691 return;
5692 }
5693 const input = getInput$1(popup, innerParams.input);
5694 if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) {
5695 if (['textarea', 'file'].includes(innerParams.input)) {
5696 return; // do not submit
5697 }
5698 clickConfirm();
5699 event.preventDefault();
5700 }
5701 };
5702
5703 /**
5704 * @param {KeyboardEvent} event
5705 */
5706 const handleTab = event => {
5707 const targetElement = event.target;
5708 const focusableElements = getFocusableElements();
5709 let btnIndex = -1;
5710 for (let i = 0; i < focusableElements.length; i++) {
5711 if (targetElement === focusableElements[i]) {
5712 btnIndex = i;
5713 break;
5714 }
5715 }
5716
5717 // Cycle to the next button
5718 if (!event.shiftKey) {
5719 setFocus(btnIndex, 1);
5720 }
5721
5722 // Cycle to the prev button
5723 else {
5724 setFocus(btnIndex, -1);
5725 }
5726 event.stopPropagation();
5727 event.preventDefault();
5728 };
5729
5730 /**
5731 * @param {string} key
5732 */
5733 const handleArrows = key => {
5734 const actions = getActions();
5735 const confirmButton = getConfirmButton();
5736 const denyButton = getDenyButton();
5737 const cancelButton = getCancelButton();
5738 if (!actions || !confirmButton || !denyButton || !cancelButton) {
5739 return;
5740 }
5741 /** @type HTMLElement[] */
5742 const buttons = [confirmButton, denyButton, cancelButton];
5743 if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) {
5744 return;
5745 }
5746 const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
5747 let buttonToFocus = document.activeElement;
5748 if (!buttonToFocus) {
5749 return;
5750 }
5751 for (let i = 0; i < actions.children.length; i++) {
5752 buttonToFocus = buttonToFocus[sibling];
5753 if (!buttonToFocus) {
5754 return;
5755 }
5756 if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) {
5757 break;
5758 }
5759 }
5760 if (buttonToFocus instanceof HTMLButtonElement) {
5761 buttonToFocus.focus();
5762 }
5763 };
5764
5765 /**
5766 * @param {KeyboardEvent} event
5767 * @param {SweetAlertOptions} innerParams
5768 * @param {(dismiss: DismissReason) => void} dismissWith
5769 */
5770 const handleEsc = (event, innerParams, dismissWith) => {
5771 event.preventDefault();
5772 if (callIfFunction(innerParams.allowEscapeKey)) {
5773 dismissWith(DismissReason.esc);
5774 }
5775 };
5776
5777 /**
5778 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
5779 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
5780 * This is the approach that Babel will probably take to implement private methods/fields
5781 * https://github.com/tc39/proposal-private-methods
5782 * https://github.com/babel/babel/pull/7555
5783 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
5784 * then we can use that language feature.
5785 */
5786
5787 var privateMethods = {
5788 swalPromiseResolve: new WeakMap(),
5789 swalPromiseReject: new WeakMap()
5790 };
5791
5792 // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/
5793 // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
5794 // elements not within the active modal dialog will not be surfaced if a user opens a screen
5795 // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
5796
5797 const setAriaHidden = () => {
5798 const container = getContainer();
5799 const bodyChildren = Array.from(document.body.children);
5800 bodyChildren.forEach(el => {
5801 if (el.contains(container)) {
5802 return;
5803 }
5804 if (el.hasAttribute('aria-hidden')) {
5805 el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || '');
5806 }
5807 el.setAttribute('aria-hidden', 'true');
5808 });
5809 };
5810 const unsetAriaHidden = () => {
5811 const bodyChildren = Array.from(document.body.children);
5812 bodyChildren.forEach(el => {
5813 if (el.hasAttribute('data-previous-aria-hidden')) {
5814 el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || '');
5815 el.removeAttribute('data-previous-aria-hidden');
5816 } else {
5817 el.removeAttribute('aria-hidden');
5818 }
5819 });
5820 };
5821
5822 // @ts-ignore
5823 const isSafariOrIOS = typeof window !== 'undefined' && Boolean(window.GestureEvent); // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394
5824
5825 /**
5826 * Fix iOS scrolling
5827 * http://stackoverflow.com/q/39626302
5828 */
5829 const iOSfix = () => {
5830 if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) {
5831 const offset = document.body.scrollTop;
5832 document.body.style.top = `${offset * -1}px`;
5833 addClass(document.body, swalClasses.iosfix);
5834 lockBodyScroll();
5835 }
5836 };
5837
5838 /**
5839 * https://github.com/sweetalert2/sweetalert2/issues/1246
5840 */
5841 const lockBodyScroll = () => {
5842 const container = getContainer();
5843 if (!container) {
5844 return;
5845 }
5846 /** @type {boolean} */
5847 let preventTouchMove;
5848 /**
5849 * @param {TouchEvent} event
5850 */
5851 container.ontouchstart = event => {
5852 preventTouchMove = shouldPreventTouchMove(event);
5853 };
5854 /**
5855 * @param {TouchEvent} event
5856 */
5857 container.ontouchmove = event => {
5858 if (preventTouchMove) {
5859 event.preventDefault();
5860 event.stopPropagation();
5861 }
5862 };
5863 };
5864
5865 /**
5866 * @param {TouchEvent} event
5867 * @returns {boolean}
5868 */
5869 const shouldPreventTouchMove = event => {
5870 const target = event.target;
5871 const container = getContainer();
5872 const htmlContainer = getHtmlContainer();
5873 if (!container || !htmlContainer) {
5874 return false;
5875 }
5876 if (isStylus(event) || isZoom(event)) {
5877 return false;
5878 }
5879 if (target === container) {
5880 return true;
5881 }
5882 if (!isScrollable(container) && target instanceof HTMLElement && !selfOrParentIsScrollable(target, htmlContainer) &&
5883 // #2823
5884 target.tagName !== 'INPUT' &&
5885 // #1603
5886 target.tagName !== 'TEXTAREA' &&
5887 // #2266
5888 !(isScrollable(htmlContainer) &&
5889 // #1944
5890 htmlContainer.contains(target))) {
5891 return true;
5892 }
5893 return false;
5894 };
5895
5896 /**
5897 * https://github.com/sweetalert2/sweetalert2/issues/1786
5898 *
5899 * @param {TouchEvent} event
5900 * @returns {boolean}
5901 */
5902 const isStylus = event => {
5903 return Boolean(event.touches && event.touches.length &&
5904 // @ts-ignore - touchType is not a standard property
5905 event.touches[0].touchType === 'stylus');
5906 };
5907
5908 /**
5909 * https://github.com/sweetalert2/sweetalert2/issues/1891
5910 *
5911 * @param {TouchEvent} event
5912 * @returns {boolean}
5913 */
5914 const isZoom = event => {
5915 return event.touches && event.touches.length > 1;
5916 };
5917 const undoIOSfix = () => {
5918 if (hasClass(document.body, swalClasses.iosfix)) {
5919 const offset = parseInt(document.body.style.top, 10);
5920 removeClass(document.body, swalClasses.iosfix);
5921 document.body.style.top = '';
5922 document.body.scrollTop = offset * -1;
5923 }
5924 };
5925
5926 /**
5927 * Measure scrollbar width for padding body during modal show/hide
5928 * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js
5929 *
5930 * @returns {number}
5931 */
5932 const measureScrollbar = () => {
5933 const scrollDiv = document.createElement('div');
5934 scrollDiv.className = swalClasses['scrollbar-measure'];
5935 document.body.appendChild(scrollDiv);
5936 const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
5937 document.body.removeChild(scrollDiv);
5938 return scrollbarWidth;
5939 };
5940
5941 /**
5942 * Remember state in cases where opening and handling a modal will fiddle with it.
5943 * @type {number | null}
5944 */
5945 let previousBodyPadding = null;
5946
5947 /**
5948 * @param {string} initialBodyOverflow
5949 */
5950 const replaceScrollbarWithPadding = initialBodyOverflow => {
5951 // for queues, do not do this more than once
5952 if (previousBodyPadding !== null) {
5953 return;
5954 }
5955 // if the body has overflow
5956 if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663
5957 ) {
5958 // add padding so the content doesn't shift after removal of scrollbar
5959 previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
5960 document.body.style.paddingRight = `${previousBodyPadding + measureScrollbar()}px`;
5961 }
5962 };
5963 const undoReplaceScrollbarWithPadding = () => {
5964 if (previousBodyPadding !== null) {
5965 document.body.style.paddingRight = `${previousBodyPadding}px`;
5966 previousBodyPadding = null;
5967 }
5968 };
5969
5970 /**
5971 * @param {SweetAlert} instance
5972 * @param {HTMLElement} container
5973 * @param {boolean} returnFocus
5974 * @param {(() => void) | undefined} didClose
5975 */
5976 function removePopupAndResetState(instance, container, returnFocus, didClose) {
5977 if (isToast()) {
5978 triggerDidCloseAndDispose(instance, didClose);
5979 } else {
5980 restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
5981 removeKeydownHandler(globalState);
5982 }
5983
5984 // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088
5985 // for some reason removing the container in Safari will scroll the document to bottom
5986 if (isSafariOrIOS) {
5987 container.setAttribute('style', 'display:none !important');
5988 container.removeAttribute('class');
5989 container.innerHTML = '';
5990 } else {
5991 container.remove();
5992 }
5993 if (isModal()) {
5994 undoReplaceScrollbarWithPadding();
5995 undoIOSfix();
5996 unsetAriaHidden();
5997 }
5998 removeBodyClasses();
5999 }
6000
6001 /**
6002 * Remove SweetAlert2 classes from body
6003 */
6004 function removeBodyClasses() {
6005 removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
6006 }
6007
6008 /**
6009 * Instance method to close sweetAlert
6010 *
6011 * @param {SweetAlertResult | undefined} resolveValue
6012 * @this {SweetAlert}
6013 */
6014 function close(resolveValue) {
6015 resolveValue = prepareResolveValue(resolveValue);
6016 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
6017 const didClose = triggerClosePopup(this);
6018 if (this.isAwaitingPromise) {
6019 // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
6020 if (!resolveValue.isDismissed) {
6021 handleAwaitingPromise(this);
6022 swalPromiseResolve(resolveValue);
6023 }
6024 } else if (didClose) {
6025 // Resolve Swal promise
6026 swalPromiseResolve(resolveValue);
6027 }
6028 }
6029
6030 /**
6031 * @param {SweetAlert} instance
6032 * @returns {boolean}
6033 */
6034 const triggerClosePopup = instance => {
6035 const popup = getPopup();
6036 if (!popup) {
6037 return false;
6038 }
6039 const innerParams = privateProps.innerParams.get(instance);
6040 if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
6041 return false;
6042 }
6043 removeClass(popup, innerParams.showClass.popup);
6044 addClass(popup, innerParams.hideClass.popup);
6045 const backdrop = getContainer();
6046 removeClass(backdrop, innerParams.showClass.backdrop);
6047 addClass(backdrop, innerParams.hideClass.backdrop);
6048 handlePopupAnimation(instance, popup, innerParams);
6049 return true;
6050 };
6051
6052 /**
6053 * @param {Error | string} error
6054 * @this {SweetAlert}
6055 */
6056 function rejectPromise(error) {
6057 const rejectPromise = privateMethods.swalPromiseReject.get(this);
6058 handleAwaitingPromise(this);
6059 if (rejectPromise) {
6060 // Reject Swal promise
6061 rejectPromise(error);
6062 }
6063 }
6064
6065 /**
6066 * @param {SweetAlert} instance
6067 */
6068 const handleAwaitingPromise = instance => {
6069 if (instance.isAwaitingPromise) {
6070 // @ts-ignore
6071 delete instance.isAwaitingPromise;
6072 // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
6073 if (!privateProps.innerParams.get(instance)) {
6074 instance._destroy();
6075 }
6076 }
6077 };
6078
6079 /**
6080 * @param {SweetAlertResult | undefined} resolveValue
6081 * @returns {SweetAlertResult}
6082 */
6083 const prepareResolveValue = resolveValue => {
6084 // When user calls Swal.close()
6085 if (typeof resolveValue === 'undefined') {
6086 return {
6087 isConfirmed: false,
6088 isDenied: false,
6089 isDismissed: true
6090 };
6091 }
6092 return Object.assign({
6093 isConfirmed: false,
6094 isDenied: false,
6095 isDismissed: false
6096 }, resolveValue);
6097 };
6098
6099 /**
6100 * @param {SweetAlert} instance
6101 * @param {HTMLElement} popup
6102 * @param {SweetAlertOptions} innerParams
6103 */
6104 const handlePopupAnimation = (instance, popup, innerParams) => {
6105 var _globalState$eventEmi;
6106 const container = getContainer();
6107 // If animation is supported, animate
6108 const animationIsSupported = hasCssAnimation(popup);
6109 if (typeof innerParams.willClose === 'function') {
6110 innerParams.willClose(popup);
6111 }
6112 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willClose', popup);
6113 if (animationIsSupported && container) {
6114 animatePopup(instance, popup, container, Boolean(innerParams.returnFocus), innerParams.didClose);
6115 } else if (container) {
6116 // Otherwise, remove immediately
6117 removePopupAndResetState(instance, container, Boolean(innerParams.returnFocus), innerParams.didClose);
6118 }
6119 };
6120
6121 /**
6122 * @param {SweetAlert} instance
6123 * @param {HTMLElement} popup
6124 * @param {HTMLElement} container
6125 * @param {boolean} returnFocus
6126 * @param {(() => void) | undefined} didClose
6127 */
6128 const animatePopup = (instance, popup, container, returnFocus, didClose) => {
6129 globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
6130 /**
6131 * @param {AnimationEvent | TransitionEvent} e
6132 */
6133 const swalCloseAnimationFinished = function (e) {
6134 if (e.target === popup) {
6135 var _globalState$swalClos;
6136 (_globalState$swalClos = globalState.swalCloseEventFinishedCallback) === null || _globalState$swalClos === void 0 || _globalState$swalClos.call(globalState);
6137 delete globalState.swalCloseEventFinishedCallback;
6138 popup.removeEventListener('animationend', swalCloseAnimationFinished);
6139 popup.removeEventListener('transitionend', swalCloseAnimationFinished);
6140 }
6141 };
6142 popup.addEventListener('animationend', swalCloseAnimationFinished);
6143 popup.addEventListener('transitionend', swalCloseAnimationFinished);
6144 };
6145
6146 /**
6147 * @param {SweetAlert} instance
6148 * @param {(() => void) | undefined} didClose
6149 */
6150 const triggerDidCloseAndDispose = (instance, didClose) => {
6151 setTimeout(() => {
6152 var _globalState$eventEmi2;
6153 if (typeof didClose === 'function') {
6154 didClose.bind(instance.params)();
6155 }
6156 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didClose');
6157 // instance might have been destroyed already
6158 if (instance._destroy) {
6159 instance._destroy();
6160 }
6161 });
6162 };
6163
6164 /**
6165 * Shows loader (spinner), this is useful with AJAX requests.
6166 * By default the loader be shown instead of the "Confirm" button.
6167 *
6168 * @param {HTMLButtonElement | null} [buttonToReplace]
6169 */
6170 const showLoading = buttonToReplace => {
6171 let popup = getPopup();
6172 if (!popup) {
6173 new Swal();
6174 }
6175 popup = getPopup();
6176 if (!popup) {
6177 return;
6178 }
6179 const loader = getLoader();
6180 if (isToast()) {
6181 hide(getIcon());
6182 } else {
6183 replaceButton(popup, buttonToReplace);
6184 }
6185 show(loader);
6186 popup.setAttribute('data-loading', 'true');
6187 popup.setAttribute('aria-busy', 'true');
6188 popup.focus();
6189 };
6190
6191 /**
6192 * @param {HTMLElement} popup
6193 * @param {HTMLButtonElement | null} [buttonToReplace]
6194 */
6195 const replaceButton = (popup, buttonToReplace) => {
6196 const actions = getActions();
6197 const loader = getLoader();
6198 if (!actions || !loader) {
6199 return;
6200 }
6201 if (!buttonToReplace && isVisible$1(getConfirmButton())) {
6202 buttonToReplace = getConfirmButton();
6203 }
6204 show(actions);
6205 if (buttonToReplace) {
6206 hide(buttonToReplace);
6207 loader.setAttribute('data-button-to-replace', buttonToReplace.className);
6208 actions.insertBefore(loader, buttonToReplace);
6209 }
6210 addClass([popup, actions], swalClasses.loading);
6211 };
6212
6213 /**
6214 * @param {SweetAlert} instance
6215 * @param {SweetAlertOptions} params
6216 */
6217 const handleInputOptionsAndValue = (instance, params) => {
6218 if (params.input === 'select' || params.input === 'radio') {
6219 handleInputOptions(instance, params);
6220 } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
6221 showLoading(getConfirmButton());
6222 handleInputValue(instance, params);
6223 }
6224 };
6225
6226 /**
6227 * @param {SweetAlert} instance
6228 * @param {SweetAlertOptions} innerParams
6229 * @returns {SweetAlertInputValue}
6230 */
6231 const getInputValue = (instance, innerParams) => {
6232 const input = instance.getInput();
6233 if (!input) {
6234 return null;
6235 }
6236 switch (innerParams.input) {
6237 case 'checkbox':
6238 return getCheckboxValue(input);
6239 case 'radio':
6240 return getRadioValue(input);
6241 case 'file':
6242 return getFileValue(input);
6243 default:
6244 return innerParams.inputAutoTrim ? input.value.trim() : input.value;
6245 }
6246 };
6247
6248 /**
6249 * @param {HTMLInputElement} input
6250 * @returns {number}
6251 */
6252 const getCheckboxValue = input => input.checked ? 1 : 0;
6253
6254 /**
6255 * @param {HTMLInputElement} input
6256 * @returns {string | null}
6257 */
6258 const getRadioValue = input => input.checked ? input.value : null;
6259
6260 /**
6261 * @param {HTMLInputElement} input
6262 * @returns {FileList | File | null}
6263 */
6264 const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null;
6265
6266 /**
6267 * @param {SweetAlert} instance
6268 * @param {SweetAlertOptions} params
6269 */
6270 const handleInputOptions = (instance, params) => {
6271 const popup = getPopup();
6272 if (!popup) {
6273 return;
6274 }
6275 /**
6276 * @param {*} inputOptions
6277 */
6278 const processInputOptions = inputOptions => {
6279 if (params.input === 'select') {
6280 populateSelectOptions(popup, formatInputOptions(inputOptions), params);
6281 } else if (params.input === 'radio') {
6282 populateRadioOptions(popup, formatInputOptions(inputOptions), params);
6283 }
6284 };
6285 if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) {
6286 showLoading(getConfirmButton());
6287 asPromise(params.inputOptions).then(inputOptions => {
6288 instance.hideLoading();
6289 processInputOptions(inputOptions);
6290 });
6291 } else if (typeof params.inputOptions === 'object') {
6292 processInputOptions(params.inputOptions);
6293 } else {
6294 error(`Unexpected type of inputOptions! Expected object, Map or Promise, got ${typeof params.inputOptions}`);
6295 }
6296 };
6297
6298 /**
6299 * @param {SweetAlert} instance
6300 * @param {SweetAlertOptions} params
6301 */
6302 const handleInputValue = (instance, params) => {
6303 const input = instance.getInput();
6304 if (!input) {
6305 return;
6306 }
6307 hide(input);
6308 asPromise(params.inputValue).then(inputValue => {
6309 input.value = params.input === 'number' ? `${parseFloat(inputValue) || 0}` : `${inputValue}`;
6310 show(input);
6311 input.focus();
6312 instance.hideLoading();
6313 }).catch(err => {
6314 error(`Error in inputValue promise: ${err}`);
6315 input.value = '';
6316 show(input);
6317 input.focus();
6318 instance.hideLoading();
6319 });
6320 };
6321
6322 /**
6323 * @param {HTMLElement} popup
6324 * @param {InputOptionFlattened[]} inputOptions
6325 * @param {SweetAlertOptions} params
6326 */
6327 function populateSelectOptions(popup, inputOptions, params) {
6328 const select = getDirectChildByClass(popup, swalClasses.select);
6329 if (!select) {
6330 return;
6331 }
6332 /**
6333 * @param {HTMLElement} parent
6334 * @param {string} optionLabel
6335 * @param {string} optionValue
6336 */
6337 const renderOption = (parent, optionLabel, optionValue) => {
6338 const option = document.createElement('option');
6339 option.value = optionValue;
6340 setInnerHtml(option, optionLabel);
6341 option.selected = isSelected(optionValue, params.inputValue);
6342 parent.appendChild(option);
6343 };
6344 inputOptions.forEach(inputOption => {
6345 const optionValue = inputOption[0];
6346 const optionLabel = inputOption[1];
6347 // <optgroup> spec:
6348 // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
6349 // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
6350 // check whether this is a <optgroup>
6351 if (Array.isArray(optionLabel)) {
6352 // if it is an array, then it is an <optgroup>
6353 const optgroup = document.createElement('optgroup');
6354 optgroup.label = optionValue;
6355 optgroup.disabled = false; // not configurable for now
6356 select.appendChild(optgroup);
6357 optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
6358 } else {
6359 // case of <option>
6360 renderOption(select, optionLabel, optionValue);
6361 }
6362 });
6363 select.focus();
6364 }
6365
6366 /**
6367 * @param {HTMLElement} popup
6368 * @param {InputOptionFlattened[]} inputOptions
6369 * @param {SweetAlertOptions} params
6370 */
6371 function populateRadioOptions(popup, inputOptions, params) {
6372 const radio = getDirectChildByClass(popup, swalClasses.radio);
6373 if (!radio) {
6374 return;
6375 }
6376 inputOptions.forEach(inputOption => {
6377 const radioValue = inputOption[0];
6378 const radioLabel = inputOption[1];
6379 const radioInput = document.createElement('input');
6380 const radioLabelElement = document.createElement('label');
6381 radioInput.type = 'radio';
6382 radioInput.name = swalClasses.radio;
6383 radioInput.value = radioValue;
6384 if (isSelected(radioValue, params.inputValue)) {
6385 radioInput.checked = true;
6386 }
6387 const label = document.createElement('span');
6388 setInnerHtml(label, radioLabel);
6389 label.className = swalClasses.label;
6390 radioLabelElement.appendChild(radioInput);
6391 radioLabelElement.appendChild(label);
6392 radio.appendChild(radioLabelElement);
6393 });
6394 const radios = radio.querySelectorAll('input');
6395 if (radios.length) {
6396 radios[0].focus();
6397 }
6398 }
6399
6400 /**
6401 * Converts `inputOptions` into an array of `[value, label]`s
6402 *
6403 * @param {*} inputOptions
6404 * @typedef {string[]} InputOptionFlattened
6405 * @returns {InputOptionFlattened[]}
6406 */
6407 const formatInputOptions = inputOptions => {
6408 /** @type {InputOptionFlattened[]} */
6409 const result = [];
6410 if (inputOptions instanceof Map) {
6411 inputOptions.forEach((value, key) => {
6412 let valueFormatted = value;
6413 if (typeof valueFormatted === 'object') {
6414 // case of <optgroup>
6415 valueFormatted = formatInputOptions(valueFormatted);
6416 }
6417 result.push([key, valueFormatted]);
6418 });
6419 } else {
6420 Object.keys(inputOptions).forEach(key => {
6421 let valueFormatted = inputOptions[key];
6422 if (typeof valueFormatted === 'object') {
6423 // case of <optgroup>
6424 valueFormatted = formatInputOptions(valueFormatted);
6425 }
6426 result.push([key, valueFormatted]);
6427 });
6428 }
6429 return result;
6430 };
6431
6432 /**
6433 * @param {string} optionValue
6434 * @param {SweetAlertInputValue} inputValue
6435 * @returns {boolean}
6436 */
6437 const isSelected = (optionValue, inputValue) => {
6438 return Boolean(inputValue) && inputValue !== null && inputValue !== undefined && inputValue.toString() === optionValue.toString();
6439 };
6440
6441 /**
6442 * @param {SweetAlert} instance
6443 */
6444 const handleConfirmButtonClick = instance => {
6445 const innerParams = privateProps.innerParams.get(instance);
6446 instance.disableButtons();
6447 if (innerParams.input) {
6448 handleConfirmOrDenyWithInput(instance, 'confirm');
6449 } else {
6450 confirm(instance, true);
6451 }
6452 };
6453
6454 /**
6455 * @param {SweetAlert} instance
6456 */
6457 const handleDenyButtonClick = instance => {
6458 const innerParams = privateProps.innerParams.get(instance);
6459 instance.disableButtons();
6460 if (innerParams.returnInputValueOnDeny) {
6461 handleConfirmOrDenyWithInput(instance, 'deny');
6462 } else {
6463 deny(instance, false);
6464 }
6465 };
6466
6467 /**
6468 * @param {SweetAlert} instance
6469 * @param {(dismiss: DismissReason) => void} dismissWith
6470 */
6471 const handleCancelButtonClick = (instance, dismissWith) => {
6472 instance.disableButtons();
6473 dismissWith(DismissReason.cancel);
6474 };
6475
6476 /**
6477 * @param {SweetAlert} instance
6478 * @param {'confirm' | 'deny'} type
6479 */
6480 const handleConfirmOrDenyWithInput = (instance, type) => {
6481 const innerParams = privateProps.innerParams.get(instance);
6482 if (!innerParams.input) {
6483 error(`The "input" parameter is needed to be set when using returnInputValueOn${capitalizeFirstLetter(type)}`);
6484 return;
6485 }
6486 const input = instance.getInput();
6487 const inputValue = getInputValue(instance, innerParams);
6488 if (innerParams.inputValidator) {
6489 handleInputValidator(instance, inputValue, type);
6490 } else if (input && !input.checkValidity()) {
6491 instance.enableButtons();
6492 instance.showValidationMessage(innerParams.validationMessage || input.validationMessage);
6493 } else if (type === 'deny') {
6494 deny(instance, inputValue);
6495 } else {
6496 confirm(instance, inputValue);
6497 }
6498 };
6499
6500 /**
6501 * @param {SweetAlert} instance
6502 * @param {SweetAlertInputValue} inputValue
6503 * @param {'confirm' | 'deny'} type
6504 */
6505 const handleInputValidator = (instance, inputValue, type) => {
6506 const innerParams = privateProps.innerParams.get(instance);
6507 instance.disableInput();
6508 const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
6509 validationPromise.then(validationMessage => {
6510 instance.enableButtons();
6511 instance.enableInput();
6512 if (validationMessage) {
6513 instance.showValidationMessage(validationMessage);
6514 } else if (type === 'deny') {
6515 deny(instance, inputValue);
6516 } else {
6517 confirm(instance, inputValue);
6518 }
6519 });
6520 };
6521
6522 /**
6523 * @param {SweetAlert} instance
6524 * @param {*} value
6525 */
6526 const deny = (instance, value) => {
6527 const innerParams = privateProps.innerParams.get(instance);
6528 if (innerParams.showLoaderOnDeny) {
6529 showLoading(getDenyButton());
6530 }
6531 if (innerParams.preDeny) {
6532 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
6533 const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
6534 preDenyPromise.then(preDenyValue => {
6535 if (preDenyValue === false) {
6536 instance.hideLoading();
6537 handleAwaitingPromise(instance);
6538 } else {
6539 instance.close(/** @type SweetAlertResult */{
6540 isDenied: true,
6541 value: typeof preDenyValue === 'undefined' ? value : preDenyValue
6542 });
6543 }
6544 }).catch(error => rejectWith(instance, error));
6545 } else {
6546 instance.close(/** @type SweetAlertResult */{
6547 isDenied: true,
6548 value
6549 });
6550 }
6551 };
6552
6553 /**
6554 * @param {SweetAlert} instance
6555 * @param {*} value
6556 */
6557 const succeedWith = (instance, value) => {
6558 instance.close(/** @type SweetAlertResult */{
6559 isConfirmed: true,
6560 value
6561 });
6562 };
6563
6564 /**
6565 *
6566 * @param {SweetAlert} instance
6567 * @param {string} error
6568 */
6569 const rejectWith = (instance, error) => {
6570 instance.rejectPromise(error);
6571 };
6572
6573 /**
6574 *
6575 * @param {SweetAlert} instance
6576 * @param {*} value
6577 */
6578 const confirm = (instance, value) => {
6579 const innerParams = privateProps.innerParams.get(instance);
6580 if (innerParams.showLoaderOnConfirm) {
6581 showLoading();
6582 }
6583 if (innerParams.preConfirm) {
6584 instance.resetValidationMessage();
6585 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
6586 const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
6587 preConfirmPromise.then(preConfirmValue => {
6588 if (isVisible$1(getValidationMessage()) || preConfirmValue === false) {
6589 instance.hideLoading();
6590 handleAwaitingPromise(instance);
6591 } else {
6592 succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
6593 }
6594 }).catch(error => rejectWith(instance, error));
6595 } else {
6596 succeedWith(instance, value);
6597 }
6598 };
6599
6600 /**
6601 * Hides loader and shows back the button which was hidden by .showLoading()
6602 * @this {SweetAlert}
6603 */
6604 function hideLoading() {
6605 // do nothing if popup is closed
6606 const innerParams = privateProps.innerParams.get(this);
6607 if (!innerParams) {
6608 return;
6609 }
6610 const domCache = privateProps.domCache.get(this);
6611 hide(domCache.loader);
6612 if (isToast()) {
6613 if (innerParams.icon) {
6614 show(getIcon());
6615 }
6616 } else {
6617 showRelatedButton(domCache);
6618 }
6619 removeClass([domCache.popup, domCache.actions], swalClasses.loading);
6620 domCache.popup.removeAttribute('aria-busy');
6621 domCache.popup.removeAttribute('data-loading');
6622 domCache.confirmButton.disabled = false;
6623 domCache.denyButton.disabled = false;
6624 domCache.cancelButton.disabled = false;
6625 }
6626
6627 /**
6628 * @param {DomCache} domCache
6629 */
6630 const showRelatedButton = domCache => {
6631 const dataButtonToReplace = domCache.loader.getAttribute('data-button-to-replace');
6632 const buttonToReplace = dataButtonToReplace ? domCache.popup.getElementsByClassName(dataButtonToReplace) : [];
6633 if (buttonToReplace.length) {
6634 show(/** @type {HTMLElement} */buttonToReplace[0], 'inline-block');
6635 } else if (allButtonsAreHidden()) {
6636 hide(domCache.actions);
6637 }
6638 };
6639
6640 /**
6641 * Gets the input DOM node, this method works with input parameter.
6642 *
6643 * @returns {HTMLInputElement | null}
6644 * @this {SweetAlert}
6645 */
6646 function getInput() {
6647 const innerParams = privateProps.innerParams.get(this);
6648 const domCache = privateProps.domCache.get(this);
6649 if (!domCache) {
6650 return null;
6651 }
6652 return getInput$1(domCache.popup, innerParams.input);
6653 }
6654
6655 /**
6656 * @param {SweetAlert} instance
6657 * @param {string[]} buttons
6658 * @param {boolean} disabled
6659 */
6660 function setButtonsDisabled(instance, buttons, disabled) {
6661 const domCache = privateProps.domCache.get(instance);
6662 buttons.forEach(button => {
6663 domCache[button].disabled = disabled;
6664 });
6665 }
6666
6667 /**
6668 * @param {HTMLInputElement | null} input
6669 * @param {boolean} disabled
6670 */
6671 function setInputDisabled(input, disabled) {
6672 const popup = getPopup();
6673 if (!popup || !input) {
6674 return;
6675 }
6676 if (input.type === 'radio') {
6677 /** @type {NodeListOf<HTMLInputElement>} */
6678 const radios = popup.querySelectorAll(`[name="${swalClasses.radio}"]`);
6679 for (let i = 0; i < radios.length; i++) {
6680 radios[i].disabled = disabled;
6681 }
6682 } else {
6683 input.disabled = disabled;
6684 }
6685 }
6686
6687 /**
6688 * Enable all the buttons
6689 * @this {SweetAlert}
6690 */
6691 function enableButtons() {
6692 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
6693 }
6694
6695 /**
6696 * Disable all the buttons
6697 * @this {SweetAlert}
6698 */
6699 function disableButtons() {
6700 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
6701 }
6702
6703 /**
6704 * Enable the input field
6705 * @this {SweetAlert}
6706 */
6707 function enableInput() {
6708 setInputDisabled(this.getInput(), false);
6709 }
6710
6711 /**
6712 * Disable the input field
6713 * @this {SweetAlert}
6714 */
6715 function disableInput() {
6716 setInputDisabled(this.getInput(), true);
6717 }
6718
6719 /**
6720 * Show block with validation message
6721 *
6722 * @param {string} error
6723 * @this {SweetAlert}
6724 */
6725 function showValidationMessage(error) {
6726 const domCache = privateProps.domCache.get(this);
6727 const params = privateProps.innerParams.get(this);
6728 setInnerHtml(domCache.validationMessage, error);
6729 domCache.validationMessage.className = swalClasses['validation-message'];
6730 if (params.customClass && params.customClass.validationMessage) {
6731 addClass(domCache.validationMessage, params.customClass.validationMessage);
6732 }
6733 show(domCache.validationMessage);
6734 const input = this.getInput();
6735 if (input) {
6736 input.setAttribute('aria-invalid', 'true');
6737 input.setAttribute('aria-describedby', swalClasses['validation-message']);
6738 focusInput(input);
6739 addClass(input, swalClasses.inputerror);
6740 }
6741 }
6742
6743 /**
6744 * Hide block with validation message
6745 *
6746 * @this {SweetAlert}
6747 */
6748 function resetValidationMessage() {
6749 const domCache = privateProps.domCache.get(this);
6750 if (domCache.validationMessage) {
6751 hide(domCache.validationMessage);
6752 }
6753 const input = this.getInput();
6754 if (input) {
6755 input.removeAttribute('aria-invalid');
6756 input.removeAttribute('aria-describedby');
6757 removeClass(input, swalClasses.inputerror);
6758 }
6759 }
6760
6761 const defaultParams = {
6762 title: '',
6763 titleText: '',
6764 text: '',
6765 html: '',
6766 footer: '',
6767 icon: undefined,
6768 iconColor: undefined,
6769 iconHtml: undefined,
6770 template: undefined,
6771 toast: false,
6772 draggable: false,
6773 animation: true,
6774 theme: 'light',
6775 showClass: {
6776 popup: 'swal2-show',
6777 backdrop: 'swal2-backdrop-show',
6778 icon: 'swal2-icon-show'
6779 },
6780 hideClass: {
6781 popup: 'swal2-hide',
6782 backdrop: 'swal2-backdrop-hide',
6783 icon: 'swal2-icon-hide'
6784 },
6785 customClass: {},
6786 target: 'body',
6787 color: undefined,
6788 backdrop: true,
6789 heightAuto: true,
6790 allowOutsideClick: true,
6791 allowEscapeKey: true,
6792 allowEnterKey: true,
6793 stopKeydownPropagation: true,
6794 keydownListenerCapture: false,
6795 showConfirmButton: true,
6796 showDenyButton: false,
6797 showCancelButton: false,
6798 preConfirm: undefined,
6799 preDeny: undefined,
6800 confirmButtonText: 'OK',
6801 confirmButtonAriaLabel: '',
6802 confirmButtonColor: undefined,
6803 denyButtonText: 'No',
6804 denyButtonAriaLabel: '',
6805 denyButtonColor: undefined,
6806 cancelButtonText: 'Cancel',
6807 cancelButtonAriaLabel: '',
6808 cancelButtonColor: undefined,
6809 buttonsStyling: true,
6810 reverseButtons: false,
6811 focusConfirm: true,
6812 focusDeny: false,
6813 focusCancel: false,
6814 returnFocus: true,
6815 showCloseButton: false,
6816 closeButtonHtml: '&times;',
6817 closeButtonAriaLabel: 'Close this dialog',
6818 loaderHtml: '',
6819 showLoaderOnConfirm: false,
6820 showLoaderOnDeny: false,
6821 imageUrl: undefined,
6822 imageWidth: undefined,
6823 imageHeight: undefined,
6824 imageAlt: '',
6825 timer: undefined,
6826 timerProgressBar: false,
6827 width: undefined,
6828 padding: undefined,
6829 background: undefined,
6830 input: undefined,
6831 inputPlaceholder: '',
6832 inputLabel: '',
6833 inputValue: '',
6834 inputOptions: {},
6835 inputAutoFocus: true,
6836 inputAutoTrim: true,
6837 inputAttributes: {},
6838 inputValidator: undefined,
6839 returnInputValueOnDeny: false,
6840 validationMessage: undefined,
6841 grow: false,
6842 position: 'center',
6843 progressSteps: [],
6844 currentProgressStep: undefined,
6845 progressStepsDistance: undefined,
6846 willOpen: undefined,
6847 didOpen: undefined,
6848 didRender: undefined,
6849 willClose: undefined,
6850 didClose: undefined,
6851 didDestroy: undefined,
6852 scrollbarPadding: true,
6853 topLayer: false
6854 };
6855 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'];
6856
6857 /** @type {Record<string, string | undefined>} */
6858 const deprecatedParams = {
6859 allowEnterKey: undefined
6860 };
6861 const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'draggable', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
6862
6863 /**
6864 * Is valid parameter
6865 *
6866 * @param {string} paramName
6867 * @returns {boolean}
6868 */
6869 const isValidParameter = paramName => {
6870 return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
6871 };
6872
6873 /**
6874 * Is valid parameter for Swal.update() method
6875 *
6876 * @param {string} paramName
6877 * @returns {boolean}
6878 */
6879 const isUpdatableParameter = paramName => {
6880 return updatableParams.indexOf(paramName) !== -1;
6881 };
6882
6883 /**
6884 * Is deprecated parameter
6885 *
6886 * @param {string} paramName
6887 * @returns {string | undefined}
6888 */
6889 const isDeprecatedParameter = paramName => {
6890 return deprecatedParams[paramName];
6891 };
6892
6893 /**
6894 * @param {string} param
6895 */
6896 const checkIfParamIsValid = param => {
6897 if (!isValidParameter(param)) {
6898 warn(`Unknown parameter "${param}"`);
6899 }
6900 };
6901
6902 /**
6903 * @param {string} param
6904 */
6905 const checkIfToastParamIsValid = param => {
6906 if (toastIncompatibleParams.includes(param)) {
6907 warn(`The parameter "${param}" is incompatible with toasts`);
6908 }
6909 };
6910
6911 /**
6912 * @param {string} param
6913 */
6914 const checkIfParamIsDeprecated = param => {
6915 const isDeprecated = isDeprecatedParameter(param);
6916 if (isDeprecated) {
6917 warnAboutDeprecation(param, isDeprecated);
6918 }
6919 };
6920
6921 /**
6922 * Show relevant warnings for given params
6923 *
6924 * @param {SweetAlertOptions} params
6925 */
6926 const showWarningsForParams = params => {
6927 if (params.backdrop === false && params.allowOutsideClick) {
6928 warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
6929 }
6930 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)) {
6931 warn(`Invalid theme "${params.theme}"`);
6932 }
6933 for (const param in params) {
6934 checkIfParamIsValid(param);
6935 if (params.toast) {
6936 checkIfToastParamIsValid(param);
6937 }
6938 checkIfParamIsDeprecated(param);
6939 }
6940 };
6941
6942 /**
6943 * Updates popup parameters.
6944 *
6945 * @this {any}
6946 * @param {SweetAlertOptions} params
6947 */
6948 function update(params) {
6949 const container = getContainer();
6950 const popup = getPopup();
6951 const innerParams = privateProps.innerParams.get(this);
6952 if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
6953 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.`);
6954 return;
6955 }
6956 const validUpdatableParams = filterValidParams(params);
6957 const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
6958 showWarningsForParams(updatedParams);
6959 if (container) {
6960 container.dataset['swal2Theme'] = updatedParams.theme;
6961 }
6962 render(this, updatedParams);
6963 privateProps.innerParams.set(this, updatedParams);
6964 Object.defineProperties(this, {
6965 params: {
6966 value: Object.assign({}, this.params, params),
6967 writable: false,
6968 enumerable: true
6969 }
6970 });
6971 }
6972
6973 /**
6974 * @param {SweetAlertOptions} params
6975 * @returns {SweetAlertOptions}
6976 */
6977 const filterValidParams = params => {
6978 /** @type {Record<string, any>} */
6979 const validUpdatableParams = {};
6980 Object.keys(params).forEach(param => {
6981 if (isUpdatableParameter(param)) {
6982 const typedParams = /** @type {Record<string, any>} */params;
6983 validUpdatableParams[param] = typedParams[param];
6984 } else {
6985 warn(`Invalid parameter to update: ${param}`);
6986 }
6987 });
6988 return validUpdatableParams;
6989 };
6990
6991 /**
6992 * Dispose the current SweetAlert2 instance
6993 * @this {SweetAlert}
6994 */
6995 function _destroy() {
6996 var _globalState$eventEmi;
6997 const domCache = privateProps.domCache.get(this);
6998 const innerParams = privateProps.innerParams.get(this);
6999 if (!innerParams) {
7000 disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
7001 return; // This instance has already been destroyed
7002 }
7003
7004 // Check if there is another Swal closing
7005 if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
7006 globalState.swalCloseEventFinishedCallback();
7007 delete globalState.swalCloseEventFinishedCallback;
7008 }
7009 if (typeof innerParams.didDestroy === 'function') {
7010 innerParams.didDestroy();
7011 }
7012 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didDestroy');
7013 disposeSwal(this);
7014 }
7015
7016 /**
7017 * @param {SweetAlert} instance
7018 */
7019 const disposeSwal = instance => {
7020 disposeWeakMaps(instance);
7021 // Unset this.params so GC will dispose it (#1569)
7022 // @ts-ignore
7023 delete instance.params;
7024 // Unset globalState props so GC will dispose globalState (#1569)
7025 delete globalState.keydownHandler;
7026 delete globalState.keydownTarget;
7027 // Unset currentInstance
7028 delete globalState.currentInstance;
7029 };
7030
7031 /**
7032 * @param {SweetAlert} instance
7033 */
7034 const disposeWeakMaps = instance => {
7035 // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
7036 if (instance.isAwaitingPromise) {
7037 unsetWeakMaps(privateProps, instance);
7038 instance.isAwaitingPromise = true;
7039 } else {
7040 unsetWeakMaps(privateMethods, instance);
7041 unsetWeakMaps(privateProps, instance);
7042
7043 // @ts-ignore
7044 delete instance.isAwaitingPromise;
7045 // Unset instance methods
7046 // @ts-ignore
7047 delete instance.disableButtons;
7048 // @ts-ignore
7049 delete instance.enableButtons;
7050 // @ts-ignore
7051 delete instance.getInput;
7052 // @ts-ignore
7053 delete instance.disableInput;
7054 // @ts-ignore
7055 delete instance.enableInput;
7056 // @ts-ignore
7057 delete instance.hideLoading;
7058 // @ts-ignore
7059 delete instance.disableLoading;
7060 // @ts-ignore
7061 delete instance.showValidationMessage;
7062 // @ts-ignore
7063 delete instance.resetValidationMessage;
7064 // @ts-ignore
7065 delete instance.close;
7066 // @ts-ignore
7067 delete instance.closePopup;
7068 // @ts-ignore
7069 delete instance.closeModal;
7070 // @ts-ignore
7071 delete instance.closeToast;
7072 // @ts-ignore
7073 delete instance.rejectPromise;
7074 // @ts-ignore
7075 delete instance.update;
7076 // @ts-ignore
7077 delete instance._destroy;
7078 }
7079 };
7080
7081 /**
7082 * @param {Record<string, WeakMap<any, any>>} obj
7083 * @param {SweetAlert} instance
7084 */
7085 const unsetWeakMaps = (obj, instance) => {
7086 for (const i in obj) {
7087 obj[i].delete(instance);
7088 }
7089 };
7090
7091 var instanceMethods = /*#__PURE__*/Object.freeze({
7092 __proto__: null,
7093 _destroy: _destroy,
7094 close: close,
7095 closeModal: close,
7096 closePopup: close,
7097 closeToast: close,
7098 disableButtons: disableButtons,
7099 disableInput: disableInput,
7100 disableLoading: hideLoading,
7101 enableButtons: enableButtons,
7102 enableInput: enableInput,
7103 getInput: getInput,
7104 handleAwaitingPromise: handleAwaitingPromise,
7105 hideLoading: hideLoading,
7106 rejectPromise: rejectPromise,
7107 resetValidationMessage: resetValidationMessage,
7108 showValidationMessage: showValidationMessage,
7109 update: update
7110 });
7111
7112 /**
7113 * @param {SweetAlertOptions} innerParams
7114 * @param {DomCache} domCache
7115 * @param {(dismiss: DismissReason) => void} dismissWith
7116 */
7117 const handlePopupClick = (innerParams, domCache, dismissWith) => {
7118 if (innerParams.toast) {
7119 handleToastClick(innerParams, domCache, dismissWith);
7120 } else {
7121 // Ignore click events that had mousedown on the popup but mouseup on the container
7122 // This can happen when the user drags a slider
7123 handleModalMousedown(domCache);
7124
7125 // Ignore click events that had mousedown on the container but mouseup on the popup
7126 handleContainerMousedown(domCache);
7127 handleModalClick(innerParams, domCache, dismissWith);
7128 }
7129 };
7130
7131 /**
7132 * @param {SweetAlertOptions} innerParams
7133 * @param {DomCache} domCache
7134 * @param {(dismiss: DismissReason) => void} dismissWith
7135 */
7136 const handleToastClick = (innerParams, domCache, dismissWith) => {
7137 // Closing toast by internal click
7138 domCache.popup.onclick = () => {
7139 if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
7140 return;
7141 }
7142 dismissWith(DismissReason.close);
7143 };
7144 };
7145
7146 /**
7147 * @param {SweetAlertOptions} innerParams
7148 * @returns {boolean}
7149 */
7150 const isAnyButtonShown = innerParams => {
7151 return Boolean(innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton);
7152 };
7153 let ignoreOutsideClick = false;
7154
7155 /**
7156 * @param {DomCache} domCache
7157 */
7158 const handleModalMousedown = domCache => {
7159 domCache.popup.onmousedown = () => {
7160 domCache.container.onmouseup = function (e) {
7161 domCache.container.onmouseup = () => {};
7162 // We only check if the mouseup target is the container because usually it doesn't
7163 // have any other direct children aside of the popup
7164 if (e.target === domCache.container) {
7165 ignoreOutsideClick = true;
7166 }
7167 };
7168 };
7169 };
7170
7171 /**
7172 * @param {DomCache} domCache
7173 */
7174 const handleContainerMousedown = domCache => {
7175 domCache.container.onmousedown = e => {
7176 // prevent the modal text from being selected on double click on the container (allowOutsideClick: false)
7177 if (e.target === domCache.container) {
7178 e.preventDefault();
7179 }
7180 domCache.popup.onmouseup = function (e) {
7181 domCache.popup.onmouseup = () => {};
7182 // We also need to check if the mouseup target is a child of the popup
7183 if (e.target === domCache.popup || e.target instanceof HTMLElement && domCache.popup.contains(e.target)) {
7184 ignoreOutsideClick = true;
7185 }
7186 };
7187 };
7188 };
7189
7190 /**
7191 * @param {SweetAlertOptions} innerParams
7192 * @param {DomCache} domCache
7193 * @param {(dismiss: DismissReason) => void} dismissWith
7194 */
7195 const handleModalClick = (innerParams, domCache, dismissWith) => {
7196 domCache.container.onclick = e => {
7197 if (ignoreOutsideClick) {
7198 ignoreOutsideClick = false;
7199 return;
7200 }
7201 if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
7202 dismissWith(DismissReason.backdrop);
7203 }
7204 };
7205 };
7206
7207 /**
7208 * @param {any} elem
7209 * @returns {boolean}
7210 */
7211 const isJqueryElement = elem => typeof elem === 'object' && elem.jquery;
7212
7213 /**
7214 * @param {any} elem
7215 * @returns {boolean}
7216 */
7217 const isElement = elem => elem instanceof Element || isJqueryElement(elem);
7218
7219 /**
7220 * @param {any[]} args
7221 * @returns {SweetAlertOptions}
7222 */
7223 const argsToParams = args => {
7224 /** @type {Record<string, any>} */
7225 const params = {};
7226 if (typeof args[0] === 'object' && !isElement(args[0])) {
7227 Object.assign(params, args[0]);
7228 } else {
7229 ['title', 'html', 'icon'].forEach((name, index) => {
7230 const arg = args[index];
7231 if (typeof arg === 'string' || isElement(arg)) {
7232 params[name] = arg;
7233 } else if (arg !== undefined) {
7234 error(`Unexpected type of ${name}! Expected "string" or "Element", got ${typeof arg}`);
7235 }
7236 });
7237 }
7238 return params;
7239 };
7240
7241 /**
7242 * Main method to create a new SweetAlert2 popup
7243 *
7244 * @this {new (...args: any[]) => any}
7245 * @param {...SweetAlertOptions} args
7246 * @returns {Promise<SweetAlertResult>}
7247 */
7248 function fire(...args) {
7249 return new this(...args);
7250 }
7251
7252 /**
7253 * Returns an extended version of `Swal` containing `params` as defaults.
7254 * Useful for reusing Swal configuration.
7255 *
7256 * For example:
7257 *
7258 * Before:
7259 * const textPromptOptions = { input: 'text', showCancelButton: true }
7260 * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
7261 * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
7262 *
7263 * After:
7264 * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
7265 * const {value: firstName} = await TextPrompt('What is your first name?')
7266 * const {value: lastName} = await TextPrompt('What is your last name?')
7267 *
7268 * @param {SweetAlertOptions} mixinParams
7269 * @returns {SweetAlert}
7270 * @this {typeof import('../SweetAlert.js').SweetAlert}
7271 */
7272 function mixin(mixinParams) {
7273 // @ts-ignore: 'this' refers to the SweetAlert constructor
7274 class MixinSwal extends this {
7275 /**
7276 * @param {any} params
7277 * @param {any} priorityMixinParams
7278 */
7279 _main(params, priorityMixinParams) {
7280 return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
7281 }
7282 }
7283 // @ts-ignore
7284 return MixinSwal;
7285 }
7286
7287 /**
7288 * If `timer` parameter is set, returns number of milliseconds of timer remained.
7289 * Otherwise, returns undefined.
7290 *
7291 * @returns {number | undefined}
7292 */
7293 const getTimerLeft = () => {
7294 return globalState.timeout && globalState.timeout.getTimerLeft();
7295 };
7296
7297 /**
7298 * Stop timer. Returns number of milliseconds of timer remained.
7299 * If `timer` parameter isn't set, returns undefined.
7300 *
7301 * @returns {number | undefined}
7302 */
7303 const stopTimer = () => {
7304 if (globalState.timeout) {
7305 stopTimerProgressBar();
7306 return globalState.timeout.stop();
7307 }
7308 };
7309
7310 /**
7311 * Resume timer. Returns number of milliseconds of timer remained.
7312 * If `timer` parameter isn't set, returns undefined.
7313 *
7314 * @returns {number | undefined}
7315 */
7316 const resumeTimer = () => {
7317 if (globalState.timeout) {
7318 const remaining = globalState.timeout.start();
7319 animateTimerProgressBar(remaining);
7320 return remaining;
7321 }
7322 };
7323
7324 /**
7325 * Resume timer. Returns number of milliseconds of timer remained.
7326 * If `timer` parameter isn't set, returns undefined.
7327 *
7328 * @returns {number | undefined}
7329 */
7330 const toggleTimer = () => {
7331 const timer = globalState.timeout;
7332 return timer && (timer.running ? stopTimer() : resumeTimer());
7333 };
7334
7335 /**
7336 * Increase timer. Returns number of milliseconds of an updated timer.
7337 * If `timer` parameter isn't set, returns undefined.
7338 *
7339 * @param {number} ms
7340 * @returns {number | undefined}
7341 */
7342 const increaseTimer = ms => {
7343 if (globalState.timeout) {
7344 const remaining = globalState.timeout.increase(ms);
7345 animateTimerProgressBar(remaining, true);
7346 return remaining;
7347 }
7348 };
7349
7350 /**
7351 * Check if timer is running. Returns true if timer is running
7352 * or false if timer is paused or stopped.
7353 * If `timer` parameter isn't set, returns undefined
7354 *
7355 * @returns {boolean}
7356 */
7357 const isTimerRunning = () => {
7358 return Boolean(globalState.timeout && globalState.timeout.isRunning());
7359 };
7360
7361 let bodyClickListenerAdded = false;
7362 /** @type {Record<string, any>} */
7363 const clickHandlers = {};
7364
7365 /**
7366 * @this {any}
7367 * @param {string} attr
7368 */
7369 function bindClickHandler(attr = 'data-swal-template') {
7370 clickHandlers[attr] = this;
7371 if (!bodyClickListenerAdded) {
7372 document.body.addEventListener('click', bodyClickListener);
7373 bodyClickListenerAdded = true;
7374 }
7375 }
7376
7377 /**
7378 * @param {MouseEvent} event
7379 */
7380 const bodyClickListener = event => {
7381 for (let el = /** @type {any} */event.target; el && el !== document; el = el.parentNode) {
7382 for (const attr in clickHandlers) {
7383 const template = el.getAttribute && el.getAttribute(attr);
7384 if (template) {
7385 clickHandlers[attr].fire({
7386 template
7387 });
7388 return;
7389 }
7390 }
7391 }
7392 };
7393
7394 // Source: https://gist.github.com/mudge/5830382?permalink_comment_id=2691957#gistcomment-2691957
7395
7396 class EventEmitter {
7397 constructor() {
7398 /** @type {Events} */
7399 this.events = {};
7400 }
7401
7402 /**
7403 * @param {string} eventName
7404 * @returns {EventHandlers}
7405 */
7406 _getHandlersByEventName(eventName) {
7407 if (typeof this.events[eventName] === 'undefined') {
7408 // not Set because we need to keep the FIFO order
7409 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1748990334
7410 this.events[eventName] = [];
7411 }
7412 return this.events[eventName];
7413 }
7414
7415 /**
7416 * @param {string} eventName
7417 * @param {EventHandler} eventHandler
7418 */
7419 on(eventName, eventHandler) {
7420 const currentHandlers = this._getHandlersByEventName(eventName);
7421 if (!currentHandlers.includes(eventHandler)) {
7422 currentHandlers.push(eventHandler);
7423 }
7424 }
7425
7426 /**
7427 * @param {string} eventName
7428 * @param {EventHandler} eventHandler
7429 */
7430 once(eventName, eventHandler) {
7431 /**
7432 * @param {...any} args
7433 */
7434 const onceFn = (...args) => {
7435 this.removeListener(eventName, onceFn);
7436 // @ts-ignore
7437 eventHandler.apply(this, args);
7438 };
7439 this.on(eventName, onceFn);
7440 }
7441
7442 /**
7443 * @param {string} eventName
7444 * @param {...any} args
7445 */
7446 emit(eventName, ...args) {
7447 this._getHandlersByEventName(eventName).forEach(
7448 /**
7449 * @param {EventHandler} eventHandler
7450 */
7451 eventHandler => {
7452 try {
7453 // @ts-ignore
7454 eventHandler.apply(this, args);
7455 } catch (error) {
7456 console.error(error);
7457 }
7458 });
7459 }
7460
7461 /**
7462 * @param {string} eventName
7463 * @param {EventHandler} eventHandler
7464 */
7465 removeListener(eventName, eventHandler) {
7466 const currentHandlers = this._getHandlersByEventName(eventName);
7467 const index = currentHandlers.indexOf(eventHandler);
7468 if (index > -1) {
7469 currentHandlers.splice(index, 1);
7470 }
7471 }
7472
7473 /**
7474 * @param {string} eventName
7475 */
7476 removeAllListeners(eventName) {
7477 if (this.events[eventName] !== undefined) {
7478 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1749239222
7479 this.events[eventName].length = 0;
7480 }
7481 }
7482 reset() {
7483 this.events = {};
7484 }
7485 }
7486
7487 globalState.eventEmitter = new EventEmitter();
7488
7489 /**
7490 * @param {string} eventName
7491 * @param {EventHandler} eventHandler
7492 */
7493 const on = (eventName, eventHandler) => {
7494 if (globalState.eventEmitter) {
7495 globalState.eventEmitter.on(eventName, eventHandler);
7496 }
7497 };
7498
7499 /**
7500 * @param {string} eventName
7501 * @param {EventHandler} eventHandler
7502 */
7503 const once = (eventName, eventHandler) => {
7504 if (globalState.eventEmitter) {
7505 globalState.eventEmitter.once(eventName, eventHandler);
7506 }
7507 };
7508
7509 /**
7510 * @param {string} [eventName]
7511 * @param {EventHandler} [eventHandler]
7512 */
7513 const off = (eventName, eventHandler) => {
7514 if (!globalState.eventEmitter) {
7515 return;
7516 }
7517
7518 // Remove all handlers for all events
7519 if (!eventName) {
7520 globalState.eventEmitter.reset();
7521 return;
7522 }
7523 if (eventHandler) {
7524 // Remove a specific handler
7525 globalState.eventEmitter.removeListener(eventName, eventHandler);
7526 } else {
7527 // Remove all handlers for a specific event
7528 globalState.eventEmitter.removeAllListeners(eventName);
7529 }
7530 };
7531
7532 var staticMethods = /*#__PURE__*/Object.freeze({
7533 __proto__: null,
7534 argsToParams: argsToParams,
7535 bindClickHandler: bindClickHandler,
7536 clickCancel: clickCancel,
7537 clickConfirm: clickConfirm,
7538 clickDeny: clickDeny,
7539 enableLoading: showLoading,
7540 fire: fire,
7541 getActions: getActions,
7542 getCancelButton: getCancelButton,
7543 getCloseButton: getCloseButton,
7544 getConfirmButton: getConfirmButton,
7545 getContainer: getContainer,
7546 getDenyButton: getDenyButton,
7547 getFocusableElements: getFocusableElements,
7548 getFooter: getFooter,
7549 getHtmlContainer: getHtmlContainer,
7550 getIcon: getIcon,
7551 getIconContent: getIconContent,
7552 getImage: getImage,
7553 getInputLabel: getInputLabel,
7554 getLoader: getLoader,
7555 getPopup: getPopup,
7556 getProgressSteps: getProgressSteps,
7557 getTimerLeft: getTimerLeft,
7558 getTimerProgressBar: getTimerProgressBar,
7559 getTitle: getTitle,
7560 getValidationMessage: getValidationMessage,
7561 increaseTimer: increaseTimer,
7562 isDeprecatedParameter: isDeprecatedParameter,
7563 isLoading: isLoading,
7564 isTimerRunning: isTimerRunning,
7565 isUpdatableParameter: isUpdatableParameter,
7566 isValidParameter: isValidParameter,
7567 isVisible: isVisible,
7568 mixin: mixin,
7569 off: off,
7570 on: on,
7571 once: once,
7572 resumeTimer: resumeTimer,
7573 showLoading: showLoading,
7574 stopTimer: stopTimer,
7575 toggleTimer: toggleTimer
7576 });
7577
7578 class Timer {
7579 /**
7580 * @param {() => void} callback
7581 * @param {number} delay
7582 */
7583 constructor(callback, delay) {
7584 this.callback = callback;
7585 this.remaining = delay;
7586 this.running = false;
7587 this.start();
7588 }
7589
7590 /**
7591 * @returns {number}
7592 */
7593 start() {
7594 if (!this.running) {
7595 this.running = true;
7596 this.started = new Date();
7597 this.id = setTimeout(this.callback, this.remaining);
7598 }
7599 return this.remaining;
7600 }
7601
7602 /**
7603 * @returns {number}
7604 */
7605 stop() {
7606 if (this.started && this.running) {
7607 this.running = false;
7608 clearTimeout(this.id);
7609 this.remaining -= new Date().getTime() - this.started.getTime();
7610 }
7611 return this.remaining;
7612 }
7613
7614 /**
7615 * @param {number} n
7616 * @returns {number}
7617 */
7618 increase(n) {
7619 const running = this.running;
7620 if (running) {
7621 this.stop();
7622 }
7623 this.remaining += n;
7624 if (running) {
7625 this.start();
7626 }
7627 return this.remaining;
7628 }
7629
7630 /**
7631 * @returns {number}
7632 */
7633 getTimerLeft() {
7634 if (this.running) {
7635 this.stop();
7636 this.start();
7637 }
7638 return this.remaining;
7639 }
7640
7641 /**
7642 * @returns {boolean}
7643 */
7644 isRunning() {
7645 return this.running;
7646 }
7647 }
7648
7649 const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
7650
7651 /**
7652 * @param {SweetAlertOptions} params
7653 * @returns {SweetAlertOptions}
7654 */
7655 const getTemplateParams = params => {
7656 const template = typeof params.template === 'string' ? (/** @type {HTMLTemplateElement} */document.querySelector(params.template)) : params.template;
7657 if (!template) {
7658 return {};
7659 }
7660 /** @type {DocumentFragment} */
7661 const templateContent = template.content;
7662 showWarningsForElements(templateContent);
7663 const result = Object.assign(getSwalParams(templateContent), getSwalFunctionParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
7664 return result;
7665 };
7666
7667 /**
7668 * @param {DocumentFragment} templateContent
7669 * @returns {Record<string, string | boolean | number>}
7670 */
7671 const getSwalParams = templateContent => {
7672 /** @type {Record<string, string | boolean | number>} */
7673 const result = {};
7674 /** @type {HTMLElement[]} */
7675 const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
7676 swalParams.forEach(param => {
7677 showWarningsForAttributes(param, ['name', 'value']);
7678 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7679 const value = param.getAttribute('value');
7680 if (!paramName || !value) {
7681 return;
7682 }
7683 if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'boolean') {
7684 result[paramName] = value !== 'false';
7685 } else if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'object') {
7686 result[paramName] = JSON.parse(value);
7687 } else {
7688 result[paramName] = value;
7689 }
7690 });
7691 return result;
7692 };
7693
7694 /**
7695 * @param {DocumentFragment} templateContent
7696 * @returns {Record<string, () => void>}
7697 */
7698 const getSwalFunctionParams = templateContent => {
7699 /** @type {Record<string, () => void>} */
7700 const result = {};
7701 /** @type {HTMLElement[]} */
7702 const swalFunctions = Array.from(templateContent.querySelectorAll('swal-function-param'));
7703 swalFunctions.forEach(param => {
7704 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7705 const value = param.getAttribute('value');
7706 if (!paramName || !value) {
7707 return;
7708 }
7709 result[paramName] = new Function(`return ${value}`)();
7710 });
7711 return result;
7712 };
7713
7714 /**
7715 * @param {DocumentFragment} templateContent
7716 * @returns {Record<string, string | boolean>}
7717 */
7718 const getSwalButtons = templateContent => {
7719 /** @type {Record<string, string | boolean>} */
7720 const result = {};
7721 /** @type {HTMLElement[]} */
7722 const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
7723 swalButtons.forEach(button => {
7724 showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
7725 const type = button.getAttribute('type');
7726 if (!type || !['confirm', 'cancel', 'deny'].includes(type)) {
7727 return;
7728 }
7729 result[`${type}ButtonText`] = button.innerHTML;
7730 result[`show${capitalizeFirstLetter(type)}Button`] = true;
7731 if (button.hasAttribute('color')) {
7732 const color = button.getAttribute('color');
7733 if (color !== null) {
7734 result[`${type}ButtonColor`] = color;
7735 }
7736 }
7737 if (button.hasAttribute('aria-label')) {
7738 const ariaLabel = button.getAttribute('aria-label');
7739 if (ariaLabel !== null) {
7740 result[`${type}ButtonAriaLabel`] = ariaLabel;
7741 }
7742 }
7743 });
7744 return result;
7745 };
7746
7747 /**
7748 * @param {DocumentFragment} templateContent
7749 * @returns {Pick<SweetAlertOptions, 'imageUrl' | 'imageWidth' | 'imageHeight' | 'imageAlt'>}
7750 */
7751 const getSwalImage = templateContent => {
7752 const result = {};
7753 /** @type {HTMLElement | null} */
7754 const image = templateContent.querySelector('swal-image');
7755 if (image) {
7756 showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
7757 if (image.hasAttribute('src')) {
7758 result.imageUrl = image.getAttribute('src') || undefined;
7759 }
7760 if (image.hasAttribute('width')) {
7761 result.imageWidth = image.getAttribute('width') || undefined;
7762 }
7763 if (image.hasAttribute('height')) {
7764 result.imageHeight = image.getAttribute('height') || undefined;
7765 }
7766 if (image.hasAttribute('alt')) {
7767 result.imageAlt = image.getAttribute('alt') || undefined;
7768 }
7769 }
7770 return result;
7771 };
7772
7773 /**
7774 * @param {DocumentFragment} templateContent
7775 * @returns {object}
7776 */
7777 const getSwalIcon = templateContent => {
7778 const result = {};
7779 /** @type {HTMLElement | null} */
7780 const icon = templateContent.querySelector('swal-icon');
7781 if (icon) {
7782 showWarningsForAttributes(icon, ['type', 'color']);
7783 if (icon.hasAttribute('type')) {
7784 result.icon = icon.getAttribute('type');
7785 }
7786 if (icon.hasAttribute('color')) {
7787 result.iconColor = icon.getAttribute('color');
7788 }
7789 result.iconHtml = icon.innerHTML;
7790 }
7791 return result;
7792 };
7793
7794 /**
7795 * @param {DocumentFragment} templateContent
7796 * @returns {object}
7797 */
7798 const getSwalInput = templateContent => {
7799 /** @type {Record<string, any>} */
7800 const result = {};
7801 /** @type {HTMLElement | null} */
7802 const input = templateContent.querySelector('swal-input');
7803 if (input) {
7804 showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
7805 result.input = input.getAttribute('type') || 'text';
7806 if (input.hasAttribute('label')) {
7807 result.inputLabel = input.getAttribute('label');
7808 }
7809 if (input.hasAttribute('placeholder')) {
7810 result.inputPlaceholder = input.getAttribute('placeholder');
7811 }
7812 if (input.hasAttribute('value')) {
7813 result.inputValue = input.getAttribute('value');
7814 }
7815 }
7816 /** @type {HTMLElement[]} */
7817 const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
7818 if (inputOptions.length) {
7819 result.inputOptions = {};
7820 inputOptions.forEach(option => {
7821 showWarningsForAttributes(option, ['value']);
7822 const optionValue = option.getAttribute('value');
7823 if (!optionValue) {
7824 return;
7825 }
7826 const optionName = option.innerHTML;
7827 result.inputOptions[optionValue] = optionName;
7828 });
7829 }
7830 return result;
7831 };
7832
7833 /**
7834 * @param {DocumentFragment} templateContent
7835 * @param {string[]} paramNames
7836 * @returns {Record<string, string>}
7837 */
7838 const getSwalStringParams = (templateContent, paramNames) => {
7839 /** @type {Record<string, string>} */
7840 const result = {};
7841 for (const i in paramNames) {
7842 const paramName = paramNames[i];
7843 /** @type {HTMLElement | null} */
7844 const tag = templateContent.querySelector(paramName);
7845 if (tag) {
7846 showWarningsForAttributes(tag, []);
7847 result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
7848 }
7849 }
7850 return result;
7851 };
7852
7853 /**
7854 * @param {DocumentFragment} templateContent
7855 */
7856 const showWarningsForElements = templateContent => {
7857 const allowedElements = swalStringParams.concat(['swal-param', 'swal-function-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
7858 Array.from(templateContent.children).forEach(el => {
7859 const tagName = el.tagName.toLowerCase();
7860 if (!allowedElements.includes(tagName)) {
7861 warn(`Unrecognized element <${tagName}>`);
7862 }
7863 });
7864 };
7865
7866 /**
7867 * @param {HTMLElement} el
7868 * @param {string[]} allowedAttributes
7869 */
7870 const showWarningsForAttributes = (el, allowedAttributes) => {
7871 Array.from(el.attributes).forEach(attribute => {
7872 if (allowedAttributes.indexOf(attribute.name) === -1) {
7873 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.'}`]);
7874 }
7875 });
7876 };
7877
7878 const SHOW_CLASS_TIMEOUT = 10;
7879
7880 /**
7881 * Open popup, add necessary classes and styles, fix scrollbar
7882 *
7883 * @param {SweetAlertOptions} params
7884 */
7885 const openPopup = params => {
7886 var _globalState$eventEmi, _globalState$eventEmi2;
7887 const container = getContainer();
7888 const popup = getPopup();
7889 if (!container || !popup) {
7890 return;
7891 }
7892 if (typeof params.willOpen === 'function') {
7893 params.willOpen(popup);
7894 }
7895 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willOpen', popup);
7896 const bodyStyles = window.getComputedStyle(document.body);
7897 const initialBodyOverflow = bodyStyles.overflowY;
7898 addClasses(container, popup, params);
7899
7900 // scrolling is 'hidden' until animation is done, after that 'auto'
7901 setTimeout(() => {
7902 setScrollingVisibility(container, popup);
7903 }, SHOW_CLASS_TIMEOUT);
7904 if (isModal()) {
7905 // Using ternary instead of ?? operator for Webpack 4 compatibility
7906 fixScrollContainer(container, params.scrollbarPadding !== undefined ? params.scrollbarPadding : false, initialBodyOverflow);
7907 setAriaHidden();
7908 }
7909 if (!isToast() && !globalState.previousActiveElement) {
7910 globalState.previousActiveElement = document.activeElement;
7911 }
7912 if (typeof params.didOpen === 'function') {
7913 const didOpen = params.didOpen;
7914 setTimeout(() => didOpen(popup));
7915 }
7916 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didOpen', popup);
7917 };
7918
7919 /**
7920 * @param {Event} event
7921 */
7922 const swalOpenAnimationFinished = event => {
7923 const popup = getPopup();
7924 if (!popup || event.target !== popup) {
7925 return;
7926 }
7927 const container = getContainer();
7928 if (!container) {
7929 return;
7930 }
7931 popup.removeEventListener('animationend', swalOpenAnimationFinished);
7932 popup.removeEventListener('transitionend', swalOpenAnimationFinished);
7933 container.style.overflowY = 'auto';
7934
7935 // no-transition is added in init() in case one swal is opened right after another
7936 removeClass(container, swalClasses['no-transition']);
7937 };
7938
7939 /**
7940 * @param {HTMLElement} container
7941 * @param {HTMLElement} popup
7942 */
7943 const setScrollingVisibility = (container, popup) => {
7944 if (hasCssAnimation(popup)) {
7945 container.style.overflowY = 'hidden';
7946 popup.addEventListener('animationend', swalOpenAnimationFinished);
7947 popup.addEventListener('transitionend', swalOpenAnimationFinished);
7948 } else {
7949 container.style.overflowY = 'auto';
7950 }
7951 };
7952
7953 /**
7954 * @param {HTMLElement} container
7955 * @param {boolean} scrollbarPadding
7956 * @param {string} initialBodyOverflow
7957 */
7958 const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
7959 iOSfix();
7960 if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
7961 replaceScrollbarWithPadding(initialBodyOverflow);
7962 }
7963
7964 // sweetalert2/issues/1247
7965 setTimeout(() => {
7966 container.scrollTop = 0;
7967 });
7968 };
7969
7970 /**
7971 * @param {HTMLElement} container
7972 * @param {HTMLElement} popup
7973 * @param {SweetAlertOptions} params
7974 */
7975 const addClasses = (container, popup, params) => {
7976 var _params$showClass;
7977 if ((_params$showClass = params.showClass) !== null && _params$showClass !== void 0 && _params$showClass.backdrop) {
7978 addClass(container, params.showClass.backdrop);
7979 }
7980 if (params.animation) {
7981 // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
7982 popup.style.setProperty('opacity', '0', 'important');
7983 show(popup, 'grid');
7984 setTimeout(() => {
7985 var _params$showClass2;
7986 // Animate popup right after showing it
7987 if ((_params$showClass2 = params.showClass) !== null && _params$showClass2 !== void 0 && _params$showClass2.popup) {
7988 addClass(popup, params.showClass.popup);
7989 }
7990 // and remove the opacity workaround
7991 popup.style.removeProperty('opacity');
7992 }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
7993 } else {
7994 show(popup, 'grid');
7995 }
7996 addClass([document.documentElement, document.body], swalClasses.shown);
7997 if (params.heightAuto && params.backdrop && !params.toast) {
7998 addClass([document.documentElement, document.body], swalClasses['height-auto']);
7999 }
8000 };
8001
8002 var defaultInputValidators = {
8003 /**
8004 * @param {string} string
8005 * @param {string} [validationMessage]
8006 * @returns {Promise<string | void>}
8007 */
8008 email: (string, validationMessage) => {
8009 return /^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
8010 },
8011 /**
8012 * @param {string} string
8013 * @param {string} [validationMessage]
8014 * @returns {Promise<string | void>}
8015 */
8016 url: (string, validationMessage) => {
8017 // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
8018 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');
8019 }
8020 };
8021
8022 /**
8023 * @param {SweetAlertOptions} params
8024 */
8025 function setDefaultInputValidators(params) {
8026 // Use default `inputValidator` for supported input types if not provided
8027 if (params.inputValidator) {
8028 return;
8029 }
8030 if (params.input === 'email') {
8031 params.inputValidator = defaultInputValidators['email'];
8032 }
8033 if (params.input === 'url') {
8034 params.inputValidator = defaultInputValidators['url'];
8035 }
8036 }
8037
8038 /**
8039 * @param {SweetAlertOptions} params
8040 */
8041 function validateCustomTargetElement(params) {
8042 // Determine if the custom target element is valid
8043 if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
8044 warn('Target parameter is not valid, defaulting to "body"');
8045 params.target = 'body';
8046 }
8047 }
8048
8049 /**
8050 * Set type, text and actions on popup
8051 *
8052 * @param {SweetAlertOptions} params
8053 */
8054 function setParameters(params) {
8055 setDefaultInputValidators(params);
8056
8057 // showLoaderOnConfirm && preConfirm
8058 if (params.showLoaderOnConfirm && !params.preConfirm) {
8059 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');
8060 }
8061 validateCustomTargetElement(params);
8062
8063 // Replace newlines with <br> in title
8064 if (typeof params.title === 'string') {
8065 params.title = params.title.split('\n').join('<br />');
8066 }
8067 init(params);
8068 }
8069
8070 /** @type {SweetAlert} */
8071 let currentInstance;
8072 var _promise = /*#__PURE__*/new WeakMap();
8073 class SweetAlert {
8074 /**
8075 * @param {...(SweetAlertOptions | string)} args
8076 * @this {SweetAlert}
8077 */
8078 constructor(...args) {
8079 /**
8080 * @type {Promise<SweetAlertResult>}
8081 */
8082 _classPrivateFieldInitSpec(this, _promise, /** @type {Promise<SweetAlertResult>} */Promise.resolve({
8083 isConfirmed: false,
8084 isDenied: false,
8085 isDismissed: true
8086 }));
8087 // Prevent run in Node env
8088 if (typeof window === 'undefined') {
8089 return;
8090 }
8091 currentInstance = this;
8092
8093 // @ts-ignore
8094 const outerParams = Object.freeze(this.constructor.argsToParams(args));
8095
8096 /** @type {Readonly<SweetAlertOptions>} */
8097 this.params = outerParams;
8098
8099 /** @type {boolean} */
8100 this.isAwaitingPromise = false;
8101 _classPrivateFieldSet2(_promise, this, this._main(currentInstance.params));
8102 }
8103
8104 /**
8105 * @param {any} userParams
8106 * @param {any} mixinParams
8107 */
8108 _main(userParams, mixinParams = {}) {
8109 showWarningsForParams(Object.assign({}, mixinParams, userParams));
8110 if (globalState.currentInstance) {
8111 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance);
8112 const {
8113 isAwaitingPromise
8114 } = globalState.currentInstance;
8115 globalState.currentInstance._destroy();
8116 if (!isAwaitingPromise) {
8117 swalPromiseResolve({
8118 isDismissed: true
8119 });
8120 }
8121 if (isModal()) {
8122 unsetAriaHidden();
8123 }
8124 }
8125 globalState.currentInstance = currentInstance;
8126 const innerParams = prepareParams(userParams, mixinParams);
8127 setParameters(innerParams);
8128 Object.freeze(innerParams);
8129
8130 // clear the previous timer
8131 if (globalState.timeout) {
8132 globalState.timeout.stop();
8133 delete globalState.timeout;
8134 }
8135
8136 // clear the restore focus timeout
8137 clearTimeout(globalState.restoreFocusTimeout);
8138 const domCache = populateDomCache(currentInstance);
8139 render(currentInstance, innerParams);
8140 privateProps.innerParams.set(currentInstance, innerParams);
8141 return swalPromise(currentInstance, domCache, innerParams);
8142 }
8143
8144 // `catch` cannot be the name of a module export, so we define our thenable methods here instead
8145 /**
8146 * @param {any} onFulfilled
8147 */
8148 then(onFulfilled) {
8149 return _classPrivateFieldGet2(_promise, this).then(onFulfilled);
8150 }
8151
8152 /**
8153 * @param {any} onFinally
8154 */
8155 finally(onFinally) {
8156 return _classPrivateFieldGet2(_promise, this).finally(onFinally);
8157 }
8158 }
8159
8160 /**
8161 * @param {SweetAlert} instance
8162 * @param {DomCache} domCache
8163 * @param {SweetAlertOptions} innerParams
8164 * @returns {Promise<SweetAlertResult>}
8165 */
8166 const swalPromise = (instance, domCache, innerParams) => {
8167 return new Promise((resolve, reject) => {
8168 // functions to handle all closings/dismissals
8169 /**
8170 * @param {DismissReason} dismiss
8171 */
8172 const dismissWith = dismiss => {
8173 instance.close({
8174 isDismissed: true,
8175 dismiss,
8176 isConfirmed: false,
8177 isDenied: false
8178 });
8179 };
8180 privateMethods.swalPromiseResolve.set(instance, resolve);
8181 privateMethods.swalPromiseReject.set(instance, reject);
8182 domCache.confirmButton.onclick = () => {
8183 handleConfirmButtonClick(instance);
8184 };
8185 domCache.denyButton.onclick = () => {
8186 handleDenyButtonClick(instance);
8187 };
8188 domCache.cancelButton.onclick = () => {
8189 handleCancelButtonClick(instance, dismissWith);
8190 };
8191 domCache.closeButton.onclick = () => {
8192 dismissWith(DismissReason.close);
8193 };
8194 handlePopupClick(innerParams, domCache, dismissWith);
8195 addKeydownHandler(globalState, innerParams, dismissWith);
8196 handleInputOptionsAndValue(instance, innerParams);
8197 openPopup(innerParams);
8198 setupTimer(globalState, innerParams, dismissWith);
8199 initFocus(domCache, innerParams);
8200
8201 // Scroll container to top on open (#1247, #1946)
8202 setTimeout(() => {
8203 domCache.container.scrollTop = 0;
8204 });
8205 });
8206 };
8207
8208 /**
8209 * @param {SweetAlertOptions} userParams
8210 * @param {SweetAlertOptions} mixinParams
8211 * @returns {SweetAlertOptions}
8212 */
8213 const prepareParams = (userParams, mixinParams) => {
8214 const templateParams = getTemplateParams(userParams);
8215 const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams); // precedence is described in #2131
8216 params.showClass = Object.assign({}, defaultParams.showClass, params.showClass);
8217 params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass);
8218 if (params.animation === false) {
8219 params.showClass = {
8220 backdrop: 'swal2-noanimation'
8221 };
8222 params.hideClass = {};
8223 }
8224 return params;
8225 };
8226
8227 /**
8228 * @param {SweetAlert} instance
8229 * @returns {DomCache}
8230 */
8231 const populateDomCache = instance => {
8232 const domCache = /** @type {DomCache} */{
8233 popup: (/** @type {HTMLElement} */getPopup()),
8234 container: (/** @type {HTMLElement} */getContainer()),
8235 actions: (/** @type {HTMLElement} */getActions()),
8236 confirmButton: (/** @type {HTMLElement} */getConfirmButton()),
8237 denyButton: (/** @type {HTMLElement} */getDenyButton()),
8238 cancelButton: (/** @type {HTMLElement} */getCancelButton()),
8239 loader: (/** @type {HTMLElement} */getLoader()),
8240 closeButton: (/** @type {HTMLElement} */getCloseButton()),
8241 validationMessage: (/** @type {HTMLElement} */getValidationMessage()),
8242 progressSteps: (/** @type {HTMLElement} */getProgressSteps())
8243 };
8244 privateProps.domCache.set(instance, domCache);
8245 return domCache;
8246 };
8247
8248 /**
8249 * @param {GlobalState} globalState
8250 * @param {SweetAlertOptions} innerParams
8251 * @param {(dismiss: DismissReason) => void} dismissWith
8252 */
8253 const setupTimer = (globalState, innerParams, dismissWith) => {
8254 const timerProgressBar = getTimerProgressBar();
8255 hide(timerProgressBar);
8256 if (innerParams.timer) {
8257 globalState.timeout = new Timer(() => {
8258 dismissWith('timer');
8259 delete globalState.timeout;
8260 }, innerParams.timer);
8261 if (innerParams.timerProgressBar && timerProgressBar) {
8262 show(timerProgressBar);
8263 applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar');
8264 setTimeout(() => {
8265 if (globalState.timeout && globalState.timeout.running) {
8266 // timer can be already stopped or unset at this point
8267 animateTimerProgressBar(/** @type {number} */innerParams.timer);
8268 }
8269 });
8270 }
8271 }
8272 };
8273
8274 /**
8275 * Initialize focus in the popup:
8276 *
8277 * 1. If `toast` is `true`, don't steal focus from the document.
8278 * 2. Else if there is an [autofocus] element, focus it.
8279 * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it.
8280 * 4. Else if `focusDeny` is `true` and deny button is visible, focus it.
8281 * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it.
8282 * 6. Else focus the first focusable element in a popup (if any).
8283 *
8284 * @param {DomCache} domCache
8285 * @param {SweetAlertOptions} innerParams
8286 */
8287 const initFocus = (domCache, innerParams) => {
8288 if (innerParams.toast) {
8289 return;
8290 }
8291 // TODO: this is dumb, remove `allowEnterKey` param in the next major version
8292 if (!callIfFunction(innerParams.allowEnterKey)) {
8293 warnAboutDeprecation('allowEnterKey');
8294 blurActiveElement();
8295 return;
8296 }
8297 if (focusAutofocus(domCache)) {
8298 return;
8299 }
8300 if (focusButton(domCache, innerParams)) {
8301 return;
8302 }
8303 setFocus(-1, 1);
8304 };
8305
8306 /**
8307 * @param {DomCache} domCache
8308 * @returns {boolean}
8309 */
8310 const focusAutofocus = domCache => {
8311 const autofocusElements = Array.from(domCache.popup.querySelectorAll('[autofocus]'));
8312 for (const autofocusElement of autofocusElements) {
8313 if (autofocusElement instanceof HTMLElement && isVisible$1(autofocusElement)) {
8314 autofocusElement.focus();
8315 return true;
8316 }
8317 }
8318 return false;
8319 };
8320
8321 /**
8322 * @param {DomCache} domCache
8323 * @param {SweetAlertOptions} innerParams
8324 * @returns {boolean}
8325 */
8326 const focusButton = (domCache, innerParams) => {
8327 if (innerParams.focusDeny && isVisible$1(domCache.denyButton)) {
8328 domCache.denyButton.focus();
8329 return true;
8330 }
8331 if (innerParams.focusCancel && isVisible$1(domCache.cancelButton)) {
8332 domCache.cancelButton.focus();
8333 return true;
8334 }
8335 if (innerParams.focusConfirm && isVisible$1(domCache.confirmButton)) {
8336 domCache.confirmButton.focus();
8337 return true;
8338 }
8339 return false;
8340 };
8341 const blurActiveElement = () => {
8342 if (document.activeElement instanceof HTMLElement && typeof document.activeElement.blur === 'function') {
8343 document.activeElement.blur();
8344 }
8345 };
8346
8347 // Assign instance methods from src/instanceMethods/*.js to prototype
8348 SweetAlert.prototype.disableButtons = disableButtons;
8349 SweetAlert.prototype.enableButtons = enableButtons;
8350 SweetAlert.prototype.getInput = getInput;
8351 SweetAlert.prototype.disableInput = disableInput;
8352 SweetAlert.prototype.enableInput = enableInput;
8353 SweetAlert.prototype.hideLoading = hideLoading;
8354 SweetAlert.prototype.disableLoading = hideLoading;
8355 SweetAlert.prototype.showValidationMessage = showValidationMessage;
8356 SweetAlert.prototype.resetValidationMessage = resetValidationMessage;
8357 SweetAlert.prototype.close = close;
8358 SweetAlert.prototype.closePopup = close;
8359 SweetAlert.prototype.closeModal = close;
8360 SweetAlert.prototype.closeToast = close;
8361 SweetAlert.prototype.rejectPromise = rejectPromise;
8362 SweetAlert.prototype.update = update;
8363 SweetAlert.prototype._destroy = _destroy;
8364
8365 // Assign static methods from src/staticMethods/*.js to constructor
8366 Object.assign(SweetAlert, staticMethods);
8367
8368 // Proxy to instance methods to constructor, for now, for backwards compatibility
8369 Object.keys(instanceMethods).forEach(key => {
8370 /**
8371 * @param {...(SweetAlertOptions | string | undefined)} args
8372 * @returns {SweetAlertResult | Promise<SweetAlertResult> | undefined}
8373 */
8374 // @ts-ignore: Dynamic property assignment for backwards compatibility
8375 SweetAlert[key] = function (...args) {
8376 // @ts-ignore
8377 if (currentInstance && currentInstance[key]) {
8378 // @ts-ignore
8379 return currentInstance[key](...args);
8380 }
8381 return undefined;
8382 };
8383 });
8384 SweetAlert.DismissReason = DismissReason;
8385 SweetAlert.version = '11.26.17';
8386
8387 const Swal = SweetAlert;
8388 // @ts-ignore
8389 Swal.default = Swal;
8390
8391 return Swal;
8392
8393 }));
8394 if (typeof this !== 'undefined' && this.Sweetalert2){this.swal = this.sweetAlert = this.Swal = this.SweetAlert = this.Sweetalert2}
8395 "undefined"!=typeof document&&function(e,t){var n=e.createElement("style");if(e.getElementsByTagName("head")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,":root{--swal2-outline: 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-container-padding: 0.625em;--swal2-backdrop: rgba(0, 0, 0, 0.4);--swal2-backdrop-transition: background-color 0.15s;--swal2-width: 32em;--swal2-padding: 0 0 1.25em;--swal2-border: none;--swal2-border-radius: 0.3125rem;--swal2-background: white;--swal2-color: #545454;--swal2-show-animation: swal2-show 0.3s;--swal2-hide-animation: swal2-hide 0.15s forwards;--swal2-icon-zoom: 1;--swal2-icon-animations: true;--swal2-title-padding: 0.8em 1em 0;--swal2-html-container-padding: 1em 1.6em 0.3em;--swal2-input-border: 1px solid #d9d9d9;--swal2-input-border-radius: 0.1875em;--swal2-input-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-background: transparent;--swal2-input-transition: border-color 0.2s, box-shadow 0.2s;--swal2-input-hover-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-focus-border: 1px solid #b4dbed;--swal2-input-focus-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-progress-step-background: #add8e6;--swal2-validation-message-background: #f0f0f0;--swal2-validation-message-color: #666;--swal2-footer-border-color: #eee;--swal2-footer-background: transparent;--swal2-footer-color: inherit;--swal2-timer-progress-bar-background: rgba(0, 0, 0, 0.3);--swal2-close-button-position: initial;--swal2-close-button-inset: auto;--swal2-close-button-font-size: 2.5em;--swal2-close-button-color: #ccc;--swal2-close-button-transition: color 0.2s, box-shadow 0.2s;--swal2-close-button-outline: initial;--swal2-close-button-box-shadow: inset 0 0 0 3px transparent;--swal2-close-button-focus-box-shadow: inset var(--swal2-outline);--swal2-close-button-hover-transform: none;--swal2-actions-justify-content: center;--swal2-actions-width: auto;--swal2-actions-margin: 1.25em auto 0;--swal2-actions-padding: 0;--swal2-actions-border-radius: 0;--swal2-actions-background: transparent;--swal2-action-button-transition: background-color 0.2s, box-shadow 0.2s;--swal2-action-button-hover: black 10%;--swal2-action-button-active: black 10%;--swal2-confirm-button-box-shadow: none;--swal2-confirm-button-border-radius: 0.25em;--swal2-confirm-button-background-color: #7066e0;--swal2-confirm-button-color: #fff;--swal2-deny-button-box-shadow: none;--swal2-deny-button-border-radius: 0.25em;--swal2-deny-button-background-color: #dc3741;--swal2-deny-button-color: #fff;--swal2-cancel-button-box-shadow: none;--swal2-cancel-button-border-radius: 0.25em;--swal2-cancel-button-background-color: #6e7881;--swal2-cancel-button-color: #fff;--swal2-toast-show-animation: swal2-toast-show 0.5s;--swal2-toast-hide-animation: swal2-toast-hide 0.1s forwards;--swal2-toast-border: none;--swal2-toast-box-shadow: 0 0 1px hsl(0deg 0% 0% / 0.075), 0 1px 2px hsl(0deg 0% 0% / 0.075), 1px 2px 4px hsl(0deg 0% 0% / 0.075), 1px 3px 8px hsl(0deg 0% 0% / 0.075), 2px 4px 16px hsl(0deg 0% 0% / 0.075)}[data-swal2-theme=dark]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}@media(prefers-color-scheme: dark){[data-swal2-theme=auto]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto !important}body.swal2-no-backdrop .swal2-container{background-color:rgba(0,0,0,0) !important;pointer-events:none}body.swal2-no-backdrop .swal2-container .swal2-popup{pointer-events:all}body.swal2-no-backdrop .swal2-container .swal2-modal{box-shadow:0 0 10px var(--swal2-backdrop)}body.swal2-toast-shown .swal2-container{box-sizing:border-box;width:360px;max-width:100%;background-color:rgba(0,0,0,0);pointer-events:none}body.swal2-toast-shown .swal2-container.swal2-top{inset:0 auto auto 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{inset:0 0 auto auto}body.swal2-toast-shown .swal2-container.swal2-top-start,body.swal2-toast-shown .swal2-container.swal2-top-left{inset:0 auto auto 0}body.swal2-toast-shown .swal2-container.swal2-center-start,body.swal2-toast-shown .swal2-container.swal2-center-left{inset:50% auto auto 0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{inset:50% auto auto 50%;transform:translate(-50%, -50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{inset:50% 0 auto auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-start,body.swal2-toast-shown .swal2-container.swal2-bottom-left{inset:auto auto 0 0}body.swal2-toast-shown .swal2-container.swal2-bottom{inset:auto auto 0 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{inset:auto 0 0 auto}@media print{body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow-y:scroll !important}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown) .swal2-container{position:static !important}}div:where(.swal2-container){display:grid;position:fixed;z-index:1060;inset:0;box-sizing:border-box;grid-template-areas:\"top-start top top-end\" \"center-start center center-end\" \"bottom-start bottom-center bottom-end\";grid-template-rows:minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);height:100%;padding:var(--swal2-container-padding);overflow-x:hidden;transition:var(--swal2-backdrop-transition);-webkit-overflow-scrolling:touch}div:where(.swal2-container).swal2-backdrop-show,div:where(.swal2-container).swal2-noanimation{background:var(--swal2-backdrop)}div:where(.swal2-container).swal2-backdrop-hide{background:rgba(0,0,0,0) !important}div:where(.swal2-container).swal2-top-start,div:where(.swal2-container).swal2-center-start,div:where(.swal2-container).swal2-bottom-start{grid-template-columns:minmax(0, 1fr) auto auto}div:where(.swal2-container).swal2-top,div:where(.swal2-container).swal2-center,div:where(.swal2-container).swal2-bottom{grid-template-columns:auto minmax(0, 1fr) auto}div:where(.swal2-container).swal2-top-end,div:where(.swal2-container).swal2-center-end,div:where(.swal2-container).swal2-bottom-end{grid-template-columns:auto auto minmax(0, 1fr)}div:where(.swal2-container).swal2-top-start>.swal2-popup{align-self:start}div:where(.swal2-container).swal2-top>.swal2-popup{grid-column:2;place-self:start center}div:where(.swal2-container).swal2-top-end>.swal2-popup,div:where(.swal2-container).swal2-top-right>.swal2-popup{grid-column:3;place-self:start end}div:where(.swal2-container).swal2-center-start>.swal2-popup,div:where(.swal2-container).swal2-center-left>.swal2-popup{grid-row:2;align-self:center}div:where(.swal2-container).swal2-center>.swal2-popup{grid-column:2;grid-row:2;place-self:center center}div:where(.swal2-container).swal2-center-end>.swal2-popup,div:where(.swal2-container).swal2-center-right>.swal2-popup{grid-column:3;grid-row:2;place-self:center end}div:where(.swal2-container).swal2-bottom-start>.swal2-popup,div:where(.swal2-container).swal2-bottom-left>.swal2-popup{grid-column:1;grid-row:3;align-self:end}div:where(.swal2-container).swal2-bottom>.swal2-popup{grid-column:2;grid-row:3;place-self:end center}div:where(.swal2-container).swal2-bottom-end>.swal2-popup,div:where(.swal2-container).swal2-bottom-right>.swal2-popup{grid-column:3;grid-row:3;place-self:end end}div:where(.swal2-container).swal2-grow-row>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-column:1/4;width:100%}div:where(.swal2-container).swal2-grow-column>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-row:1/4;align-self:stretch}div:where(.swal2-container).swal2-no-transition{transition:none !important}div:where(.swal2-container)[popover]{width:auto;border:0}div:where(.swal2-container) div:where(.swal2-popup){display:none;position:relative;box-sizing:border-box;grid-template-columns:minmax(0, 100%);width:var(--swal2-width);max-width:100%;padding:var(--swal2-padding);border:var(--swal2-border);border-radius:var(--swal2-border-radius);background:var(--swal2-background);color:var(--swal2-color);font-family:inherit;font-size:1rem;container-name:swal2-popup}div:where(.swal2-container) div:where(.swal2-popup):focus{outline:none}div:where(.swal2-container) div:where(.swal2-popup).swal2-loading{overflow-y:hidden}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable{cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable div:where(.swal2-icon){cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging{cursor:grabbing}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging div:where(.swal2-icon){cursor:grabbing}div:where(.swal2-container) h2:where(.swal2-title){position:relative;max-width:100%;margin:0;padding:var(--swal2-title-padding);color:inherit;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;overflow-wrap:break-word;cursor:initial}div:where(.swal2-container) div:where(.swal2-actions){display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:var(--swal2-actions-justify-content);width:var(--swal2-actions-width);margin:var(--swal2-actions-margin);padding:var(--swal2-actions-padding);border-radius:var(--swal2-actions-border-radius);background:var(--swal2-actions-background)}div:where(.swal2-container) div:where(.swal2-loader){display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 rgba(0,0,0,0) #2778c4 rgba(0,0,0,0)}div:where(.swal2-container) button:where(.swal2-styled){margin:.3125em;padding:.625em 1.1em;transition:var(--swal2-action-button-transition);border:none;box-shadow:0 0 0 3px rgba(0,0,0,0);font-weight:500}div:where(.swal2-container) button:where(.swal2-styled):not([disabled]){cursor:pointer}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm){border-radius:var(--swal2-confirm-button-border-radius);background:initial;background-color:var(--swal2-confirm-button-background-color);box-shadow:var(--swal2-confirm-button-box-shadow);color:var(--swal2-confirm-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):hover{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):active{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny){border-radius:var(--swal2-deny-button-border-radius);background:initial;background-color:var(--swal2-deny-button-background-color);box-shadow:var(--swal2-deny-button-box-shadow);color:var(--swal2-deny-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):hover{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):active{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel){border-radius:var(--swal2-cancel-button-border-radius);background:initial;background-color:var(--swal2-cancel-button-background-color);box-shadow:var(--swal2-cancel-button-box-shadow);color:var(--swal2-cancel-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):hover{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):active{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):focus-visible{outline:none;box-shadow:var(--swal2-action-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-styled)[disabled]:not(.swal2-loading){opacity:.4}div:where(.swal2-container) button:where(.swal2-styled)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-footer){margin:1em 0 0;padding:1em 1em 0;border-top:1px solid var(--swal2-footer-border-color);background:var(--swal2-footer-background);color:var(--swal2-footer-color);font-size:1em;text-align:center;cursor:initial}div:where(.swal2-container) .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto !important;overflow:hidden;border-bottom-right-radius:var(--swal2-border-radius);border-bottom-left-radius:var(--swal2-border-radius)}div:where(.swal2-container) div:where(.swal2-timer-progress-bar){width:100%;height:.25em;background:var(--swal2-timer-progress-bar-background)}div:where(.swal2-container) img:where(.swal2-image){max-width:100%;margin:2em auto 1em;cursor:initial}div:where(.swal2-container) button:where(.swal2-close){position:var(--swal2-close-button-position);inset:var(--swal2-close-button-inset);z-index:2;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-top:0;margin-right:0;margin-bottom:-1.2em;padding:0;overflow:hidden;transition:var(--swal2-close-button-transition);border:none;border-radius:var(--swal2-border-radius);outline:var(--swal2-close-button-outline);background:rgba(0,0,0,0);color:var(--swal2-close-button-color);font-family:monospace;font-size:var(--swal2-close-button-font-size);cursor:pointer;justify-self:end}div:where(.swal2-container) button:where(.swal2-close):hover{transform:var(--swal2-close-button-hover-transform);background:rgba(0,0,0,0);color:#f27474}div:where(.swal2-container) button:where(.swal2-close):focus-visible{outline:none;box-shadow:var(--swal2-close-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-close)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-html-container){z-index:1;justify-content:center;margin:0;padding:var(--swal2-html-container-padding);overflow:auto;color:inherit;font-size:1.125em;font-weight:normal;line-height:normal;text-align:center;overflow-wrap:break-word;word-break:break-word;cursor:initial}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea),div:where(.swal2-container) select:where(.swal2-select),div:where(.swal2-container) div:where(.swal2-radio),div:where(.swal2-container) label:where(.swal2-checkbox){margin:1em 2em 3px}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea){box-sizing:border-box;width:auto;transition:var(--swal2-input-transition);border:var(--swal2-input-border);border-radius:var(--swal2-input-border-radius);background:var(--swal2-input-background);box-shadow:var(--swal2-input-box-shadow);color:inherit;font-size:1.125em}div:where(.swal2-container) input:where(.swal2-input).swal2-inputerror,div:where(.swal2-container) input:where(.swal2-file).swal2-inputerror,div:where(.swal2-container) textarea:where(.swal2-textarea).swal2-inputerror{border-color:#f27474 !important;box-shadow:0 0 2px #f27474 !important}div:where(.swal2-container) input:where(.swal2-input):hover,div:where(.swal2-container) input:where(.swal2-file):hover,div:where(.swal2-container) textarea:where(.swal2-textarea):hover{box-shadow:var(--swal2-input-hover-box-shadow)}div:where(.swal2-container) input:where(.swal2-input):focus,div:where(.swal2-container) input:where(.swal2-file):focus,div:where(.swal2-container) textarea:where(.swal2-textarea):focus{border:var(--swal2-input-focus-border);outline:none;box-shadow:var(--swal2-input-focus-box-shadow)}div:where(.swal2-container) input:where(.swal2-input)::placeholder,div:where(.swal2-container) input:where(.swal2-file)::placeholder,div:where(.swal2-container) textarea:where(.swal2-textarea)::placeholder{color:#ccc}div:where(.swal2-container) .swal2-range{margin:1em 2em 3px;background:var(--swal2-background)}div:where(.swal2-container) .swal2-range input{width:80%}div:where(.swal2-container) .swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}div:where(.swal2-container) .swal2-range input,div:where(.swal2-container) .swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}div:where(.swal2-container) .swal2-input{height:2.625em;padding:0 .75em}div:where(.swal2-container) .swal2-file{width:75%;margin-right:auto;margin-left:auto;background:var(--swal2-input-background);font-size:1.125em}div:where(.swal2-container) .swal2-textarea{height:6.75em;padding:.75em}div:where(.swal2-container) .swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:var(--swal2-input-background);color:inherit;font-size:1.125em}div:where(.swal2-container) .swal2-radio,div:where(.swal2-container) .swal2-checkbox{align-items:center;justify-content:center;background:var(--swal2-background);color:inherit}div:where(.swal2-container) .swal2-radio label,div:where(.swal2-container) .swal2-checkbox label{margin:0 .6em;font-size:1.125em}div:where(.swal2-container) .swal2-radio input,div:where(.swal2-container) .swal2-checkbox input{flex-shrink:0;margin:0 .4em}div:where(.swal2-container) label:where(.swal2-input-label){display:flex;justify-content:center;margin:1em auto 0}div:where(.swal2-container) div:where(.swal2-validation-message){align-items:center;justify-content:center;margin:1em 0 0;padding:.625em;overflow:hidden;background:var(--swal2-validation-message-background);color:var(--swal2-validation-message-color);font-size:1em;font-weight:300}div:where(.swal2-container) div:where(.swal2-validation-message)::before{content:\"!\";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}div:where(.swal2-container) .swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:1.25em auto;padding:0;background:rgba(0,0,0,0);font-weight:600}div:where(.swal2-container) .swal2-progress-steps li{display:inline-block;position:relative}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:var(--swal2-progress-step-background);color:#fff}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:var(--swal2-progress-step-background)}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}div:where(.swal2-icon){position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:2.5em auto .6em;zoom:var(--swal2-icon-zoom);border:.25em solid rgba(0,0,0,0);border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;user-select:none}div:where(.swal2-icon) .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}div:where(.swal2-icon).swal2-error{border-color:#f27474;color:#f27474}div:where(.swal2-icon).swal2-error .swal2-x-mark{position:relative;flex-grow:1}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-error.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-error.swal2-icon-show .swal2-x-mark{animation:swal2-animate-error-x-mark .5s}}div:where(.swal2-icon).swal2-warning{border-color:#f8bb86;color:#f8bb86}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-warning.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-warning.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .5s}}div:where(.swal2-icon).swal2-info{border-color:#3fc3ee;color:#3fc3ee}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-info.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-info.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .8s}}div:where(.swal2-icon).swal2-question{border-color:#87adbd;color:#87adbd}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-question.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-question.swal2-icon-show .swal2-icon-content{animation:swal2-animate-question-mark .8s}}div:where(.swal2-icon).swal2-success{border-color:#a5dc86;color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;border-radius:50%}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}div:where(.swal2-icon).swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-0.25em;left:-0.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}div:where(.swal2-icon).swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-animate-success-line-tip .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-animate-success-line-long .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-circular-line-right{animation:swal2-rotate-success-circular-line 4.25s ease-in}}[class^=swal2]{-webkit-tap-highlight-color:rgba(0,0,0,0)}.swal2-show{animation:var(--swal2-show-animation)}.swal2-hide{animation:var(--swal2-hide-animation)}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{margin-right:initial;margin-left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}.swal2-toast{box-sizing:border-box;grid-column:1/4 !important;grid-row:1/4 !important;grid-template-columns:min-content auto min-content;padding:1em;overflow-y:hidden;border:var(--swal2-toast-border);background:var(--swal2-background);box-shadow:var(--swal2-toast-box-shadow);pointer-events:all}.swal2-toast>*{grid-column:2}.swal2-toast h2:where(.swal2-title){margin:.5em 1em;padding:0;font-size:1em;text-align:initial}.swal2-toast .swal2-loading{justify-content:center}.swal2-toast input:where(.swal2-input){height:2em;margin:.5em;font-size:1em}.swal2-toast .swal2-validation-message{font-size:1em}.swal2-toast div:where(.swal2-footer){margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-toast button:where(.swal2-close){grid-column:3/3;grid-row:1/99;align-self:center;width:.8em;height:.8em;margin:0;font-size:2em}.swal2-toast div:where(.swal2-html-container){margin:.5em 1em;padding:0;overflow:initial;font-size:1em;text-align:initial}.swal2-toast div:where(.swal2-html-container):empty{padding:0}.swal2-toast .swal2-loader{grid-column:1;grid-row:1/99;align-self:center;width:2em;height:2em;margin:.25em}.swal2-toast .swal2-icon{grid-column:1;grid-row:1/99;align-self:center;width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:bold}.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-toast div:where(.swal2-actions){justify-content:flex-start;height:auto;margin:0;margin-top:.5em;padding:0 .5em}.swal2-toast button:where(.swal2-styled){margin:.25em .5em;padding:.4em .6em;font-size:1em}.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;border-radius:50%}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.8em;left:-0.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}@container swal2-popup style(--swal2-icon-animations:true){.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-toast-animate-success-line-tip .75s}.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-toast-animate-success-line-long .75s}}.swal2-toast.swal2-show{animation:var(--swal2-toast-show-animation)}.swal2-toast.swal2-hide{animation:var(--swal2-toast-hide-animation)}@keyframes swal2-show{0%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}100%{transform:translate3d(0, 0, 0) scale(1);opacity:1}}@keyframes swal2-hide{0%{transform:translate3d(0, 0, 0) scale(1);opacity:1}100%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-0.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(0.4);opacity:0}50%{margin-top:1.625em;transform:scale(0.4);opacity:0}80%{margin-top:-0.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);opacity:1}}@keyframes swal2-rotate-loading{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes swal2-animate-question-mark{0%{transform:rotateY(-360deg)}100%{transform:rotateY(0)}}@keyframes swal2-animate-i-mark{0%{transform:rotateZ(45deg);opacity:0}25%{transform:rotateZ(-25deg);opacity:.4}50%{transform:rotateZ(15deg);opacity:.8}75%{transform:rotateZ(-5deg);opacity:1}100%{transform:rotateX(0);opacity:1}}@keyframes swal2-toast-show{0%{transform:translateY(-0.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(0.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0deg)}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-0.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}");
8396
8397 /***/ },
8398
8399 /***/ "./node_modules/@kurkle/color/dist/color.esm.js"
8400 /*!******************************************************!*\
8401 !*** ./node_modules/@kurkle/color/dist/color.esm.js ***!
8402 \******************************************************/
8403 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8404
8405 "use strict";
8406 __webpack_require__.r(__webpack_exports__);
8407 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8408 /* harmony export */ Color: () => (/* binding */ Color),
8409 /* harmony export */ b2n: () => (/* binding */ b2n),
8410 /* harmony export */ b2p: () => (/* binding */ b2p),
8411 /* harmony export */ "default": () => (/* binding */ index_esm),
8412 /* harmony export */ hexParse: () => (/* binding */ hexParse),
8413 /* harmony export */ hexString: () => (/* binding */ hexString),
8414 /* harmony export */ hsl2rgb: () => (/* binding */ hsl2rgb),
8415 /* harmony export */ hslString: () => (/* binding */ hslString),
8416 /* harmony export */ hsv2rgb: () => (/* binding */ hsv2rgb),
8417 /* harmony export */ hueParse: () => (/* binding */ hueParse),
8418 /* harmony export */ hwb2rgb: () => (/* binding */ hwb2rgb),
8419 /* harmony export */ lim: () => (/* binding */ lim),
8420 /* harmony export */ n2b: () => (/* binding */ n2b),
8421 /* harmony export */ n2p: () => (/* binding */ n2p),
8422 /* harmony export */ nameParse: () => (/* binding */ nameParse),
8423 /* harmony export */ p2b: () => (/* binding */ p2b),
8424 /* harmony export */ rgb2hsl: () => (/* binding */ rgb2hsl),
8425 /* harmony export */ rgbParse: () => (/* binding */ rgbParse),
8426 /* harmony export */ rgbString: () => (/* binding */ rgbString),
8427 /* harmony export */ rotate: () => (/* binding */ rotate),
8428 /* harmony export */ round: () => (/* binding */ round)
8429 /* harmony export */ });
8430 /*!
8431 * @kurkle/color v0.3.4
8432 * https://github.com/kurkle/color#readme
8433 * (c) 2024 Jukka Kurkela
8434 * Released under the MIT License
8435 */
8436 function round(v) {
8437 return v + 0.5 | 0;
8438 }
8439 const lim = (v, l, h) => Math.max(Math.min(v, h), l);
8440 function p2b(v) {
8441 return lim(round(v * 2.55), 0, 255);
8442 }
8443 function b2p(v) {
8444 return lim(round(v / 2.55), 0, 100);
8445 }
8446 function n2b(v) {
8447 return lim(round(v * 255), 0, 255);
8448 }
8449 function b2n(v) {
8450 return lim(round(v / 2.55) / 100, 0, 1);
8451 }
8452 function n2p(v) {
8453 return lim(round(v * 100), 0, 100);
8454 }
8455
8456 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};
8457 const hex = [...'0123456789ABCDEF'];
8458 const h1 = b => hex[b & 0xF];
8459 const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF];
8460 const eq = b => ((b & 0xF0) >> 4) === (b & 0xF);
8461 const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);
8462 function hexParse(str) {
8463 var len = str.length;
8464 var ret;
8465 if (str[0] === '#') {
8466 if (len === 4 || len === 5) {
8467 ret = {
8468 r: 255 & map$1[str[1]] * 17,
8469 g: 255 & map$1[str[2]] * 17,
8470 b: 255 & map$1[str[3]] * 17,
8471 a: len === 5 ? map$1[str[4]] * 17 : 255
8472 };
8473 } else if (len === 7 || len === 9) {
8474 ret = {
8475 r: map$1[str[1]] << 4 | map$1[str[2]],
8476 g: map$1[str[3]] << 4 | map$1[str[4]],
8477 b: map$1[str[5]] << 4 | map$1[str[6]],
8478 a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255
8479 };
8480 }
8481 }
8482 return ret;
8483 }
8484 const alpha = (a, f) => a < 255 ? f(a) : '';
8485 function hexString(v) {
8486 var f = isShort(v) ? h1 : h2;
8487 return v
8488 ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f)
8489 : undefined;
8490 }
8491
8492 const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
8493 function hsl2rgbn(h, s, l) {
8494 const a = s * Math.min(l, 1 - l);
8495 const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
8496 return [f(0), f(8), f(4)];
8497 }
8498 function hsv2rgbn(h, s, v) {
8499 const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
8500 return [f(5), f(3), f(1)];
8501 }
8502 function hwb2rgbn(h, w, b) {
8503 const rgb = hsl2rgbn(h, 1, 0.5);
8504 let i;
8505 if (w + b > 1) {
8506 i = 1 / (w + b);
8507 w *= i;
8508 b *= i;
8509 }
8510 for (i = 0; i < 3; i++) {
8511 rgb[i] *= 1 - w - b;
8512 rgb[i] += w;
8513 }
8514 return rgb;
8515 }
8516 function hueValue(r, g, b, d, max) {
8517 if (r === max) {
8518 return ((g - b) / d) + (g < b ? 6 : 0);
8519 }
8520 if (g === max) {
8521 return (b - r) / d + 2;
8522 }
8523 return (r - g) / d + 4;
8524 }
8525 function rgb2hsl(v) {
8526 const range = 255;
8527 const r = v.r / range;
8528 const g = v.g / range;
8529 const b = v.b / range;
8530 const max = Math.max(r, g, b);
8531 const min = Math.min(r, g, b);
8532 const l = (max + min) / 2;
8533 let h, s, d;
8534 if (max !== min) {
8535 d = max - min;
8536 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
8537 h = hueValue(r, g, b, d, max);
8538 h = h * 60 + 0.5;
8539 }
8540 return [h | 0, s || 0, l];
8541 }
8542 function calln(f, a, b, c) {
8543 return (
8544 Array.isArray(a)
8545 ? f(a[0], a[1], a[2])
8546 : f(a, b, c)
8547 ).map(n2b);
8548 }
8549 function hsl2rgb(h, s, l) {
8550 return calln(hsl2rgbn, h, s, l);
8551 }
8552 function hwb2rgb(h, w, b) {
8553 return calln(hwb2rgbn, h, w, b);
8554 }
8555 function hsv2rgb(h, s, v) {
8556 return calln(hsv2rgbn, h, s, v);
8557 }
8558 function hue(h) {
8559 return (h % 360 + 360) % 360;
8560 }
8561 function hueParse(str) {
8562 const m = HUE_RE.exec(str);
8563 let a = 255;
8564 let v;
8565 if (!m) {
8566 return;
8567 }
8568 if (m[5] !== v) {
8569 a = m[6] ? p2b(+m[5]) : n2b(+m[5]);
8570 }
8571 const h = hue(+m[2]);
8572 const p1 = +m[3] / 100;
8573 const p2 = +m[4] / 100;
8574 if (m[1] === 'hwb') {
8575 v = hwb2rgb(h, p1, p2);
8576 } else if (m[1] === 'hsv') {
8577 v = hsv2rgb(h, p1, p2);
8578 } else {
8579 v = hsl2rgb(h, p1, p2);
8580 }
8581 return {
8582 r: v[0],
8583 g: v[1],
8584 b: v[2],
8585 a: a
8586 };
8587 }
8588 function rotate(v, deg) {
8589 var h = rgb2hsl(v);
8590 h[0] = hue(h[0] + deg);
8591 h = hsl2rgb(h);
8592 v.r = h[0];
8593 v.g = h[1];
8594 v.b = h[2];
8595 }
8596 function hslString(v) {
8597 if (!v) {
8598 return;
8599 }
8600 const a = rgb2hsl(v);
8601 const h = a[0];
8602 const s = n2p(a[1]);
8603 const l = n2p(a[2]);
8604 return v.a < 255
8605 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`
8606 : `hsl(${h}, ${s}%, ${l}%)`;
8607 }
8608
8609 const map = {
8610 x: 'dark',
8611 Z: 'light',
8612 Y: 're',
8613 X: 'blu',
8614 W: 'gr',
8615 V: 'medium',
8616 U: 'slate',
8617 A: 'ee',
8618 T: 'ol',
8619 S: 'or',
8620 B: 'ra',
8621 C: 'lateg',
8622 D: 'ights',
8623 R: 'in',
8624 Q: 'turquois',
8625 E: 'hi',
8626 P: 'ro',
8627 O: 'al',
8628 N: 'le',
8629 M: 'de',
8630 L: 'yello',
8631 F: 'en',
8632 K: 'ch',
8633 G: 'arks',
8634 H: 'ea',
8635 I: 'ightg',
8636 J: 'wh'
8637 };
8638 const names$1 = {
8639 OiceXe: 'f0f8ff',
8640 antiquewEte: 'faebd7',
8641 aqua: 'ffff',
8642 aquamarRe: '7fffd4',
8643 azuY: 'f0ffff',
8644 beige: 'f5f5dc',
8645 bisque: 'ffe4c4',
8646 black: '0',
8647 blanKedOmond: 'ffebcd',
8648 Xe: 'ff',
8649 XeviTet: '8a2be2',
8650 bPwn: 'a52a2a',
8651 burlywood: 'deb887',
8652 caMtXe: '5f9ea0',
8653 KartYuse: '7fff00',
8654 KocTate: 'd2691e',
8655 cSO: 'ff7f50',
8656 cSnflowerXe: '6495ed',
8657 cSnsilk: 'fff8dc',
8658 crimson: 'dc143c',
8659 cyan: 'ffff',
8660 xXe: '8b',
8661 xcyan: '8b8b',
8662 xgTMnPd: 'b8860b',
8663 xWay: 'a9a9a9',
8664 xgYF: '6400',
8665 xgYy: 'a9a9a9',
8666 xkhaki: 'bdb76b',
8667 xmagFta: '8b008b',
8668 xTivegYF: '556b2f',
8669 xSange: 'ff8c00',
8670 xScEd: '9932cc',
8671 xYd: '8b0000',
8672 xsOmon: 'e9967a',
8673 xsHgYF: '8fbc8f',
8674 xUXe: '483d8b',
8675 xUWay: '2f4f4f',
8676 xUgYy: '2f4f4f',
8677 xQe: 'ced1',
8678 xviTet: '9400d3',
8679 dAppRk: 'ff1493',
8680 dApskyXe: 'bfff',
8681 dimWay: '696969',
8682 dimgYy: '696969',
8683 dodgerXe: '1e90ff',
8684 fiYbrick: 'b22222',
8685 flSOwEte: 'fffaf0',
8686 foYstWAn: '228b22',
8687 fuKsia: 'ff00ff',
8688 gaRsbSo: 'dcdcdc',
8689 ghostwEte: 'f8f8ff',
8690 gTd: 'ffd700',
8691 gTMnPd: 'daa520',
8692 Way: '808080',
8693 gYF: '8000',
8694 gYFLw: 'adff2f',
8695 gYy: '808080',
8696 honeyMw: 'f0fff0',
8697 hotpRk: 'ff69b4',
8698 RdianYd: 'cd5c5c',
8699 Rdigo: '4b0082',
8700 ivSy: 'fffff0',
8701 khaki: 'f0e68c',
8702 lavFMr: 'e6e6fa',
8703 lavFMrXsh: 'fff0f5',
8704 lawngYF: '7cfc00',
8705 NmoncEffon: 'fffacd',
8706 ZXe: 'add8e6',
8707 ZcSO: 'f08080',
8708 Zcyan: 'e0ffff',
8709 ZgTMnPdLw: 'fafad2',
8710 ZWay: 'd3d3d3',
8711 ZgYF: '90ee90',
8712 ZgYy: 'd3d3d3',
8713 ZpRk: 'ffb6c1',
8714 ZsOmon: 'ffa07a',
8715 ZsHgYF: '20b2aa',
8716 ZskyXe: '87cefa',
8717 ZUWay: '778899',
8718 ZUgYy: '778899',
8719 ZstAlXe: 'b0c4de',
8720 ZLw: 'ffffe0',
8721 lime: 'ff00',
8722 limegYF: '32cd32',
8723 lRF: 'faf0e6',
8724 magFta: 'ff00ff',
8725 maPon: '800000',
8726 VaquamarRe: '66cdaa',
8727 VXe: 'cd',
8728 VScEd: 'ba55d3',
8729 VpurpN: '9370db',
8730 VsHgYF: '3cb371',
8731 VUXe: '7b68ee',
8732 VsprRggYF: 'fa9a',
8733 VQe: '48d1cc',
8734 VviTetYd: 'c71585',
8735 midnightXe: '191970',
8736 mRtcYam: 'f5fffa',
8737 mistyPse: 'ffe4e1',
8738 moccasR: 'ffe4b5',
8739 navajowEte: 'ffdead',
8740 navy: '80',
8741 Tdlace: 'fdf5e6',
8742 Tive: '808000',
8743 TivedBb: '6b8e23',
8744 Sange: 'ffa500',
8745 SangeYd: 'ff4500',
8746 ScEd: 'da70d6',
8747 pOegTMnPd: 'eee8aa',
8748 pOegYF: '98fb98',
8749 pOeQe: 'afeeee',
8750 pOeviTetYd: 'db7093',
8751 papayawEp: 'ffefd5',
8752 pHKpuff: 'ffdab9',
8753 peru: 'cd853f',
8754 pRk: 'ffc0cb',
8755 plum: 'dda0dd',
8756 powMrXe: 'b0e0e6',
8757 purpN: '800080',
8758 YbeccapurpN: '663399',
8759 Yd: 'ff0000',
8760 Psybrown: 'bc8f8f',
8761 PyOXe: '4169e1',
8762 saddNbPwn: '8b4513',
8763 sOmon: 'fa8072',
8764 sandybPwn: 'f4a460',
8765 sHgYF: '2e8b57',
8766 sHshell: 'fff5ee',
8767 siFna: 'a0522d',
8768 silver: 'c0c0c0',
8769 skyXe: '87ceeb',
8770 UXe: '6a5acd',
8771 UWay: '708090',
8772 UgYy: '708090',
8773 snow: 'fffafa',
8774 sprRggYF: 'ff7f',
8775 stAlXe: '4682b4',
8776 tan: 'd2b48c',
8777 teO: '8080',
8778 tEstN: 'd8bfd8',
8779 tomato: 'ff6347',
8780 Qe: '40e0d0',
8781 viTet: 'ee82ee',
8782 JHt: 'f5deb3',
8783 wEte: 'ffffff',
8784 wEtesmoke: 'f5f5f5',
8785 Lw: 'ffff00',
8786 LwgYF: '9acd32'
8787 };
8788 function unpack() {
8789 const unpacked = {};
8790 const keys = Object.keys(names$1);
8791 const tkeys = Object.keys(map);
8792 let i, j, k, ok, nk;
8793 for (i = 0; i < keys.length; i++) {
8794 ok = nk = keys[i];
8795 for (j = 0; j < tkeys.length; j++) {
8796 k = tkeys[j];
8797 nk = nk.replace(k, map[k]);
8798 }
8799 k = parseInt(names$1[ok], 16);
8800 unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];
8801 }
8802 return unpacked;
8803 }
8804
8805 let names;
8806 function nameParse(str) {
8807 if (!names) {
8808 names = unpack();
8809 names.transparent = [0, 0, 0, 0];
8810 }
8811 const a = names[str.toLowerCase()];
8812 return a && {
8813 r: a[0],
8814 g: a[1],
8815 b: a[2],
8816 a: a.length === 4 ? a[3] : 255
8817 };
8818 }
8819
8820 const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
8821 function rgbParse(str) {
8822 const m = RGB_RE.exec(str);
8823 let a = 255;
8824 let r, g, b;
8825 if (!m) {
8826 return;
8827 }
8828 if (m[7] !== r) {
8829 const v = +m[7];
8830 a = m[8] ? p2b(v) : lim(v * 255, 0, 255);
8831 }
8832 r = +m[1];
8833 g = +m[3];
8834 b = +m[5];
8835 r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255));
8836 g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255));
8837 b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255));
8838 return {
8839 r: r,
8840 g: g,
8841 b: b,
8842 a: a
8843 };
8844 }
8845 function rgbString(v) {
8846 return v && (
8847 v.a < 255
8848 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`
8849 : `rgb(${v.r}, ${v.g}, ${v.b})`
8850 );
8851 }
8852
8853 const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055;
8854 const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
8855 function interpolate(rgb1, rgb2, t) {
8856 const r = from(b2n(rgb1.r));
8857 const g = from(b2n(rgb1.g));
8858 const b = from(b2n(rgb1.b));
8859 return {
8860 r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))),
8861 g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))),
8862 b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))),
8863 a: rgb1.a + t * (rgb2.a - rgb1.a)
8864 };
8865 }
8866
8867 function modHSL(v, i, ratio) {
8868 if (v) {
8869 let tmp = rgb2hsl(v);
8870 tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));
8871 tmp = hsl2rgb(tmp);
8872 v.r = tmp[0];
8873 v.g = tmp[1];
8874 v.b = tmp[2];
8875 }
8876 }
8877 function clone(v, proto) {
8878 return v ? Object.assign(proto || {}, v) : v;
8879 }
8880 function fromObject(input) {
8881 var v = {r: 0, g: 0, b: 0, a: 255};
8882 if (Array.isArray(input)) {
8883 if (input.length >= 3) {
8884 v = {r: input[0], g: input[1], b: input[2], a: 255};
8885 if (input.length > 3) {
8886 v.a = n2b(input[3]);
8887 }
8888 }
8889 } else {
8890 v = clone(input, {r: 0, g: 0, b: 0, a: 1});
8891 v.a = n2b(v.a);
8892 }
8893 return v;
8894 }
8895 function functionParse(str) {
8896 if (str.charAt(0) === 'r') {
8897 return rgbParse(str);
8898 }
8899 return hueParse(str);
8900 }
8901 class Color {
8902 constructor(input) {
8903 if (input instanceof Color) {
8904 return input;
8905 }
8906 const type = typeof input;
8907 let v;
8908 if (type === 'object') {
8909 v = fromObject(input);
8910 } else if (type === 'string') {
8911 v = hexParse(input) || nameParse(input) || functionParse(input);
8912 }
8913 this._rgb = v;
8914 this._valid = !!v;
8915 }
8916 get valid() {
8917 return this._valid;
8918 }
8919 get rgb() {
8920 var v = clone(this._rgb);
8921 if (v) {
8922 v.a = b2n(v.a);
8923 }
8924 return v;
8925 }
8926 set rgb(obj) {
8927 this._rgb = fromObject(obj);
8928 }
8929 rgbString() {
8930 return this._valid ? rgbString(this._rgb) : undefined;
8931 }
8932 hexString() {
8933 return this._valid ? hexString(this._rgb) : undefined;
8934 }
8935 hslString() {
8936 return this._valid ? hslString(this._rgb) : undefined;
8937 }
8938 mix(color, weight) {
8939 if (color) {
8940 const c1 = this.rgb;
8941 const c2 = color.rgb;
8942 let w2;
8943 const p = weight === w2 ? 0.5 : weight;
8944 const w = 2 * p - 1;
8945 const a = c1.a - c2.a;
8946 const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
8947 w2 = 1 - w1;
8948 c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;
8949 c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;
8950 c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;
8951 c1.a = p * c1.a + (1 - p) * c2.a;
8952 this.rgb = c1;
8953 }
8954 return this;
8955 }
8956 interpolate(color, t) {
8957 if (color) {
8958 this._rgb = interpolate(this._rgb, color._rgb, t);
8959 }
8960 return this;
8961 }
8962 clone() {
8963 return new Color(this.rgb);
8964 }
8965 alpha(a) {
8966 this._rgb.a = n2b(a);
8967 return this;
8968 }
8969 clearer(ratio) {
8970 const rgb = this._rgb;
8971 rgb.a *= 1 - ratio;
8972 return this;
8973 }
8974 greyscale() {
8975 const rgb = this._rgb;
8976 const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
8977 rgb.r = rgb.g = rgb.b = val;
8978 return this;
8979 }
8980 opaquer(ratio) {
8981 const rgb = this._rgb;
8982 rgb.a *= 1 + ratio;
8983 return this;
8984 }
8985 negate() {
8986 const v = this._rgb;
8987 v.r = 255 - v.r;
8988 v.g = 255 - v.g;
8989 v.b = 255 - v.b;
8990 return this;
8991 }
8992 lighten(ratio) {
8993 modHSL(this._rgb, 2, ratio);
8994 return this;
8995 }
8996 darken(ratio) {
8997 modHSL(this._rgb, 2, -ratio);
8998 return this;
8999 }
9000 saturate(ratio) {
9001 modHSL(this._rgb, 1, ratio);
9002 return this;
9003 }
9004 desaturate(ratio) {
9005 modHSL(this._rgb, 1, -ratio);
9006 return this;
9007 }
9008 rotate(deg) {
9009 rotate(this._rgb, deg);
9010 return this;
9011 }
9012 }
9013
9014 function index_esm(input) {
9015 return new Color(input);
9016 }
9017
9018
9019
9020
9021 /***/ },
9022
9023 /***/ "./node_modules/chart.js/auto/auto.js"
9024 /*!********************************************!*\
9025 !*** ./node_modules/chart.js/auto/auto.js ***!
9026 \********************************************/
9027 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
9028
9029 "use strict";
9030 __webpack_require__.r(__webpack_exports__);
9031 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9032 /* harmony export */ Animation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animation),
9033 /* harmony export */ Animations: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animations),
9034 /* harmony export */ ArcElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ArcElement),
9035 /* harmony export */ BarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarController),
9036 /* harmony export */ BarElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarElement),
9037 /* harmony export */ BasePlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasePlatform),
9038 /* harmony export */ BasicPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasicPlatform),
9039 /* harmony export */ BubbleController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BubbleController),
9040 /* harmony export */ CategoryScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.CategoryScale),
9041 /* harmony export */ Chart: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart),
9042 /* harmony export */ Colors: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Colors),
9043 /* harmony export */ DatasetController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DatasetController),
9044 /* harmony export */ Decimation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Decimation),
9045 /* harmony export */ DomPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DomPlatform),
9046 /* harmony export */ DoughnutController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DoughnutController),
9047 /* harmony export */ Element: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Element),
9048 /* harmony export */ Filler: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Filler),
9049 /* harmony export */ Interaction: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Interaction),
9050 /* harmony export */ Legend: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Legend),
9051 /* harmony export */ LineController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineController),
9052 /* harmony export */ LineElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineElement),
9053 /* harmony export */ LinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LinearScale),
9054 /* harmony export */ LogarithmicScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LogarithmicScale),
9055 /* harmony export */ PieController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PieController),
9056 /* harmony export */ PointElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PointElement),
9057 /* harmony export */ PolarAreaController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PolarAreaController),
9058 /* harmony export */ RadarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadarController),
9059 /* harmony export */ RadialLinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadialLinearScale),
9060 /* harmony export */ Scale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Scale),
9061 /* harmony export */ ScatterController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ScatterController),
9062 /* harmony export */ SubTitle: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.SubTitle),
9063 /* harmony export */ Ticks: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Ticks),
9064 /* harmony export */ TimeScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeScale),
9065 /* harmony export */ TimeSeriesScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeSeriesScale),
9066 /* harmony export */ Title: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Title),
9067 /* harmony export */ Tooltip: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Tooltip),
9068 /* harmony export */ _adapters: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._adapters),
9069 /* harmony export */ _detectPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._detectPlatform),
9070 /* harmony export */ animator: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.animator),
9071 /* harmony export */ controllers: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.controllers),
9072 /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
9073 /* harmony export */ defaults: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.defaults),
9074 /* harmony export */ elements: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.elements),
9075 /* harmony export */ layouts: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.layouts),
9076 /* harmony export */ plugins: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.plugins),
9077 /* harmony export */ registerables: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables),
9078 /* harmony export */ registry: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registry),
9079 /* harmony export */ scales: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.scales)
9080 /* harmony export */ });
9081 /* harmony import */ var _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../dist/chart.js */ "./node_modules/chart.js/dist/chart.js");
9082
9083
9084 _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart.register(..._dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables);
9085
9086
9087 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart);
9088
9089
9090 /***/ },
9091
9092 /***/ "./node_modules/chart.js/dist/chart.js"
9093 /*!*********************************************!*\
9094 !*** ./node_modules/chart.js/dist/chart.js ***!
9095 \*********************************************/
9096 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
9097
9098 "use strict";
9099 __webpack_require__.r(__webpack_exports__);
9100 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9101 /* harmony export */ Animation: () => (/* binding */ Animation),
9102 /* harmony export */ Animations: () => (/* binding */ Animations),
9103 /* harmony export */ ArcElement: () => (/* binding */ ArcElement),
9104 /* harmony export */ BarController: () => (/* binding */ BarController),
9105 /* harmony export */ BarElement: () => (/* binding */ BarElement),
9106 /* harmony export */ BasePlatform: () => (/* binding */ BasePlatform),
9107 /* harmony export */ BasicPlatform: () => (/* binding */ BasicPlatform),
9108 /* harmony export */ BubbleController: () => (/* binding */ BubbleController),
9109 /* harmony export */ CategoryScale: () => (/* binding */ CategoryScale),
9110 /* harmony export */ Chart: () => (/* binding */ Chart),
9111 /* harmony export */ Colors: () => (/* binding */ plugin_colors),
9112 /* harmony export */ DatasetController: () => (/* binding */ DatasetController),
9113 /* harmony export */ Decimation: () => (/* binding */ plugin_decimation),
9114 /* harmony export */ DomPlatform: () => (/* binding */ DomPlatform),
9115 /* harmony export */ DoughnutController: () => (/* binding */ DoughnutController),
9116 /* harmony export */ Element: () => (/* binding */ Element),
9117 /* harmony export */ Filler: () => (/* binding */ index),
9118 /* harmony export */ Interaction: () => (/* binding */ Interaction),
9119 /* harmony export */ Legend: () => (/* binding */ plugin_legend),
9120 /* harmony export */ LineController: () => (/* binding */ LineController),
9121 /* harmony export */ LineElement: () => (/* binding */ LineElement),
9122 /* harmony export */ LinearScale: () => (/* binding */ LinearScale),
9123 /* harmony export */ LogarithmicScale: () => (/* binding */ LogarithmicScale),
9124 /* harmony export */ PieController: () => (/* binding */ PieController),
9125 /* harmony export */ PointElement: () => (/* binding */ PointElement),
9126 /* harmony export */ PolarAreaController: () => (/* binding */ PolarAreaController),
9127 /* harmony export */ RadarController: () => (/* binding */ RadarController),
9128 /* harmony export */ RadialLinearScale: () => (/* binding */ RadialLinearScale),
9129 /* harmony export */ Scale: () => (/* binding */ Scale),
9130 /* harmony export */ ScatterController: () => (/* binding */ ScatterController),
9131 /* harmony export */ SubTitle: () => (/* binding */ plugin_subtitle),
9132 /* harmony export */ Ticks: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM),
9133 /* harmony export */ TimeScale: () => (/* binding */ TimeScale),
9134 /* harmony export */ TimeSeriesScale: () => (/* binding */ TimeSeriesScale),
9135 /* harmony export */ Title: () => (/* binding */ plugin_title),
9136 /* harmony export */ Tooltip: () => (/* binding */ plugin_tooltip),
9137 /* harmony export */ _adapters: () => (/* binding */ adapters),
9138 /* harmony export */ _detectPlatform: () => (/* binding */ _detectPlatform),
9139 /* harmony export */ animator: () => (/* binding */ animator),
9140 /* harmony export */ controllers: () => (/* binding */ controllers),
9141 /* harmony export */ defaults: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d),
9142 /* harmony export */ elements: () => (/* binding */ elements),
9143 /* harmony export */ layouts: () => (/* binding */ layouts),
9144 /* harmony export */ plugins: () => (/* binding */ plugins),
9145 /* harmony export */ registerables: () => (/* binding */ registerables),
9146 /* harmony export */ registry: () => (/* binding */ registry),
9147 /* harmony export */ scales: () => (/* binding */ scales)
9148 /* harmony export */ });
9149 /* 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");
9150 /*!
9151 * Chart.js v4.5.1
9152 * https://www.chartjs.org
9153 * (c) 2025 Chart.js Contributors
9154 * Released under the MIT License
9155 */
9156
9157
9158
9159 class Animator {
9160 constructor(){
9161 this._request = null;
9162 this._charts = new Map();
9163 this._running = false;
9164 this._lastDate = undefined;
9165 }
9166 _notify(chart, anims, date, type) {
9167 const callbacks = anims.listeners[type];
9168 const numSteps = anims.duration;
9169 callbacks.forEach((fn)=>fn({
9170 chart,
9171 initial: anims.initial,
9172 numSteps,
9173 currentStep: Math.min(date - anims.start, numSteps)
9174 }));
9175 }
9176 _refresh() {
9177 if (this._request) {
9178 return;
9179 }
9180 this._running = true;
9181 this._request = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.r.call(window, ()=>{
9182 this._update();
9183 this._request = null;
9184 if (this._running) {
9185 this._refresh();
9186 }
9187 });
9188 }
9189 _update(date = Date.now()) {
9190 let remaining = 0;
9191 this._charts.forEach((anims, chart)=>{
9192 if (!anims.running || !anims.items.length) {
9193 return;
9194 }
9195 const items = anims.items;
9196 let i = items.length - 1;
9197 let draw = false;
9198 let item;
9199 for(; i >= 0; --i){
9200 item = items[i];
9201 if (item._active) {
9202 if (item._total > anims.duration) {
9203 anims.duration = item._total;
9204 }
9205 item.tick(date);
9206 draw = true;
9207 } else {
9208 items[i] = items[items.length - 1];
9209 items.pop();
9210 }
9211 }
9212 if (draw) {
9213 chart.draw();
9214 this._notify(chart, anims, date, 'progress');
9215 }
9216 if (!items.length) {
9217 anims.running = false;
9218 this._notify(chart, anims, date, 'complete');
9219 anims.initial = false;
9220 }
9221 remaining += items.length;
9222 });
9223 this._lastDate = date;
9224 if (remaining === 0) {
9225 this._running = false;
9226 }
9227 }
9228 _getAnims(chart) {
9229 const charts = this._charts;
9230 let anims = charts.get(chart);
9231 if (!anims) {
9232 anims = {
9233 running: false,
9234 initial: true,
9235 items: [],
9236 listeners: {
9237 complete: [],
9238 progress: []
9239 }
9240 };
9241 charts.set(chart, anims);
9242 }
9243 return anims;
9244 }
9245 listen(chart, event, cb) {
9246 this._getAnims(chart).listeners[event].push(cb);
9247 }
9248 add(chart, items) {
9249 if (!items || !items.length) {
9250 return;
9251 }
9252 this._getAnims(chart).items.push(...items);
9253 }
9254 has(chart) {
9255 return this._getAnims(chart).items.length > 0;
9256 }
9257 start(chart) {
9258 const anims = this._charts.get(chart);
9259 if (!anims) {
9260 return;
9261 }
9262 anims.running = true;
9263 anims.start = Date.now();
9264 anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0);
9265 this._refresh();
9266 }
9267 running(chart) {
9268 if (!this._running) {
9269 return false;
9270 }
9271 const anims = this._charts.get(chart);
9272 if (!anims || !anims.running || !anims.items.length) {
9273 return false;
9274 }
9275 return true;
9276 }
9277 stop(chart) {
9278 const anims = this._charts.get(chart);
9279 if (!anims || !anims.items.length) {
9280 return;
9281 }
9282 const items = anims.items;
9283 let i = items.length - 1;
9284 for(; i >= 0; --i){
9285 items[i].cancel();
9286 }
9287 anims.items = [];
9288 this._notify(chart, anims, Date.now(), 'complete');
9289 }
9290 remove(chart) {
9291 return this._charts.delete(chart);
9292 }
9293 }
9294 var animator = /* #__PURE__ */ new Animator();
9295
9296 const transparent = 'transparent';
9297 const interpolators = {
9298 boolean (from, to, factor) {
9299 return factor > 0.5 ? to : from;
9300 },
9301 color (from, to, factor) {
9302 const c0 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(from || transparent);
9303 const c1 = c0.valid && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(to || transparent);
9304 return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;
9305 },
9306 number (from, to, factor) {
9307 return from + (to - from) * factor;
9308 }
9309 };
9310 class Animation {
9311 constructor(cfg, target, prop, to){
9312 const currentValue = target[prop];
9313 to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9314 cfg.to,
9315 to,
9316 currentValue,
9317 cfg.from
9318 ]);
9319 const from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9320 cfg.from,
9321 currentValue,
9322 to
9323 ]);
9324 this._active = true;
9325 this._fn = cfg.fn || interpolators[cfg.type || typeof from];
9326 this._easing = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e[cfg.easing] || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e.linear;
9327 this._start = Math.floor(Date.now() + (cfg.delay || 0));
9328 this._duration = this._total = Math.floor(cfg.duration);
9329 this._loop = !!cfg.loop;
9330 this._target = target;
9331 this._prop = prop;
9332 this._from = from;
9333 this._to = to;
9334 this._promises = undefined;
9335 }
9336 active() {
9337 return this._active;
9338 }
9339 update(cfg, to, date) {
9340 if (this._active) {
9341 this._notify(false);
9342 const currentValue = this._target[this._prop];
9343 const elapsed = date - this._start;
9344 const remain = this._duration - elapsed;
9345 this._start = date;
9346 this._duration = Math.floor(Math.max(remain, cfg.duration));
9347 this._total += elapsed;
9348 this._loop = !!cfg.loop;
9349 this._to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9350 cfg.to,
9351 to,
9352 currentValue,
9353 cfg.from
9354 ]);
9355 this._from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9356 cfg.from,
9357 currentValue,
9358 to
9359 ]);
9360 }
9361 }
9362 cancel() {
9363 if (this._active) {
9364 this.tick(Date.now());
9365 this._active = false;
9366 this._notify(false);
9367 }
9368 }
9369 tick(date) {
9370 const elapsed = date - this._start;
9371 const duration = this._duration;
9372 const prop = this._prop;
9373 const from = this._from;
9374 const loop = this._loop;
9375 const to = this._to;
9376 let factor;
9377 this._active = from !== to && (loop || elapsed < duration);
9378 if (!this._active) {
9379 this._target[prop] = to;
9380 this._notify(true);
9381 return;
9382 }
9383 if (elapsed < 0) {
9384 this._target[prop] = from;
9385 return;
9386 }
9387 factor = elapsed / duration % 2;
9388 factor = loop && factor > 1 ? 2 - factor : factor;
9389 factor = this._easing(Math.min(1, Math.max(0, factor)));
9390 this._target[prop] = this._fn(from, to, factor);
9391 }
9392 wait() {
9393 const promises = this._promises || (this._promises = []);
9394 return new Promise((res, rej)=>{
9395 promises.push({
9396 res,
9397 rej
9398 });
9399 });
9400 }
9401 _notify(resolved) {
9402 const method = resolved ? 'res' : 'rej';
9403 const promises = this._promises || [];
9404 for(let i = 0; i < promises.length; i++){
9405 promises[i][method]();
9406 }
9407 }
9408 }
9409
9410 class Animations {
9411 constructor(chart, config){
9412 this._chart = chart;
9413 this._properties = new Map();
9414 this.configure(config);
9415 }
9416 configure(config) {
9417 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(config)) {
9418 return;
9419 }
9420 const animationOptions = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.animation);
9421 const animatedProps = this._properties;
9422 Object.getOwnPropertyNames(config).forEach((key)=>{
9423 const cfg = config[key];
9424 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(cfg)) {
9425 return;
9426 }
9427 const resolved = {};
9428 for (const option of animationOptions){
9429 resolved[option] = cfg[option];
9430 }
9431 ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(cfg.properties) && cfg.properties || [
9432 key
9433 ]).forEach((prop)=>{
9434 if (prop === key || !animatedProps.has(prop)) {
9435 animatedProps.set(prop, resolved);
9436 }
9437 });
9438 });
9439 }
9440 _animateOptions(target, values) {
9441 const newOptions = values.options;
9442 const options = resolveTargetOptions(target, newOptions);
9443 if (!options) {
9444 return [];
9445 }
9446 const animations = this._createAnimations(options, newOptions);
9447 if (newOptions.$shared) {
9448 awaitAll(target.options.$animations, newOptions).then(()=>{
9449 target.options = newOptions;
9450 }, ()=>{
9451 });
9452 }
9453 return animations;
9454 }
9455 _createAnimations(target, values) {
9456 const animatedProps = this._properties;
9457 const animations = [];
9458 const running = target.$animations || (target.$animations = {});
9459 const props = Object.keys(values);
9460 const date = Date.now();
9461 let i;
9462 for(i = props.length - 1; i >= 0; --i){
9463 const prop = props[i];
9464 if (prop.charAt(0) === '$') {
9465 continue;
9466 }
9467 if (prop === 'options') {
9468 animations.push(...this._animateOptions(target, values));
9469 continue;
9470 }
9471 const value = values[prop];
9472 let animation = running[prop];
9473 const cfg = animatedProps.get(prop);
9474 if (animation) {
9475 if (cfg && animation.active()) {
9476 animation.update(cfg, value, date);
9477 continue;
9478 } else {
9479 animation.cancel();
9480 }
9481 }
9482 if (!cfg || !cfg.duration) {
9483 target[prop] = value;
9484 continue;
9485 }
9486 running[prop] = animation = new Animation(cfg, target, prop, value);
9487 animations.push(animation);
9488 }
9489 return animations;
9490 }
9491 update(target, values) {
9492 if (this._properties.size === 0) {
9493 Object.assign(target, values);
9494 return;
9495 }
9496 const animations = this._createAnimations(target, values);
9497 if (animations.length) {
9498 animator.add(this._chart, animations);
9499 return true;
9500 }
9501 }
9502 }
9503 function awaitAll(animations, properties) {
9504 const running = [];
9505 const keys = Object.keys(properties);
9506 for(let i = 0; i < keys.length; i++){
9507 const anim = animations[keys[i]];
9508 if (anim && anim.active()) {
9509 running.push(anim.wait());
9510 }
9511 }
9512 return Promise.all(running);
9513 }
9514 function resolveTargetOptions(target, newOptions) {
9515 if (!newOptions) {
9516 return;
9517 }
9518 let options = target.options;
9519 if (!options) {
9520 target.options = newOptions;
9521 return;
9522 }
9523 if (options.$shared) {
9524 target.options = options = Object.assign({}, options, {
9525 $shared: false,
9526 $animations: {}
9527 });
9528 }
9529 return options;
9530 }
9531
9532 function scaleClip(scale, allowedOverflow) {
9533 const opts = scale && scale.options || {};
9534 const reverse = opts.reverse;
9535 const min = opts.min === undefined ? allowedOverflow : 0;
9536 const max = opts.max === undefined ? allowedOverflow : 0;
9537 return {
9538 start: reverse ? max : min,
9539 end: reverse ? min : max
9540 };
9541 }
9542 function defaultClip(xScale, yScale, allowedOverflow) {
9543 if (allowedOverflow === false) {
9544 return false;
9545 }
9546 const x = scaleClip(xScale, allowedOverflow);
9547 const y = scaleClip(yScale, allowedOverflow);
9548 return {
9549 top: y.end,
9550 right: x.end,
9551 bottom: y.start,
9552 left: x.start
9553 };
9554 }
9555 function toClip(value) {
9556 let t, r, b, l;
9557 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value)) {
9558 t = value.top;
9559 r = value.right;
9560 b = value.bottom;
9561 l = value.left;
9562 } else {
9563 t = r = b = l = value;
9564 }
9565 return {
9566 top: t,
9567 right: r,
9568 bottom: b,
9569 left: l,
9570 disabled: value === false
9571 };
9572 }
9573 function getSortedDatasetIndices(chart, filterVisible) {
9574 const keys = [];
9575 const metasets = chart._getSortedDatasetMetas(filterVisible);
9576 let i, ilen;
9577 for(i = 0, ilen = metasets.length; i < ilen; ++i){
9578 keys.push(metasets[i].index);
9579 }
9580 return keys;
9581 }
9582 function applyStack(stack, value, dsIndex, options = {}) {
9583 const keys = stack.keys;
9584 const singleMode = options.mode === 'single';
9585 let i, ilen, datasetIndex, otherValue;
9586 if (value === null) {
9587 return;
9588 }
9589 let found = false;
9590 for(i = 0, ilen = keys.length; i < ilen; ++i){
9591 datasetIndex = +keys[i];
9592 if (datasetIndex === dsIndex) {
9593 found = true;
9594 if (options.all) {
9595 continue;
9596 }
9597 break;
9598 }
9599 otherValue = stack.values[datasetIndex];
9600 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))) {
9601 value += otherValue;
9602 }
9603 }
9604 if (!found && !options.all) {
9605 return 0;
9606 }
9607 return value;
9608 }
9609 function convertObjectDataToArray(data, meta) {
9610 const { iScale , vScale } = meta;
9611 const iAxisKey = iScale.axis === 'x' ? 'x' : 'y';
9612 const vAxisKey = vScale.axis === 'x' ? 'x' : 'y';
9613 const keys = Object.keys(data);
9614 const adata = new Array(keys.length);
9615 let i, ilen, key;
9616 for(i = 0, ilen = keys.length; i < ilen; ++i){
9617 key = keys[i];
9618 adata[i] = {
9619 [iAxisKey]: key,
9620 [vAxisKey]: data[key]
9621 };
9622 }
9623 return adata;
9624 }
9625 function isStacked(scale, meta) {
9626 const stacked = scale && scale.options.stacked;
9627 return stacked || stacked === undefined && meta.stack !== undefined;
9628 }
9629 function getStackKey(indexScale, valueScale, meta) {
9630 return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
9631 }
9632 function getUserBounds(scale) {
9633 const { min , max , minDefined , maxDefined } = scale.getUserBounds();
9634 return {
9635 min: minDefined ? min : Number.NEGATIVE_INFINITY,
9636 max: maxDefined ? max : Number.POSITIVE_INFINITY
9637 };
9638 }
9639 function getOrCreateStack(stacks, stackKey, indexValue) {
9640 const subStack = stacks[stackKey] || (stacks[stackKey] = {});
9641 return subStack[indexValue] || (subStack[indexValue] = {});
9642 }
9643 function getLastIndexInStack(stack, vScale, positive, type) {
9644 for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){
9645 const value = stack[meta.index];
9646 if (positive && value > 0 || !positive && value < 0) {
9647 return meta.index;
9648 }
9649 }
9650 return null;
9651 }
9652 function updateStacks(controller, parsed) {
9653 const { chart , _cachedMeta: meta } = controller;
9654 const stacks = chart._stacks || (chart._stacks = {});
9655 const { iScale , vScale , index: datasetIndex } = meta;
9656 const iAxis = iScale.axis;
9657 const vAxis = vScale.axis;
9658 const key = getStackKey(iScale, vScale, meta);
9659 const ilen = parsed.length;
9660 let stack;
9661 for(let i = 0; i < ilen; ++i){
9662 const item = parsed[i];
9663 const { [iAxis]: index , [vAxis]: value } = item;
9664 const itemStacks = item._stacks || (item._stacks = {});
9665 stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
9666 stack[datasetIndex] = value;
9667 stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
9668 stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
9669 const visualValues = stack._visualValues || (stack._visualValues = {});
9670 visualValues[datasetIndex] = value;
9671 }
9672 }
9673 function getFirstScaleId(chart, axis) {
9674 const scales = chart.scales;
9675 return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift();
9676 }
9677 function createDatasetContext(parent, index) {
9678 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9679 active: false,
9680 dataset: undefined,
9681 datasetIndex: index,
9682 index,
9683 mode: 'default',
9684 type: 'dataset'
9685 });
9686 }
9687 function createDataContext(parent, index, element) {
9688 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9689 active: false,
9690 dataIndex: index,
9691 parsed: undefined,
9692 raw: undefined,
9693 element,
9694 index,
9695 mode: 'default',
9696 type: 'data'
9697 });
9698 }
9699 function clearStacks(meta, items) {
9700 const datasetIndex = meta.controller.index;
9701 const axis = meta.vScale && meta.vScale.axis;
9702 if (!axis) {
9703 return;
9704 }
9705 items = items || meta._parsed;
9706 for (const parsed of items){
9707 const stacks = parsed._stacks;
9708 if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {
9709 return;
9710 }
9711 delete stacks[axis][datasetIndex];
9712 if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) {
9713 delete stacks[axis]._visualValues[datasetIndex];
9714 }
9715 }
9716 }
9717 const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none';
9718 const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached);
9719 const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && {
9720 keys: getSortedDatasetIndices(chart, true),
9721 values: null
9722 };
9723 class DatasetController {
9724 static defaults = {};
9725 static datasetElementType = null;
9726 static dataElementType = null;
9727 constructor(chart, datasetIndex){
9728 this.chart = chart;
9729 this._ctx = chart.ctx;
9730 this.index = datasetIndex;
9731 this._cachedDataOpts = {};
9732 this._cachedMeta = this.getMeta();
9733 this._type = this._cachedMeta.type;
9734 this.options = undefined;
9735 this._parsing = false;
9736 this._data = undefined;
9737 this._objectData = undefined;
9738 this._sharedOptions = undefined;
9739 this._drawStart = undefined;
9740 this._drawCount = undefined;
9741 this.enableOptionSharing = false;
9742 this.supportsDecimation = false;
9743 this.$context = undefined;
9744 this._syncList = [];
9745 this.datasetElementType = new.target.datasetElementType;
9746 this.dataElementType = new.target.dataElementType;
9747 this.initialize();
9748 }
9749 initialize() {
9750 const meta = this._cachedMeta;
9751 this.configure();
9752 this.linkScales();
9753 meta._stacked = isStacked(meta.vScale, meta);
9754 this.addElements();
9755 if (this.options.fill && !this.chart.isPluginEnabled('filler')) {
9756 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");
9757 }
9758 }
9759 updateIndex(datasetIndex) {
9760 if (this.index !== datasetIndex) {
9761 clearStacks(this._cachedMeta);
9762 }
9763 this.index = datasetIndex;
9764 }
9765 linkScales() {
9766 const chart = this.chart;
9767 const meta = this._cachedMeta;
9768 const dataset = this.getDataset();
9769 const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y;
9770 const xid = meta.xAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.xAxisID, getFirstScaleId(chart, 'x'));
9771 const yid = meta.yAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.yAxisID, getFirstScaleId(chart, 'y'));
9772 const rid = meta.rAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.rAxisID, getFirstScaleId(chart, 'r'));
9773 const indexAxis = meta.indexAxis;
9774 const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
9775 const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
9776 meta.xScale = this.getScaleForId(xid);
9777 meta.yScale = this.getScaleForId(yid);
9778 meta.rScale = this.getScaleForId(rid);
9779 meta.iScale = this.getScaleForId(iid);
9780 meta.vScale = this.getScaleForId(vid);
9781 }
9782 getDataset() {
9783 return this.chart.data.datasets[this.index];
9784 }
9785 getMeta() {
9786 return this.chart.getDatasetMeta(this.index);
9787 }
9788 getScaleForId(scaleID) {
9789 return this.chart.scales[scaleID];
9790 }
9791 _getOtherScale(scale) {
9792 const meta = this._cachedMeta;
9793 return scale === meta.iScale ? meta.vScale : meta.iScale;
9794 }
9795 reset() {
9796 this._update('reset');
9797 }
9798 _destroy() {
9799 const meta = this._cachedMeta;
9800 if (this._data) {
9801 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(this._data, this);
9802 }
9803 if (meta._stacked) {
9804 clearStacks(meta);
9805 }
9806 }
9807 _dataCheck() {
9808 const dataset = this.getDataset();
9809 const data = dataset.data || (dataset.data = []);
9810 const _data = this._data;
9811 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data)) {
9812 const meta = this._cachedMeta;
9813 this._data = convertObjectDataToArray(data, meta);
9814 } else if (_data !== data) {
9815 if (_data) {
9816 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(_data, this);
9817 const meta = this._cachedMeta;
9818 clearStacks(meta);
9819 meta._parsed = [];
9820 }
9821 if (data && Object.isExtensible(data)) {
9822 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.l)(data, this);
9823 }
9824 this._syncList = [];
9825 this._data = data;
9826 }
9827 }
9828 addElements() {
9829 const meta = this._cachedMeta;
9830 this._dataCheck();
9831 if (this.datasetElementType) {
9832 meta.dataset = new this.datasetElementType();
9833 }
9834 }
9835 buildOrUpdateElements(resetNewElements) {
9836 const meta = this._cachedMeta;
9837 const dataset = this.getDataset();
9838 let stackChanged = false;
9839 this._dataCheck();
9840 const oldStacked = meta._stacked;
9841 meta._stacked = isStacked(meta.vScale, meta);
9842 if (meta.stack !== dataset.stack) {
9843 stackChanged = true;
9844 clearStacks(meta);
9845 meta.stack = dataset.stack;
9846 }
9847 this._resyncElements(resetNewElements);
9848 if (stackChanged || oldStacked !== meta._stacked) {
9849 updateStacks(this, meta._parsed);
9850 meta._stacked = isStacked(meta.vScale, meta);
9851 }
9852 }
9853 configure() {
9854 const config = this.chart.config;
9855 const scopeKeys = config.datasetScopeKeys(this._type);
9856 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
9857 this.options = config.createResolver(scopes, this.getContext());
9858 this._parsing = this.options.parsing;
9859 this._cachedDataOpts = {};
9860 }
9861 parse(start, count) {
9862 const { _cachedMeta: meta , _data: data } = this;
9863 const { iScale , _stacked } = meta;
9864 const iAxis = iScale.axis;
9865 let sorted = start === 0 && count === data.length ? true : meta._sorted;
9866 let prev = start > 0 && meta._parsed[start - 1];
9867 let i, cur, parsed;
9868 if (this._parsing === false) {
9869 meta._parsed = data;
9870 meta._sorted = true;
9871 parsed = data;
9872 } else {
9873 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(data[start])) {
9874 parsed = this.parseArrayData(meta, data, start, count);
9875 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
9876 parsed = this.parseObjectData(meta, data, start, count);
9877 } else {
9878 parsed = this.parsePrimitiveData(meta, data, start, count);
9879 }
9880 const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];
9881 for(i = 0; i < count; ++i){
9882 meta._parsed[i + start] = cur = parsed[i];
9883 if (sorted) {
9884 if (isNotInOrderComparedToPrev()) {
9885 sorted = false;
9886 }
9887 prev = cur;
9888 }
9889 }
9890 meta._sorted = sorted;
9891 }
9892 if (_stacked) {
9893 updateStacks(this, parsed);
9894 }
9895 }
9896 parsePrimitiveData(meta, data, start, count) {
9897 const { iScale , vScale } = meta;
9898 const iAxis = iScale.axis;
9899 const vAxis = vScale.axis;
9900 const labels = iScale.getLabels();
9901 const singleScale = iScale === vScale;
9902 const parsed = new Array(count);
9903 let i, ilen, index;
9904 for(i = 0, ilen = count; i < ilen; ++i){
9905 index = i + start;
9906 parsed[i] = {
9907 [iAxis]: singleScale || iScale.parse(labels[index], index),
9908 [vAxis]: vScale.parse(data[index], index)
9909 };
9910 }
9911 return parsed;
9912 }
9913 parseArrayData(meta, data, start, count) {
9914 const { xScale , yScale } = meta;
9915 const parsed = new Array(count);
9916 let i, ilen, index, item;
9917 for(i = 0, ilen = count; i < ilen; ++i){
9918 index = i + start;
9919 item = data[index];
9920 parsed[i] = {
9921 x: xScale.parse(item[0], index),
9922 y: yScale.parse(item[1], index)
9923 };
9924 }
9925 return parsed;
9926 }
9927 parseObjectData(meta, data, start, count) {
9928 const { xScale , yScale } = meta;
9929 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
9930 const parsed = new Array(count);
9931 let i, ilen, index, item;
9932 for(i = 0, ilen = count; i < ilen; ++i){
9933 index = i + start;
9934 item = data[index];
9935 parsed[i] = {
9936 x: xScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, xAxisKey), index),
9937 y: yScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, yAxisKey), index)
9938 };
9939 }
9940 return parsed;
9941 }
9942 getParsed(index) {
9943 return this._cachedMeta._parsed[index];
9944 }
9945 getDataElement(index) {
9946 return this._cachedMeta.data[index];
9947 }
9948 applyStack(scale, parsed, mode) {
9949 const chart = this.chart;
9950 const meta = this._cachedMeta;
9951 const value = parsed[scale.axis];
9952 const stack = {
9953 keys: getSortedDatasetIndices(chart, true),
9954 values: parsed._stacks[scale.axis]._visualValues
9955 };
9956 return applyStack(stack, value, meta.index, {
9957 mode
9958 });
9959 }
9960 updateRangeFromParsed(range, scale, parsed, stack) {
9961 const parsedValue = parsed[scale.axis];
9962 let value = parsedValue === null ? NaN : parsedValue;
9963 const values = stack && parsed._stacks[scale.axis];
9964 if (stack && values) {
9965 stack.values = values;
9966 value = applyStack(stack, parsedValue, this._cachedMeta.index);
9967 }
9968 range.min = Math.min(range.min, value);
9969 range.max = Math.max(range.max, value);
9970 }
9971 getMinMax(scale, canStack) {
9972 const meta = this._cachedMeta;
9973 const _parsed = meta._parsed;
9974 const sorted = meta._sorted && scale === meta.iScale;
9975 const ilen = _parsed.length;
9976 const otherScale = this._getOtherScale(scale);
9977 const stack = createStack(canStack, meta, this.chart);
9978 const range = {
9979 min: Number.POSITIVE_INFINITY,
9980 max: Number.NEGATIVE_INFINITY
9981 };
9982 const { min: otherMin , max: otherMax } = getUserBounds(otherScale);
9983 let i, parsed;
9984 function _skip() {
9985 parsed = _parsed[i];
9986 const otherValue = parsed[otherScale.axis];
9987 return !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
9988 }
9989 for(i = 0; i < ilen; ++i){
9990 if (_skip()) {
9991 continue;
9992 }
9993 this.updateRangeFromParsed(range, scale, parsed, stack);
9994 if (sorted) {
9995 break;
9996 }
9997 }
9998 if (sorted) {
9999 for(i = ilen - 1; i >= 0; --i){
10000 if (_skip()) {
10001 continue;
10002 }
10003 this.updateRangeFromParsed(range, scale, parsed, stack);
10004 break;
10005 }
10006 }
10007 return range;
10008 }
10009 getAllParsedValues(scale) {
10010 const parsed = this._cachedMeta._parsed;
10011 const values = [];
10012 let i, ilen, value;
10013 for(i = 0, ilen = parsed.length; i < ilen; ++i){
10014 value = parsed[i][scale.axis];
10015 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
10016 values.push(value);
10017 }
10018 }
10019 return values;
10020 }
10021 getMaxOverflow() {
10022 return false;
10023 }
10024 getLabelAndValue(index) {
10025 const meta = this._cachedMeta;
10026 const iScale = meta.iScale;
10027 const vScale = meta.vScale;
10028 const parsed = this.getParsed(index);
10029 return {
10030 label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
10031 value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
10032 };
10033 }
10034 _update(mode) {
10035 const meta = this._cachedMeta;
10036 this.update(mode || 'default');
10037 meta._clip = toClip((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
10038 }
10039 update(mode) {}
10040 draw() {
10041 const ctx = this._ctx;
10042 const chart = this.chart;
10043 const meta = this._cachedMeta;
10044 const elements = meta.data || [];
10045 const area = chart.chartArea;
10046 const active = [];
10047 const start = this._drawStart || 0;
10048 const count = this._drawCount || elements.length - start;
10049 const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
10050 let i;
10051 if (meta.dataset) {
10052 meta.dataset.draw(ctx, area, start, count);
10053 }
10054 for(i = start; i < start + count; ++i){
10055 const element = elements[i];
10056 if (element.hidden) {
10057 continue;
10058 }
10059 if (element.active && drawActiveElementsOnTop) {
10060 active.push(element);
10061 } else {
10062 element.draw(ctx, area);
10063 }
10064 }
10065 for(i = 0; i < active.length; ++i){
10066 active[i].draw(ctx, area);
10067 }
10068 }
10069 getStyle(index, active) {
10070 const mode = active ? 'active' : 'default';
10071 return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);
10072 }
10073 getContext(index, active, mode) {
10074 const dataset = this.getDataset();
10075 let context;
10076 if (index >= 0 && index < this._cachedMeta.data.length) {
10077 const element = this._cachedMeta.data[index];
10078 context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));
10079 context.parsed = this.getParsed(index);
10080 context.raw = dataset.data[index];
10081 context.index = context.dataIndex = index;
10082 } else {
10083 context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));
10084 context.dataset = dataset;
10085 context.index = context.datasetIndex = this.index;
10086 }
10087 context.active = !!active;
10088 context.mode = mode;
10089 return context;
10090 }
10091 resolveDatasetElementOptions(mode) {
10092 return this._resolveElementOptions(this.datasetElementType.id, mode);
10093 }
10094 resolveDataElementOptions(index, mode) {
10095 return this._resolveElementOptions(this.dataElementType.id, mode, index);
10096 }
10097 _resolveElementOptions(elementType, mode = 'default', index) {
10098 const active = mode === 'active';
10099 const cache = this._cachedDataOpts;
10100 const cacheKey = elementType + '-' + mode;
10101 const cached = cache[cacheKey];
10102 const sharing = this.enableOptionSharing && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(index);
10103 if (cached) {
10104 return cloneIfNotShared(cached, sharing);
10105 }
10106 const config = this.chart.config;
10107 const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
10108 const prefixes = active ? [
10109 `${elementType}Hover`,
10110 'hover',
10111 elementType,
10112 ''
10113 ] : [
10114 elementType,
10115 ''
10116 ];
10117 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
10118 const names = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.elements[elementType]);
10119 const context = ()=>this.getContext(index, active, mode);
10120 const values = config.resolveNamedOptions(scopes, names, context, prefixes);
10121 if (values.$shared) {
10122 values.$shared = sharing;
10123 cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
10124 }
10125 return values;
10126 }
10127 _resolveAnimations(index, transition, active) {
10128 const chart = this.chart;
10129 const cache = this._cachedDataOpts;
10130 const cacheKey = `animation-${transition}`;
10131 const cached = cache[cacheKey];
10132 if (cached) {
10133 return cached;
10134 }
10135 let options;
10136 if (chart.options.animation !== false) {
10137 const config = this.chart.config;
10138 const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
10139 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
10140 options = config.createResolver(scopes, this.getContext(index, active, transition));
10141 }
10142 const animations = new Animations(chart, options && options.animations);
10143 if (options && options._cacheable) {
10144 cache[cacheKey] = Object.freeze(animations);
10145 }
10146 return animations;
10147 }
10148 getSharedOptions(options) {
10149 if (!options.$shared) {
10150 return;
10151 }
10152 return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
10153 }
10154 includeOptions(mode, sharedOptions) {
10155 return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
10156 }
10157 _getSharedOptions(start, mode) {
10158 const firstOpts = this.resolveDataElementOptions(start, mode);
10159 const previouslySharedOptions = this._sharedOptions;
10160 const sharedOptions = this.getSharedOptions(firstOpts);
10161 const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;
10162 this.updateSharedOptions(sharedOptions, mode, firstOpts);
10163 return {
10164 sharedOptions,
10165 includeOptions
10166 };
10167 }
10168 updateElement(element, index, properties, mode) {
10169 if (isDirectUpdateMode(mode)) {
10170 Object.assign(element, properties);
10171 } else {
10172 this._resolveAnimations(index, mode).update(element, properties);
10173 }
10174 }
10175 updateSharedOptions(sharedOptions, mode, newOptions) {
10176 if (sharedOptions && !isDirectUpdateMode(mode)) {
10177 this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);
10178 }
10179 }
10180 _setStyle(element, index, mode, active) {
10181 element.active = active;
10182 const options = this.getStyle(index, active);
10183 this._resolveAnimations(index, mode, active).update(element, {
10184 options: !active && this.getSharedOptions(options) || options
10185 });
10186 }
10187 removeHoverStyle(element, datasetIndex, index) {
10188 this._setStyle(element, index, 'active', false);
10189 }
10190 setHoverStyle(element, datasetIndex, index) {
10191 this._setStyle(element, index, 'active', true);
10192 }
10193 _removeDatasetHoverStyle() {
10194 const element = this._cachedMeta.dataset;
10195 if (element) {
10196 this._setStyle(element, undefined, 'active', false);
10197 }
10198 }
10199 _setDatasetHoverStyle() {
10200 const element = this._cachedMeta.dataset;
10201 if (element) {
10202 this._setStyle(element, undefined, 'active', true);
10203 }
10204 }
10205 _resyncElements(resetNewElements) {
10206 const data = this._data;
10207 const elements = this._cachedMeta.data;
10208 for (const [method, arg1, arg2] of this._syncList){
10209 this[method](arg1, arg2);
10210 }
10211 this._syncList = [];
10212 const numMeta = elements.length;
10213 const numData = data.length;
10214 const count = Math.min(numData, numMeta);
10215 if (count) {
10216 this.parse(0, count);
10217 }
10218 if (numData > numMeta) {
10219 this._insertElements(numMeta, numData - numMeta, resetNewElements);
10220 } else if (numData < numMeta) {
10221 this._removeElements(numData, numMeta - numData);
10222 }
10223 }
10224 _insertElements(start, count, resetNewElements = true) {
10225 const meta = this._cachedMeta;
10226 const data = meta.data;
10227 const end = start + count;
10228 let i;
10229 const move = (arr)=>{
10230 arr.length += count;
10231 for(i = arr.length - 1; i >= end; i--){
10232 arr[i] = arr[i - count];
10233 }
10234 };
10235 move(data);
10236 for(i = start; i < end; ++i){
10237 data[i] = new this.dataElementType();
10238 }
10239 if (this._parsing) {
10240 move(meta._parsed);
10241 }
10242 this.parse(start, count);
10243 if (resetNewElements) {
10244 this.updateElements(data, start, count, 'reset');
10245 }
10246 }
10247 updateElements(element, start, count, mode) {}
10248 _removeElements(start, count) {
10249 const meta = this._cachedMeta;
10250 if (this._parsing) {
10251 const removed = meta._parsed.splice(start, count);
10252 if (meta._stacked) {
10253 clearStacks(meta, removed);
10254 }
10255 }
10256 meta.data.splice(start, count);
10257 }
10258 _sync(args) {
10259 if (this._parsing) {
10260 this._syncList.push(args);
10261 } else {
10262 const [method, arg1, arg2] = args;
10263 this[method](arg1, arg2);
10264 }
10265 this.chart._dataChanges.push([
10266 this.index,
10267 ...args
10268 ]);
10269 }
10270 _onDataPush() {
10271 const count = arguments.length;
10272 this._sync([
10273 '_insertElements',
10274 this.getDataset().data.length - count,
10275 count
10276 ]);
10277 }
10278 _onDataPop() {
10279 this._sync([
10280 '_removeElements',
10281 this._cachedMeta.data.length - 1,
10282 1
10283 ]);
10284 }
10285 _onDataShift() {
10286 this._sync([
10287 '_removeElements',
10288 0,
10289 1
10290 ]);
10291 }
10292 _onDataSplice(start, count) {
10293 if (count) {
10294 this._sync([
10295 '_removeElements',
10296 start,
10297 count
10298 ]);
10299 }
10300 const newCount = arguments.length - 2;
10301 if (newCount) {
10302 this._sync([
10303 '_insertElements',
10304 start,
10305 newCount
10306 ]);
10307 }
10308 }
10309 _onDataUnshift() {
10310 this._sync([
10311 '_insertElements',
10312 0,
10313 arguments.length
10314 ]);
10315 }
10316 }
10317
10318 function getAllScaleValues(scale, type) {
10319 if (!scale._cache.$bar) {
10320 const visibleMetas = scale.getMatchingVisibleMetas(type);
10321 let values = [];
10322 for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){
10323 values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));
10324 }
10325 scale._cache.$bar = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort((a, b)=>a - b));
10326 }
10327 return scale._cache.$bar;
10328 }
10329 function computeMinSampleSize(meta) {
10330 const scale = meta.iScale;
10331 const values = getAllScaleValues(scale, meta.type);
10332 let min = scale._length;
10333 let i, ilen, curr, prev;
10334 const updateMinAndPrev = ()=>{
10335 if (curr === 32767 || curr === -32768) {
10336 return;
10337 }
10338 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(prev)) {
10339 min = Math.min(min, Math.abs(curr - prev) || min);
10340 }
10341 prev = curr;
10342 };
10343 for(i = 0, ilen = values.length; i < ilen; ++i){
10344 curr = scale.getPixelForValue(values[i]);
10345 updateMinAndPrev();
10346 }
10347 prev = undefined;
10348 for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){
10349 curr = scale.getPixelForTick(i);
10350 updateMinAndPrev();
10351 }
10352 return min;
10353 }
10354 function computeFitCategoryTraits(index, ruler, options, stackCount) {
10355 const thickness = options.barThickness;
10356 let size, ratio;
10357 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(thickness)) {
10358 size = ruler.min * options.categoryPercentage;
10359 ratio = options.barPercentage;
10360 } else {
10361 size = thickness * stackCount;
10362 ratio = 1;
10363 }
10364 return {
10365 chunk: size / stackCount,
10366 ratio,
10367 start: ruler.pixels[index] - size / 2
10368 };
10369 }
10370 function computeFlexCategoryTraits(index, ruler, options, stackCount) {
10371 const pixels = ruler.pixels;
10372 const curr = pixels[index];
10373 let prev = index > 0 ? pixels[index - 1] : null;
10374 let next = index < pixels.length - 1 ? pixels[index + 1] : null;
10375 const percent = options.categoryPercentage;
10376 if (prev === null) {
10377 prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
10378 }
10379 if (next === null) {
10380 next = curr + curr - prev;
10381 }
10382 const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
10383 const size = Math.abs(next - prev) / 2 * percent;
10384 return {
10385 chunk: size / stackCount,
10386 ratio: options.barPercentage,
10387 start
10388 };
10389 }
10390 function parseFloatBar(entry, item, vScale, i) {
10391 const startValue = vScale.parse(entry[0], i);
10392 const endValue = vScale.parse(entry[1], i);
10393 const min = Math.min(startValue, endValue);
10394 const max = Math.max(startValue, endValue);
10395 let barStart = min;
10396 let barEnd = max;
10397 if (Math.abs(min) > Math.abs(max)) {
10398 barStart = max;
10399 barEnd = min;
10400 }
10401 item[vScale.axis] = barEnd;
10402 item._custom = {
10403 barStart,
10404 barEnd,
10405 start: startValue,
10406 end: endValue,
10407 min,
10408 max
10409 };
10410 }
10411 function parseValue(entry, item, vScale, i) {
10412 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(entry)) {
10413 parseFloatBar(entry, item, vScale, i);
10414 } else {
10415 item[vScale.axis] = vScale.parse(entry, i);
10416 }
10417 return item;
10418 }
10419 function parseArrayOrPrimitive(meta, data, start, count) {
10420 const iScale = meta.iScale;
10421 const vScale = meta.vScale;
10422 const labels = iScale.getLabels();
10423 const singleScale = iScale === vScale;
10424 const parsed = [];
10425 let i, ilen, item, entry;
10426 for(i = start, ilen = start + count; i < ilen; ++i){
10427 entry = data[i];
10428 item = {};
10429 item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
10430 parsed.push(parseValue(entry, item, vScale, i));
10431 }
10432 return parsed;
10433 }
10434 function isFloatBar(custom) {
10435 return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
10436 }
10437 function barSign(size, vScale, actualBase) {
10438 if (size !== 0) {
10439 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size);
10440 }
10441 return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
10442 }
10443 function borderProps(properties) {
10444 let reverse, start, end, top, bottom;
10445 if (properties.horizontal) {
10446 reverse = properties.base > properties.x;
10447 start = 'left';
10448 end = 'right';
10449 } else {
10450 reverse = properties.base < properties.y;
10451 start = 'bottom';
10452 end = 'top';
10453 }
10454 if (reverse) {
10455 top = 'end';
10456 bottom = 'start';
10457 } else {
10458 top = 'start';
10459 bottom = 'end';
10460 }
10461 return {
10462 start,
10463 end,
10464 reverse,
10465 top,
10466 bottom
10467 };
10468 }
10469 function setBorderSkipped(properties, options, stack, index) {
10470 let edge = options.borderSkipped;
10471 const res = {};
10472 if (!edge) {
10473 properties.borderSkipped = res;
10474 return;
10475 }
10476 if (edge === true) {
10477 properties.borderSkipped = {
10478 top: true,
10479 right: true,
10480 bottom: true,
10481 left: true
10482 };
10483 return;
10484 }
10485 const { start , end , reverse , top , bottom } = borderProps(properties);
10486 if (edge === 'middle' && stack) {
10487 properties.enableBorderRadius = true;
10488 if ((stack._top || 0) === index) {
10489 edge = top;
10490 } else if ((stack._bottom || 0) === index) {
10491 edge = bottom;
10492 } else {
10493 res[parseEdge(bottom, start, end, reverse)] = true;
10494 edge = top;
10495 }
10496 }
10497 res[parseEdge(edge, start, end, reverse)] = true;
10498 properties.borderSkipped = res;
10499 }
10500 function parseEdge(edge, a, b, reverse) {
10501 if (reverse) {
10502 edge = swap(edge, a, b);
10503 edge = startEnd(edge, b, a);
10504 } else {
10505 edge = startEnd(edge, a, b);
10506 }
10507 return edge;
10508 }
10509 function swap(orig, v1, v2) {
10510 return orig === v1 ? v2 : orig === v2 ? v1 : orig;
10511 }
10512 function startEnd(v, start, end) {
10513 return v === 'start' ? start : v === 'end' ? end : v;
10514 }
10515 function setInflateAmount(properties, { inflateAmount }, ratio) {
10516 properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount;
10517 }
10518 class BarController extends DatasetController {
10519 static id = 'bar';
10520 static defaults = {
10521 datasetElementType: false,
10522 dataElementType: 'bar',
10523 categoryPercentage: 0.8,
10524 barPercentage: 0.9,
10525 grouped: true,
10526 animations: {
10527 numbers: {
10528 type: 'number',
10529 properties: [
10530 'x',
10531 'y',
10532 'base',
10533 'width',
10534 'height'
10535 ]
10536 }
10537 }
10538 };
10539 static overrides = {
10540 scales: {
10541 _index_: {
10542 type: 'category',
10543 offset: true,
10544 grid: {
10545 offset: true
10546 }
10547 },
10548 _value_: {
10549 type: 'linear',
10550 beginAtZero: true
10551 }
10552 }
10553 };
10554 parsePrimitiveData(meta, data, start, count) {
10555 return parseArrayOrPrimitive(meta, data, start, count);
10556 }
10557 parseArrayData(meta, data, start, count) {
10558 return parseArrayOrPrimitive(meta, data, start, count);
10559 }
10560 parseObjectData(meta, data, start, count) {
10561 const { iScale , vScale } = meta;
10562 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
10563 const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
10564 const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
10565 const parsed = [];
10566 let i, ilen, item, obj;
10567 for(i = start, ilen = start + count; i < ilen; ++i){
10568 obj = data[i];
10569 item = {};
10570 item[iScale.axis] = iScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, iAxisKey), i);
10571 parsed.push(parseValue((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, vAxisKey), item, vScale, i));
10572 }
10573 return parsed;
10574 }
10575 updateRangeFromParsed(range, scale, parsed, stack) {
10576 super.updateRangeFromParsed(range, scale, parsed, stack);
10577 const custom = parsed._custom;
10578 if (custom && scale === this._cachedMeta.vScale) {
10579 range.min = Math.min(range.min, custom.min);
10580 range.max = Math.max(range.max, custom.max);
10581 }
10582 }
10583 getMaxOverflow() {
10584 return 0;
10585 }
10586 getLabelAndValue(index) {
10587 const meta = this._cachedMeta;
10588 const { iScale , vScale } = meta;
10589 const parsed = this.getParsed(index);
10590 const custom = parsed._custom;
10591 const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]);
10592 return {
10593 label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
10594 value
10595 };
10596 }
10597 initialize() {
10598 this.enableOptionSharing = true;
10599 super.initialize();
10600 const meta = this._cachedMeta;
10601 meta.stack = this.getDataset().stack;
10602 }
10603 update(mode) {
10604 const meta = this._cachedMeta;
10605 this.updateElements(meta.data, 0, meta.data.length, mode);
10606 }
10607 updateElements(bars, start, count, mode) {
10608 const reset = mode === 'reset';
10609 const { index , _cachedMeta: { vScale } } = this;
10610 const base = vScale.getBasePixel();
10611 const horizontal = vScale.isHorizontal();
10612 const ruler = this._getRuler();
10613 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10614 for(let i = start; i < start + count; i++){
10615 const parsed = this.getParsed(i);
10616 const vpixels = reset || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vScale.axis]) ? {
10617 base,
10618 head: base
10619 } : this._calculateBarValuePixels(i);
10620 const ipixels = this._calculateBarIndexPixels(i, ruler);
10621 const stack = (parsed._stacks || {})[vScale.axis];
10622 const properties = {
10623 horizontal,
10624 base: vpixels.base,
10625 enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,
10626 x: horizontal ? vpixels.head : ipixels.center,
10627 y: horizontal ? ipixels.center : vpixels.head,
10628 height: horizontal ? ipixels.size : Math.abs(vpixels.size),
10629 width: horizontal ? Math.abs(vpixels.size) : ipixels.size
10630 };
10631 if (includeOptions) {
10632 properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);
10633 }
10634 const options = properties.options || bars[i].options;
10635 setBorderSkipped(properties, options, stack, index);
10636 setInflateAmount(properties, options, ruler.ratio);
10637 this.updateElement(bars[i], i, properties, mode);
10638 }
10639 }
10640 _getStacks(last, dataIndex) {
10641 const { iScale } = this._cachedMeta;
10642 const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped);
10643 const stacked = iScale.options.stacked;
10644 const stacks = [];
10645 const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);
10646 const iScaleValue = currentParsed && currentParsed[iScale.axis];
10647 const skipNull = (meta)=>{
10648 const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue);
10649 const val = parsed && parsed[meta.vScale.axis];
10650 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(val) || isNaN(val)) {
10651 return true;
10652 }
10653 };
10654 for (const meta of metasets){
10655 if (dataIndex !== undefined && skipNull(meta)) {
10656 continue;
10657 }
10658 if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) {
10659 stacks.push(meta.stack);
10660 }
10661 if (meta.index === last) {
10662 break;
10663 }
10664 }
10665 if (!stacks.length) {
10666 stacks.push(undefined);
10667 }
10668 return stacks;
10669 }
10670 _getStackCount(index) {
10671 return this._getStacks(undefined, index).length;
10672 }
10673 _getAxisCount() {
10674 return this._getAxis().length;
10675 }
10676 getFirstScaleIdForIndexAxis() {
10677 const scales = this.chart.scales;
10678 const indexScaleId = this.chart.options.indexAxis;
10679 return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift();
10680 }
10681 _getAxis() {
10682 const axis = {};
10683 const firstScaleAxisId = this.getFirstScaleIdForIndexAxis();
10684 for (const dataset of this.chart.data.datasets){
10685 axis[(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true;
10686 }
10687 return Object.keys(axis);
10688 }
10689 _getStackIndex(datasetIndex, name, dataIndex) {
10690 const stacks = this._getStacks(datasetIndex, dataIndex);
10691 const index = name !== undefined ? stacks.indexOf(name) : -1;
10692 return index === -1 ? stacks.length - 1 : index;
10693 }
10694 _getRuler() {
10695 const opts = this.options;
10696 const meta = this._cachedMeta;
10697 const iScale = meta.iScale;
10698 const pixels = [];
10699 let i, ilen;
10700 for(i = 0, ilen = meta.data.length; i < ilen; ++i){
10701 pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));
10702 }
10703 const barThickness = opts.barThickness;
10704 const min = barThickness || computeMinSampleSize(meta);
10705 return {
10706 min,
10707 pixels,
10708 start: iScale._startPixel,
10709 end: iScale._endPixel,
10710 stackCount: this._getStackCount(),
10711 scale: iScale,
10712 grouped: opts.grouped,
10713 ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
10714 };
10715 }
10716 _calculateBarValuePixels(index) {
10717 const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this;
10718 const actualBase = baseValue || 0;
10719 const parsed = this.getParsed(index);
10720 const custom = parsed._custom;
10721 const floating = isFloatBar(custom);
10722 let value = parsed[vScale.axis];
10723 let start = 0;
10724 let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
10725 let head, size;
10726 if (length !== value) {
10727 start = length - value;
10728 length = value;
10729 }
10730 if (floating) {
10731 value = custom.barStart;
10732 length = custom.barEnd - custom.barStart;
10733 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)) {
10734 start = 0;
10735 }
10736 start += value;
10737 }
10738 const startValue = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(baseValue) && !floating ? baseValue : start;
10739 let base = vScale.getPixelForValue(startValue);
10740 if (this.chart.getDataVisibility(index)) {
10741 head = vScale.getPixelForValue(start + length);
10742 } else {
10743 head = base;
10744 }
10745 size = head - base;
10746 if (Math.abs(size) < minBarLength) {
10747 size = barSign(size, vScale, actualBase) * minBarLength;
10748 if (value === actualBase) {
10749 base -= size / 2;
10750 }
10751 const startPixel = vScale.getPixelForDecimal(0);
10752 const endPixel = vScale.getPixelForDecimal(1);
10753 const min = Math.min(startPixel, endPixel);
10754 const max = Math.max(startPixel, endPixel);
10755 base = Math.max(Math.min(base, max), min);
10756 head = base + size;
10757 if (_stacked && !floating) {
10758 parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);
10759 }
10760 }
10761 if (base === vScale.getPixelForValue(actualBase)) {
10762 const halfGrid = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size) * vScale.getLineWidthForValue(actualBase) / 2;
10763 base += halfGrid;
10764 size -= halfGrid;
10765 }
10766 return {
10767 size,
10768 base,
10769 head,
10770 center: head + size / 2
10771 };
10772 }
10773 _calculateBarIndexPixels(index, ruler) {
10774 const scale = ruler.scale;
10775 const options = this.options;
10776 const skipNull = options.skipNull;
10777 const maxBarThickness = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.maxBarThickness, Infinity);
10778 let center, size;
10779 const axisCount = this._getAxisCount();
10780 if (ruler.grouped) {
10781 const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
10782 const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount);
10783 const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID;
10784 const axisNumber = this._getAxis().indexOf((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(axisID, this.getFirstScaleIdForIndexAxis()));
10785 const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber;
10786 center = range.start + range.chunk * stackIndex + range.chunk / 2;
10787 size = Math.min(maxBarThickness, range.chunk * range.ratio);
10788 } else {
10789 center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
10790 size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
10791 }
10792 return {
10793 base: center - size / 2,
10794 head: center + size / 2,
10795 center,
10796 size
10797 };
10798 }
10799 draw() {
10800 const meta = this._cachedMeta;
10801 const vScale = meta.vScale;
10802 const rects = meta.data;
10803 const ilen = rects.length;
10804 let i = 0;
10805 for(; i < ilen; ++i){
10806 if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) {
10807 rects[i].draw(this._ctx);
10808 }
10809 }
10810 }
10811 }
10812
10813 class BubbleController extends DatasetController {
10814 static id = 'bubble';
10815 static defaults = {
10816 datasetElementType: false,
10817 dataElementType: 'point',
10818 animations: {
10819 numbers: {
10820 type: 'number',
10821 properties: [
10822 'x',
10823 'y',
10824 'borderWidth',
10825 'radius'
10826 ]
10827 }
10828 }
10829 };
10830 static overrides = {
10831 scales: {
10832 x: {
10833 type: 'linear'
10834 },
10835 y: {
10836 type: 'linear'
10837 }
10838 }
10839 };
10840 initialize() {
10841 this.enableOptionSharing = true;
10842 super.initialize();
10843 }
10844 parsePrimitiveData(meta, data, start, count) {
10845 const parsed = super.parsePrimitiveData(meta, data, start, count);
10846 for(let i = 0; i < parsed.length; i++){
10847 parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;
10848 }
10849 return parsed;
10850 }
10851 parseArrayData(meta, data, start, count) {
10852 const parsed = super.parseArrayData(meta, data, start, count);
10853 for(let i = 0; i < parsed.length; i++){
10854 const item = data[start + i];
10855 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item[2], this.resolveDataElementOptions(i + start).radius);
10856 }
10857 return parsed;
10858 }
10859 parseObjectData(meta, data, start, count) {
10860 const parsed = super.parseObjectData(meta, data, start, count);
10861 for(let i = 0; i < parsed.length; i++){
10862 const item = data[start + i];
10863 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);
10864 }
10865 return parsed;
10866 }
10867 getMaxOverflow() {
10868 const data = this._cachedMeta.data;
10869 let max = 0;
10870 for(let i = data.length - 1; i >= 0; --i){
10871 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
10872 }
10873 return max > 0 && max;
10874 }
10875 getLabelAndValue(index) {
10876 const meta = this._cachedMeta;
10877 const labels = this.chart.data.labels || [];
10878 const { xScale , yScale } = meta;
10879 const parsed = this.getParsed(index);
10880 const x = xScale.getLabelForValue(parsed.x);
10881 const y = yScale.getLabelForValue(parsed.y);
10882 const r = parsed._custom;
10883 return {
10884 label: labels[index] || '',
10885 value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
10886 };
10887 }
10888 update(mode) {
10889 const points = this._cachedMeta.data;
10890 this.updateElements(points, 0, points.length, mode);
10891 }
10892 updateElements(points, start, count, mode) {
10893 const reset = mode === 'reset';
10894 const { iScale , vScale } = this._cachedMeta;
10895 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10896 const iAxis = iScale.axis;
10897 const vAxis = vScale.axis;
10898 for(let i = start; i < start + count; i++){
10899 const point = points[i];
10900 const parsed = !reset && this.getParsed(i);
10901 const properties = {};
10902 const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);
10903 const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);
10904 properties.skip = isNaN(iPixel) || isNaN(vPixel);
10905 if (includeOptions) {
10906 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
10907 if (reset) {
10908 properties.options.radius = 0;
10909 }
10910 }
10911 this.updateElement(point, i, properties, mode);
10912 }
10913 }
10914 resolveDataElementOptions(index, mode) {
10915 const parsed = this.getParsed(index);
10916 let values = super.resolveDataElementOptions(index, mode);
10917 if (values.$shared) {
10918 values = Object.assign({}, values, {
10919 $shared: false
10920 });
10921 }
10922 const radius = values.radius;
10923 if (mode !== 'active') {
10924 values.radius = 0;
10925 }
10926 values.radius += (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(parsed && parsed._custom, radius);
10927 return values;
10928 }
10929 }
10930
10931 function getRatioAndOffset(rotation, circumference, cutout) {
10932 let ratioX = 1;
10933 let ratioY = 1;
10934 let offsetX = 0;
10935 let offsetY = 0;
10936 if (circumference < _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) {
10937 const startAngle = rotation;
10938 const endAngle = startAngle + circumference;
10939 const startX = Math.cos(startAngle);
10940 const startY = Math.sin(startAngle);
10941 const endX = Math.cos(endAngle);
10942 const endY = Math.sin(endAngle);
10943 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);
10944 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);
10945 const maxX = calcMax(0, startX, endX);
10946 const maxY = calcMax(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10947 const minX = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, startX, endX);
10948 const minY = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10949 ratioX = (maxX - minX) / 2;
10950 ratioY = (maxY - minY) / 2;
10951 offsetX = -(maxX + minX) / 2;
10952 offsetY = -(maxY + minY) / 2;
10953 }
10954 return {
10955 ratioX,
10956 ratioY,
10957 offsetX,
10958 offsetY
10959 };
10960 }
10961 class DoughnutController extends DatasetController {
10962 static id = 'doughnut';
10963 static defaults = {
10964 datasetElementType: false,
10965 dataElementType: 'arc',
10966 animation: {
10967 animateRotate: true,
10968 animateScale: false
10969 },
10970 animations: {
10971 numbers: {
10972 type: 'number',
10973 properties: [
10974 'circumference',
10975 'endAngle',
10976 'innerRadius',
10977 'outerRadius',
10978 'startAngle',
10979 'x',
10980 'y',
10981 'offset',
10982 'borderWidth',
10983 'spacing'
10984 ]
10985 }
10986 },
10987 cutout: '50%',
10988 rotation: 0,
10989 circumference: 360,
10990 radius: '100%',
10991 spacing: 0,
10992 indexAxis: 'r'
10993 };
10994 static descriptors = {
10995 _scriptable: (name)=>name !== 'spacing',
10996 _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash')
10997 };
10998 static overrides = {
10999 aspectRatio: 1,
11000 plugins: {
11001 legend: {
11002 labels: {
11003 generateLabels (chart) {
11004 const data = chart.data;
11005 const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
11006 if (data.labels.length && data.datasets.length) {
11007 return data.labels.map((label, i)=>{
11008 const meta = chart.getDatasetMeta(0);
11009 const style = meta.controller.getStyle(i);
11010 return {
11011 text: label,
11012 fillStyle: style.backgroundColor,
11013 fontColor: color,
11014 hidden: !chart.getDataVisibility(i),
11015 lineDash: style.borderDash,
11016 lineDashOffset: style.borderDashOffset,
11017 lineJoin: style.borderJoinStyle,
11018 lineWidth: style.borderWidth,
11019 strokeStyle: style.borderColor,
11020 textAlign: textAlign,
11021 pointStyle: pointStyle,
11022 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
11023 index: i
11024 };
11025 });
11026 }
11027 return [];
11028 }
11029 },
11030 onClick (e, legendItem, legend) {
11031 legend.chart.toggleDataVisibility(legendItem.index);
11032 legend.chart.update();
11033 }
11034 }
11035 }
11036 };
11037 constructor(chart, datasetIndex){
11038 super(chart, datasetIndex);
11039 this.enableOptionSharing = true;
11040 this.innerRadius = undefined;
11041 this.outerRadius = undefined;
11042 this.offsetX = undefined;
11043 this.offsetY = undefined;
11044 }
11045 linkScales() {}
11046 parse(start, count) {
11047 const data = this.getDataset().data;
11048 const meta = this._cachedMeta;
11049 if (this._parsing === false) {
11050 meta._parsed = data;
11051 } else {
11052 let getter = (i)=>+data[i];
11053 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
11054 const { key ='value' } = this._parsing;
11055 getter = (i)=>+(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(data[i], key);
11056 }
11057 let i, ilen;
11058 for(i = start, ilen = start + count; i < ilen; ++i){
11059 meta._parsed[i] = getter(i);
11060 }
11061 }
11062 }
11063 _getRotation() {
11064 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.rotation - 90);
11065 }
11066 _getCircumference() {
11067 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.circumference);
11068 }
11069 _getRotationExtents() {
11070 let min = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
11071 let max = -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
11072 for(let i = 0; i < this.chart.data.datasets.length; ++i){
11073 if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) {
11074 const controller = this.chart.getDatasetMeta(i).controller;
11075 const rotation = controller._getRotation();
11076 const circumference = controller._getCircumference();
11077 min = Math.min(min, rotation);
11078 max = Math.max(max, rotation + circumference);
11079 }
11080 }
11081 return {
11082 rotation: min,
11083 circumference: max - min
11084 };
11085 }
11086 update(mode) {
11087 const chart = this.chart;
11088 const { chartArea } = chart;
11089 const meta = this._cachedMeta;
11090 const arcs = meta.data;
11091 const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
11092 const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
11093 const cutout = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.m)(this.options.cutout, maxSize), 1);
11094 const chartWeight = this._getRingWeight(this.index);
11095 const { circumference , rotation } = this._getRotationExtents();
11096 const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout);
11097 const maxWidth = (chartArea.width - spacing) / ratioX;
11098 const maxHeight = (chartArea.height - spacing) / ratioY;
11099 const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
11100 const outerRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.n)(this.options.radius, maxRadius);
11101 const innerRadius = Math.max(outerRadius * cutout, 0);
11102 const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
11103 this.offsetX = offsetX * outerRadius;
11104 this.offsetY = offsetY * outerRadius;
11105 meta.total = this.calculateTotal();
11106 this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
11107 this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
11108 this.updateElements(arcs, 0, arcs.length, mode);
11109 }
11110 _circumference(i, reset) {
11111 const opts = this.options;
11112 const meta = this._cachedMeta;
11113 const circumference = this._getCircumference();
11114 if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
11115 return 0;
11116 }
11117 return this.calculateCircumference(meta._parsed[i] * circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
11118 }
11119 updateElements(arcs, start, count, mode) {
11120 const reset = mode === 'reset';
11121 const chart = this.chart;
11122 const chartArea = chart.chartArea;
11123 const opts = chart.options;
11124 const animationOpts = opts.animation;
11125 const centerX = (chartArea.left + chartArea.right) / 2;
11126 const centerY = (chartArea.top + chartArea.bottom) / 2;
11127 const animateScale = reset && animationOpts.animateScale;
11128 const innerRadius = animateScale ? 0 : this.innerRadius;
11129 const outerRadius = animateScale ? 0 : this.outerRadius;
11130 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11131 let startAngle = this._getRotation();
11132 let i;
11133 for(i = 0; i < start; ++i){
11134 startAngle += this._circumference(i, reset);
11135 }
11136 for(i = start; i < start + count; ++i){
11137 const circumference = this._circumference(i, reset);
11138 const arc = arcs[i];
11139 const properties = {
11140 x: centerX + this.offsetX,
11141 y: centerY + this.offsetY,
11142 startAngle,
11143 endAngle: startAngle + circumference,
11144 circumference,
11145 outerRadius,
11146 innerRadius
11147 };
11148 if (includeOptions) {
11149 properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);
11150 }
11151 startAngle += circumference;
11152 this.updateElement(arc, i, properties, mode);
11153 }
11154 }
11155 calculateTotal() {
11156 const meta = this._cachedMeta;
11157 const metaData = meta.data;
11158 let total = 0;
11159 let i;
11160 for(i = 0; i < metaData.length; i++){
11161 const value = meta._parsed[i];
11162 if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
11163 total += Math.abs(value);
11164 }
11165 }
11166 return total;
11167 }
11168 calculateCircumference(value) {
11169 const total = this._cachedMeta.total;
11170 if (total > 0 && !isNaN(value)) {
11171 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T * (Math.abs(value) / total);
11172 }
11173 return 0;
11174 }
11175 getLabelAndValue(index) {
11176 const meta = this._cachedMeta;
11177 const chart = this.chart;
11178 const labels = chart.data.labels || [];
11179 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index], chart.options.locale);
11180 return {
11181 label: labels[index] || '',
11182 value
11183 };
11184 }
11185 getMaxBorderWidth(arcs) {
11186 let max = 0;
11187 const chart = this.chart;
11188 let i, ilen, meta, controller, options;
11189 if (!arcs) {
11190 for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){
11191 if (chart.isDatasetVisible(i)) {
11192 meta = chart.getDatasetMeta(i);
11193 arcs = meta.data;
11194 controller = meta.controller;
11195 break;
11196 }
11197 }
11198 }
11199 if (!arcs) {
11200 return 0;
11201 }
11202 for(i = 0, ilen = arcs.length; i < ilen; ++i){
11203 options = controller.resolveDataElementOptions(i);
11204 if (options.borderAlign !== 'inner') {
11205 max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
11206 }
11207 }
11208 return max;
11209 }
11210 getMaxOffset(arcs) {
11211 let max = 0;
11212 for(let i = 0, ilen = arcs.length; i < ilen; ++i){
11213 const options = this.resolveDataElementOptions(i);
11214 max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
11215 }
11216 return max;
11217 }
11218 _getRingWeightOffset(datasetIndex) {
11219 let ringWeightOffset = 0;
11220 for(let i = 0; i < datasetIndex; ++i){
11221 if (this.chart.isDatasetVisible(i)) {
11222 ringWeightOffset += this._getRingWeight(i);
11223 }
11224 }
11225 return ringWeightOffset;
11226 }
11227 _getRingWeight(datasetIndex) {
11228 return Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.data.datasets[datasetIndex].weight, 1), 0);
11229 }
11230 _getVisibleDatasetWeightTotal() {
11231 return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
11232 }
11233 }
11234
11235 class LineController extends DatasetController {
11236 static id = 'line';
11237 static defaults = {
11238 datasetElementType: 'line',
11239 dataElementType: 'point',
11240 showLine: true,
11241 spanGaps: false
11242 };
11243 static overrides = {
11244 scales: {
11245 _index_: {
11246 type: 'category'
11247 },
11248 _value_: {
11249 type: 'linear'
11250 }
11251 }
11252 };
11253 initialize() {
11254 this.enableOptionSharing = true;
11255 this.supportsDecimation = true;
11256 super.initialize();
11257 }
11258 update(mode) {
11259 const meta = this._cachedMeta;
11260 const { dataset: line , data: points = [] , _dataset } = meta;
11261 const animationsDisabled = this.chart._animationsDisabled;
11262 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11263 this._drawStart = start;
11264 this._drawCount = count;
11265 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11266 start = 0;
11267 count = points.length;
11268 }
11269 line._chart = this.chart;
11270 line._datasetIndex = this.index;
11271 line._decimated = !!_dataset._decimated;
11272 line.points = points;
11273 const options = this.resolveDatasetElementOptions(mode);
11274 if (!this.options.showLine) {
11275 options.borderWidth = 0;
11276 }
11277 options.segment = this.options.segment;
11278 this.updateElement(line, undefined, {
11279 animated: !animationsDisabled,
11280 options
11281 }, mode);
11282 this.updateElements(points, start, count, mode);
11283 }
11284 updateElements(points, start, count, mode) {
11285 const reset = mode === 'reset';
11286 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11287 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11288 const iAxis = iScale.axis;
11289 const vAxis = vScale.axis;
11290 const { spanGaps , segment } = this.options;
11291 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11292 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11293 const end = start + count;
11294 const pointsCount = points.length;
11295 let prevParsed = start > 0 && this.getParsed(start - 1);
11296 for(let i = 0; i < pointsCount; ++i){
11297 const point = points[i];
11298 const properties = directUpdate ? point : {};
11299 if (i < start || i >= end) {
11300 properties.skip = true;
11301 continue;
11302 }
11303 const parsed = this.getParsed(i);
11304 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11305 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11306 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11307 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11308 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11309 if (segment) {
11310 properties.parsed = parsed;
11311 properties.raw = _dataset.data[i];
11312 }
11313 if (includeOptions) {
11314 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11315 }
11316 if (!directUpdate) {
11317 this.updateElement(point, i, properties, mode);
11318 }
11319 prevParsed = parsed;
11320 }
11321 }
11322 getMaxOverflow() {
11323 const meta = this._cachedMeta;
11324 const dataset = meta.dataset;
11325 const border = dataset.options && dataset.options.borderWidth || 0;
11326 const data = meta.data || [];
11327 if (!data.length) {
11328 return border;
11329 }
11330 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11331 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11332 return Math.max(border, firstPoint, lastPoint) / 2;
11333 }
11334 draw() {
11335 const meta = this._cachedMeta;
11336 meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);
11337 super.draw();
11338 }
11339 }
11340
11341 class PolarAreaController extends DatasetController {
11342 static id = 'polarArea';
11343 static defaults = {
11344 dataElementType: 'arc',
11345 animation: {
11346 animateRotate: true,
11347 animateScale: true
11348 },
11349 animations: {
11350 numbers: {
11351 type: 'number',
11352 properties: [
11353 'x',
11354 'y',
11355 'startAngle',
11356 'endAngle',
11357 'innerRadius',
11358 'outerRadius'
11359 ]
11360 }
11361 },
11362 indexAxis: 'r',
11363 startAngle: 0
11364 };
11365 static overrides = {
11366 aspectRatio: 1,
11367 plugins: {
11368 legend: {
11369 labels: {
11370 generateLabels (chart) {
11371 const data = chart.data;
11372 if (data.labels.length && data.datasets.length) {
11373 const { labels: { pointStyle , color } } = chart.legend.options;
11374 return data.labels.map((label, i)=>{
11375 const meta = chart.getDatasetMeta(0);
11376 const style = meta.controller.getStyle(i);
11377 return {
11378 text: label,
11379 fillStyle: style.backgroundColor,
11380 strokeStyle: style.borderColor,
11381 fontColor: color,
11382 lineWidth: style.borderWidth,
11383 pointStyle: pointStyle,
11384 hidden: !chart.getDataVisibility(i),
11385 index: i
11386 };
11387 });
11388 }
11389 return [];
11390 }
11391 },
11392 onClick (e, legendItem, legend) {
11393 legend.chart.toggleDataVisibility(legendItem.index);
11394 legend.chart.update();
11395 }
11396 }
11397 },
11398 scales: {
11399 r: {
11400 type: 'radialLinear',
11401 angleLines: {
11402 display: false
11403 },
11404 beginAtZero: true,
11405 grid: {
11406 circular: true
11407 },
11408 pointLabels: {
11409 display: false
11410 },
11411 startAngle: 0
11412 }
11413 }
11414 };
11415 constructor(chart, datasetIndex){
11416 super(chart, datasetIndex);
11417 this.innerRadius = undefined;
11418 this.outerRadius = undefined;
11419 }
11420 getLabelAndValue(index) {
11421 const meta = this._cachedMeta;
11422 const chart = this.chart;
11423 const labels = chart.data.labels || [];
11424 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index].r, chart.options.locale);
11425 return {
11426 label: labels[index] || '',
11427 value
11428 };
11429 }
11430 parseObjectData(meta, data, start, count) {
11431 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11432 }
11433 update(mode) {
11434 const arcs = this._cachedMeta.data;
11435 this._updateRadius();
11436 this.updateElements(arcs, 0, arcs.length, mode);
11437 }
11438 getMinMax() {
11439 const meta = this._cachedMeta;
11440 const range = {
11441 min: Number.POSITIVE_INFINITY,
11442 max: Number.NEGATIVE_INFINITY
11443 };
11444 meta.data.forEach((element, index)=>{
11445 const parsed = this.getParsed(index).r;
11446 if (!isNaN(parsed) && this.chart.getDataVisibility(index)) {
11447 if (parsed < range.min) {
11448 range.min = parsed;
11449 }
11450 if (parsed > range.max) {
11451 range.max = parsed;
11452 }
11453 }
11454 });
11455 return range;
11456 }
11457 _updateRadius() {
11458 const chart = this.chart;
11459 const chartArea = chart.chartArea;
11460 const opts = chart.options;
11461 const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
11462 const outerRadius = Math.max(minSize / 2, 0);
11463 const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0);
11464 const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
11465 this.outerRadius = outerRadius - radiusLength * this.index;
11466 this.innerRadius = this.outerRadius - radiusLength;
11467 }
11468 updateElements(arcs, start, count, mode) {
11469 const reset = mode === 'reset';
11470 const chart = this.chart;
11471 const opts = chart.options;
11472 const animationOpts = opts.animation;
11473 const scale = this._cachedMeta.rScale;
11474 const centerX = scale.xCenter;
11475 const centerY = scale.yCenter;
11476 const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P;
11477 let angle = datasetStartAngle;
11478 let i;
11479 const defaultAngle = 360 / this.countVisibleElements();
11480 for(i = 0; i < start; ++i){
11481 angle += this._computeAngle(i, mode, defaultAngle);
11482 }
11483 for(i = start; i < start + count; i++){
11484 const arc = arcs[i];
11485 let startAngle = angle;
11486 let endAngle = angle + this._computeAngle(i, mode, defaultAngle);
11487 let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0;
11488 angle = endAngle;
11489 if (reset) {
11490 if (animationOpts.animateScale) {
11491 outerRadius = 0;
11492 }
11493 if (animationOpts.animateRotate) {
11494 startAngle = endAngle = datasetStartAngle;
11495 }
11496 }
11497 const properties = {
11498 x: centerX,
11499 y: centerY,
11500 innerRadius: 0,
11501 outerRadius,
11502 startAngle,
11503 endAngle,
11504 options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)
11505 };
11506 this.updateElement(arc, i, properties, mode);
11507 }
11508 }
11509 countVisibleElements() {
11510 const meta = this._cachedMeta;
11511 let count = 0;
11512 meta.data.forEach((element, index)=>{
11513 if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) {
11514 count++;
11515 }
11516 });
11517 return count;
11518 }
11519 _computeAngle(index, mode, defaultAngle) {
11520 return this.chart.getDataVisibility(index) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0;
11521 }
11522 }
11523
11524 class PieController extends DoughnutController {
11525 static id = 'pie';
11526 static defaults = {
11527 cutout: 0,
11528 rotation: 0,
11529 circumference: 360,
11530 radius: '100%'
11531 };
11532 }
11533
11534 class RadarController extends DatasetController {
11535 static id = 'radar';
11536 static defaults = {
11537 datasetElementType: 'line',
11538 dataElementType: 'point',
11539 indexAxis: 'r',
11540 showLine: true,
11541 elements: {
11542 line: {
11543 fill: 'start'
11544 }
11545 }
11546 };
11547 static overrides = {
11548 aspectRatio: 1,
11549 scales: {
11550 r: {
11551 type: 'radialLinear'
11552 }
11553 }
11554 };
11555 getLabelAndValue(index) {
11556 const vScale = this._cachedMeta.vScale;
11557 const parsed = this.getParsed(index);
11558 return {
11559 label: vScale.getLabels()[index],
11560 value: '' + vScale.getLabelForValue(parsed[vScale.axis])
11561 };
11562 }
11563 parseObjectData(meta, data, start, count) {
11564 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11565 }
11566 update(mode) {
11567 const meta = this._cachedMeta;
11568 const line = meta.dataset;
11569 const points = meta.data || [];
11570 const labels = meta.iScale.getLabels();
11571 line.points = points;
11572 if (mode !== 'resize') {
11573 const options = this.resolveDatasetElementOptions(mode);
11574 if (!this.options.showLine) {
11575 options.borderWidth = 0;
11576 }
11577 const properties = {
11578 _loop: true,
11579 _fullLoop: labels.length === points.length,
11580 options
11581 };
11582 this.updateElement(line, undefined, properties, mode);
11583 }
11584 this.updateElements(points, 0, points.length, mode);
11585 }
11586 updateElements(points, start, count, mode) {
11587 const scale = this._cachedMeta.rScale;
11588 const reset = mode === 'reset';
11589 for(let i = start; i < start + count; i++){
11590 const point = points[i];
11591 const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11592 const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r);
11593 const x = reset ? scale.xCenter : pointPosition.x;
11594 const y = reset ? scale.yCenter : pointPosition.y;
11595 const properties = {
11596 x,
11597 y,
11598 angle: pointPosition.angle,
11599 skip: isNaN(x) || isNaN(y),
11600 options
11601 };
11602 this.updateElement(point, i, properties, mode);
11603 }
11604 }
11605 }
11606
11607 class ScatterController extends DatasetController {
11608 static id = 'scatter';
11609 static defaults = {
11610 datasetElementType: false,
11611 dataElementType: 'point',
11612 showLine: false,
11613 fill: false
11614 };
11615 static overrides = {
11616 interaction: {
11617 mode: 'point'
11618 },
11619 scales: {
11620 x: {
11621 type: 'linear'
11622 },
11623 y: {
11624 type: 'linear'
11625 }
11626 }
11627 };
11628 getLabelAndValue(index) {
11629 const meta = this._cachedMeta;
11630 const labels = this.chart.data.labels || [];
11631 const { xScale , yScale } = meta;
11632 const parsed = this.getParsed(index);
11633 const x = xScale.getLabelForValue(parsed.x);
11634 const y = yScale.getLabelForValue(parsed.y);
11635 return {
11636 label: labels[index] || '',
11637 value: '(' + x + ', ' + y + ')'
11638 };
11639 }
11640 update(mode) {
11641 const meta = this._cachedMeta;
11642 const { data: points = [] } = meta;
11643 const animationsDisabled = this.chart._animationsDisabled;
11644 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11645 this._drawStart = start;
11646 this._drawCount = count;
11647 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11648 start = 0;
11649 count = points.length;
11650 }
11651 if (this.options.showLine) {
11652 if (!this.datasetElementType) {
11653 this.addElements();
11654 }
11655 const { dataset: line , _dataset } = meta;
11656 line._chart = this.chart;
11657 line._datasetIndex = this.index;
11658 line._decimated = !!_dataset._decimated;
11659 line.points = points;
11660 const options = this.resolveDatasetElementOptions(mode);
11661 options.segment = this.options.segment;
11662 this.updateElement(line, undefined, {
11663 animated: !animationsDisabled,
11664 options
11665 }, mode);
11666 } else if (this.datasetElementType) {
11667 delete meta.dataset;
11668 this.datasetElementType = false;
11669 }
11670 this.updateElements(points, start, count, mode);
11671 }
11672 addElements() {
11673 const { showLine } = this.options;
11674 if (!this.datasetElementType && showLine) {
11675 this.datasetElementType = this.chart.registry.getElement('line');
11676 }
11677 super.addElements();
11678 }
11679 updateElements(points, start, count, mode) {
11680 const reset = mode === 'reset';
11681 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11682 const firstOpts = this.resolveDataElementOptions(start, mode);
11683 const sharedOptions = this.getSharedOptions(firstOpts);
11684 const includeOptions = this.includeOptions(mode, sharedOptions);
11685 const iAxis = iScale.axis;
11686 const vAxis = vScale.axis;
11687 const { spanGaps , segment } = this.options;
11688 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11689 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11690 let prevParsed = start > 0 && this.getParsed(start - 1);
11691 for(let i = start; i < start + count; ++i){
11692 const point = points[i];
11693 const parsed = this.getParsed(i);
11694 const properties = directUpdate ? point : {};
11695 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11696 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11697 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11698 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11699 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11700 if (segment) {
11701 properties.parsed = parsed;
11702 properties.raw = _dataset.data[i];
11703 }
11704 if (includeOptions) {
11705 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11706 }
11707 if (!directUpdate) {
11708 this.updateElement(point, i, properties, mode);
11709 }
11710 prevParsed = parsed;
11711 }
11712 this.updateSharedOptions(sharedOptions, mode, firstOpts);
11713 }
11714 getMaxOverflow() {
11715 const meta = this._cachedMeta;
11716 const data = meta.data || [];
11717 if (!this.options.showLine) {
11718 let max = 0;
11719 for(let i = data.length - 1; i >= 0; --i){
11720 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
11721 }
11722 return max > 0 && max;
11723 }
11724 const dataset = meta.dataset;
11725 const border = dataset.options && dataset.options.borderWidth || 0;
11726 if (!data.length) {
11727 return border;
11728 }
11729 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11730 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11731 return Math.max(border, firstPoint, lastPoint) / 2;
11732 }
11733 }
11734
11735 var controllers = /*#__PURE__*/Object.freeze({
11736 __proto__: null,
11737 BarController: BarController,
11738 BubbleController: BubbleController,
11739 DoughnutController: DoughnutController,
11740 LineController: LineController,
11741 PieController: PieController,
11742 PolarAreaController: PolarAreaController,
11743 RadarController: RadarController,
11744 ScatterController: ScatterController
11745 });
11746
11747 /**
11748 * @namespace Chart._adapters
11749 * @since 2.8.0
11750 * @private
11751 */ function abstract() {
11752 throw new Error('This method is not implemented: Check that a complete date adapter is provided.');
11753 }
11754 /**
11755 * Date adapter (current used by the time scale)
11756 * @namespace Chart._adapters._date
11757 * @memberof Chart._adapters
11758 * @private
11759 */ class DateAdapterBase {
11760 /**
11761 * Override default date adapter methods.
11762 * Accepts type parameter to define options type.
11763 * @example
11764 * Chart._adapters._date.override<{myAdapterOption: string}>({
11765 * init() {
11766 * console.log(this.options.myAdapterOption);
11767 * }
11768 * })
11769 */ static override(members) {
11770 Object.assign(DateAdapterBase.prototype, members);
11771 }
11772 options;
11773 constructor(options){
11774 this.options = options || {};
11775 }
11776 // eslint-disable-next-line @typescript-eslint/no-empty-function
11777 init() {}
11778 formats() {
11779 return abstract();
11780 }
11781 parse() {
11782 return abstract();
11783 }
11784 format() {
11785 return abstract();
11786 }
11787 add() {
11788 return abstract();
11789 }
11790 diff() {
11791 return abstract();
11792 }
11793 startOf() {
11794 return abstract();
11795 }
11796 endOf() {
11797 return abstract();
11798 }
11799 }
11800 var adapters = {
11801 _date: DateAdapterBase
11802 };
11803
11804 function binarySearch(metaset, axis, value, intersect) {
11805 const { controller , data , _sorted } = metaset;
11806 const iScale = controller._cachedMeta.iScale;
11807 const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null;
11808 if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
11809 const lookupMethod = iScale._reversePixels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.A : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B;
11810 if (!intersect) {
11811 const result = lookupMethod(data, axis, value);
11812 if (spanGaps) {
11813 const { vScale } = controller._cachedMeta;
11814 const { _parsed } = metaset;
11815 const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11816 result.lo -= Math.max(0, distanceToDefinedLo);
11817 const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11818 result.hi += Math.max(0, distanceToDefinedHi);
11819 }
11820 return result;
11821 } else if (controller._sharedOptions) {
11822 const el = data[0];
11823 const range = typeof el.getRange === 'function' && el.getRange(axis);
11824 if (range) {
11825 const start = lookupMethod(data, axis, value - range);
11826 const end = lookupMethod(data, axis, value + range);
11827 return {
11828 lo: start.lo,
11829 hi: end.hi
11830 };
11831 }
11832 }
11833 }
11834 return {
11835 lo: 0,
11836 hi: data.length - 1
11837 };
11838 }
11839 function evaluateInteractionItems(chart, axis, position, handler, intersect) {
11840 const metasets = chart.getSortedVisibleDatasetMetas();
11841 const value = position[axis];
11842 for(let i = 0, ilen = metasets.length; i < ilen; ++i){
11843 const { index , data } = metasets[i];
11844 const { lo , hi } = binarySearch(metasets[i], axis, value, intersect);
11845 for(let j = lo; j <= hi; ++j){
11846 const element = data[j];
11847 if (!element.skip) {
11848 handler(element, index, j);
11849 }
11850 }
11851 }
11852 }
11853 function getDistanceMetricForAxis(axis) {
11854 const useX = axis.indexOf('x') !== -1;
11855 const useY = axis.indexOf('y') !== -1;
11856 return function(pt1, pt2) {
11857 const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
11858 const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
11859 return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
11860 };
11861 }
11862 function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {
11863 const items = [];
11864 if (!includeInvisible && !chart.isPointInArea(position)) {
11865 return items;
11866 }
11867 const evaluationFunc = function(element, datasetIndex, index) {
11868 if (!includeInvisible && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(element, chart.chartArea, 0)) {
11869 return;
11870 }
11871 if (element.inRange(position.x, position.y, useFinalPosition)) {
11872 items.push({
11873 element,
11874 datasetIndex,
11875 index
11876 });
11877 }
11878 };
11879 evaluateInteractionItems(chart, axis, position, evaluationFunc, true);
11880 return items;
11881 }
11882 function getNearestRadialItems(chart, position, axis, useFinalPosition) {
11883 let items = [];
11884 function evaluationFunc(element, datasetIndex, index) {
11885 const { startAngle , endAngle } = element.getProps([
11886 'startAngle',
11887 'endAngle'
11888 ], useFinalPosition);
11889 const { angle } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(element, {
11890 x: position.x,
11891 y: position.y
11892 });
11893 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle)) {
11894 items.push({
11895 element,
11896 datasetIndex,
11897 index
11898 });
11899 }
11900 }
11901 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11902 return items;
11903 }
11904 function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11905 let items = [];
11906 const distanceMetric = getDistanceMetricForAxis(axis);
11907 let minDistance = Number.POSITIVE_INFINITY;
11908 function evaluationFunc(element, datasetIndex, index) {
11909 const inRange = element.inRange(position.x, position.y, useFinalPosition);
11910 if (intersect && !inRange) {
11911 return;
11912 }
11913 const center = element.getCenterPoint(useFinalPosition);
11914 const pointInArea = !!includeInvisible || chart.isPointInArea(center);
11915 if (!pointInArea && !inRange) {
11916 return;
11917 }
11918 const distance = distanceMetric(position, center);
11919 if (distance < minDistance) {
11920 items = [
11921 {
11922 element,
11923 datasetIndex,
11924 index
11925 }
11926 ];
11927 minDistance = distance;
11928 } else if (distance === minDistance) {
11929 items.push({
11930 element,
11931 datasetIndex,
11932 index
11933 });
11934 }
11935 }
11936 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11937 return items;
11938 }
11939 function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11940 if (!includeInvisible && !chart.isPointInArea(position)) {
11941 return [];
11942 }
11943 return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);
11944 }
11945 function getAxisItems(chart, position, axis, intersect, useFinalPosition) {
11946 const items = [];
11947 const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
11948 let intersectsItem = false;
11949 evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{
11950 if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {
11951 items.push({
11952 element,
11953 datasetIndex,
11954 index
11955 });
11956 intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);
11957 }
11958 });
11959 if (intersect && !intersectsItem) {
11960 return [];
11961 }
11962 return items;
11963 }
11964 var Interaction = {
11965 evaluateInteractionItems,
11966 modes: {
11967 index (chart, e, options, useFinalPosition) {
11968 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11969 const axis = options.axis || 'x';
11970 const includeInvisible = options.includeInvisible || false;
11971 const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11972 const elements = [];
11973 if (!items.length) {
11974 return [];
11975 }
11976 chart.getSortedVisibleDatasetMetas().forEach((meta)=>{
11977 const index = items[0].index;
11978 const element = meta.data[index];
11979 if (element && !element.skip) {
11980 elements.push({
11981 element,
11982 datasetIndex: meta.index,
11983 index
11984 });
11985 }
11986 });
11987 return elements;
11988 },
11989 dataset (chart, e, options, useFinalPosition) {
11990 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11991 const axis = options.axis || 'xy';
11992 const includeInvisible = options.includeInvisible || false;
11993 let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11994 if (items.length > 0) {
11995 const datasetIndex = items[0].datasetIndex;
11996 const data = chart.getDatasetMeta(datasetIndex).data;
11997 items = [];
11998 for(let i = 0; i < data.length; ++i){
11999 items.push({
12000 element: data[i],
12001 datasetIndex,
12002 index: i
12003 });
12004 }
12005 }
12006 return items;
12007 },
12008 point (chart, e, options, useFinalPosition) {
12009 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
12010 const axis = options.axis || 'xy';
12011 const includeInvisible = options.includeInvisible || false;
12012 return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);
12013 },
12014 nearest (chart, e, options, useFinalPosition) {
12015 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
12016 const axis = options.axis || 'xy';
12017 const includeInvisible = options.includeInvisible || false;
12018 return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);
12019 },
12020 x (chart, e, options, useFinalPosition) {
12021 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
12022 return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition);
12023 },
12024 y (chart, e, options, useFinalPosition) {
12025 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
12026 return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition);
12027 }
12028 }
12029 };
12030
12031 const STATIC_POSITIONS = [
12032 'left',
12033 'top',
12034 'right',
12035 'bottom'
12036 ];
12037 function filterByPosition(array, position) {
12038 return array.filter((v)=>v.pos === position);
12039 }
12040 function filterDynamicPositionByAxis(array, axis) {
12041 return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
12042 }
12043 function sortByWeight(array, reverse) {
12044 return array.sort((a, b)=>{
12045 const v0 = reverse ? b : a;
12046 const v1 = reverse ? a : b;
12047 return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;
12048 });
12049 }
12050 function wrapBoxes(boxes) {
12051 const layoutBoxes = [];
12052 let i, ilen, box, pos, stack, stackWeight;
12053 for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){
12054 box = boxes[i];
12055 ({ position: pos , options: { stack , stackWeight =1 } } = box);
12056 layoutBoxes.push({
12057 index: i,
12058 box,
12059 pos,
12060 horizontal: box.isHorizontal(),
12061 weight: box.weight,
12062 stack: stack && pos + stack,
12063 stackWeight
12064 });
12065 }
12066 return layoutBoxes;
12067 }
12068 function buildStacks(layouts) {
12069 const stacks = {};
12070 for (const wrap of layouts){
12071 const { stack , pos , stackWeight } = wrap;
12072 if (!stack || !STATIC_POSITIONS.includes(pos)) {
12073 continue;
12074 }
12075 const _stack = stacks[stack] || (stacks[stack] = {
12076 count: 0,
12077 placed: 0,
12078 weight: 0,
12079 size: 0
12080 });
12081 _stack.count++;
12082 _stack.weight += stackWeight;
12083 }
12084 return stacks;
12085 }
12086 function setLayoutDims(layouts, params) {
12087 const stacks = buildStacks(layouts);
12088 const { vBoxMaxWidth , hBoxMaxHeight } = params;
12089 let i, ilen, layout;
12090 for(i = 0, ilen = layouts.length; i < ilen; ++i){
12091 layout = layouts[i];
12092 const { fullSize } = layout.box;
12093 const stack = stacks[layout.stack];
12094 const factor = stack && layout.stackWeight / stack.weight;
12095 if (layout.horizontal) {
12096 layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
12097 layout.height = hBoxMaxHeight;
12098 } else {
12099 layout.width = vBoxMaxWidth;
12100 layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
12101 }
12102 }
12103 return stacks;
12104 }
12105 function buildLayoutBoxes(boxes) {
12106 const layoutBoxes = wrapBoxes(boxes);
12107 const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true);
12108 const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
12109 const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
12110 const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
12111 const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
12112 const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
12113 const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
12114 return {
12115 fullSize,
12116 leftAndTop: left.concat(top),
12117 rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
12118 chartArea: filterByPosition(layoutBoxes, 'chartArea'),
12119 vertical: left.concat(right).concat(centerVertical),
12120 horizontal: top.concat(bottom).concat(centerHorizontal)
12121 };
12122 }
12123 function getCombinedMax(maxPadding, chartArea, a, b) {
12124 return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
12125 }
12126 function updateMaxPadding(maxPadding, boxPadding) {
12127 maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
12128 maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
12129 maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
12130 maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
12131 }
12132 function updateDims(chartArea, params, layout, stacks) {
12133 const { pos , box } = layout;
12134 const maxPadding = chartArea.maxPadding;
12135 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(pos)) {
12136 if (layout.size) {
12137 chartArea[pos] -= layout.size;
12138 }
12139 const stack = stacks[layout.stack] || {
12140 size: 0,
12141 count: 1
12142 };
12143 stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
12144 layout.size = stack.size / stack.count;
12145 chartArea[pos] += layout.size;
12146 }
12147 if (box.getPadding) {
12148 updateMaxPadding(maxPadding, box.getPadding());
12149 }
12150 const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
12151 const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
12152 const widthChanged = newWidth !== chartArea.w;
12153 const heightChanged = newHeight !== chartArea.h;
12154 chartArea.w = newWidth;
12155 chartArea.h = newHeight;
12156 return layout.horizontal ? {
12157 same: widthChanged,
12158 other: heightChanged
12159 } : {
12160 same: heightChanged,
12161 other: widthChanged
12162 };
12163 }
12164 function handleMaxPadding(chartArea) {
12165 const maxPadding = chartArea.maxPadding;
12166 function updatePos(pos) {
12167 const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
12168 chartArea[pos] += change;
12169 return change;
12170 }
12171 chartArea.y += updatePos('top');
12172 chartArea.x += updatePos('left');
12173 updatePos('right');
12174 updatePos('bottom');
12175 }
12176 function getMargins(horizontal, chartArea) {
12177 const maxPadding = chartArea.maxPadding;
12178 function marginForPositions(positions) {
12179 const margin = {
12180 left: 0,
12181 top: 0,
12182 right: 0,
12183 bottom: 0
12184 };
12185 positions.forEach((pos)=>{
12186 margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
12187 });
12188 return margin;
12189 }
12190 return horizontal ? marginForPositions([
12191 'left',
12192 'right'
12193 ]) : marginForPositions([
12194 'top',
12195 'bottom'
12196 ]);
12197 }
12198 function fitBoxes(boxes, chartArea, params, stacks) {
12199 const refitBoxes = [];
12200 let i, ilen, layout, box, refit, changed;
12201 for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){
12202 layout = boxes[i];
12203 box = layout.box;
12204 box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));
12205 const { same , other } = updateDims(chartArea, params, layout, stacks);
12206 refit |= same && refitBoxes.length;
12207 changed = changed || other;
12208 if (!box.fullSize) {
12209 refitBoxes.push(layout);
12210 }
12211 }
12212 return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
12213 }
12214 function setBoxDims(box, left, top, width, height) {
12215 box.top = top;
12216 box.left = left;
12217 box.right = left + width;
12218 box.bottom = top + height;
12219 box.width = width;
12220 box.height = height;
12221 }
12222 function placeBoxes(boxes, chartArea, params, stacks) {
12223 const userPadding = params.padding;
12224 let { x , y } = chartArea;
12225 for (const layout of boxes){
12226 const box = layout.box;
12227 const stack = stacks[layout.stack] || {
12228 count: 1,
12229 placed: 0,
12230 weight: 1
12231 };
12232 const weight = layout.stackWeight / stack.weight || 1;
12233 if (layout.horizontal) {
12234 const width = chartArea.w * weight;
12235 const height = stack.size || box.height;
12236 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12237 y = stack.start;
12238 }
12239 if (box.fullSize) {
12240 setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);
12241 } else {
12242 setBoxDims(box, chartArea.left + stack.placed, y, width, height);
12243 }
12244 stack.start = y;
12245 stack.placed += width;
12246 y = box.bottom;
12247 } else {
12248 const height = chartArea.h * weight;
12249 const width = stack.size || box.width;
12250 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12251 x = stack.start;
12252 }
12253 if (box.fullSize) {
12254 setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
12255 } else {
12256 setBoxDims(box, x, chartArea.top + stack.placed, width, height);
12257 }
12258 stack.start = x;
12259 stack.placed += height;
12260 x = box.right;
12261 }
12262 }
12263 chartArea.x = x;
12264 chartArea.y = y;
12265 }
12266 var layouts = {
12267 addBox (chart, item) {
12268 if (!chart.boxes) {
12269 chart.boxes = [];
12270 }
12271 item.fullSize = item.fullSize || false;
12272 item.position = item.position || 'top';
12273 item.weight = item.weight || 0;
12274 item._layers = item._layers || function() {
12275 return [
12276 {
12277 z: 0,
12278 draw (chartArea) {
12279 item.draw(chartArea);
12280 }
12281 }
12282 ];
12283 };
12284 chart.boxes.push(item);
12285 },
12286 removeBox (chart, layoutItem) {
12287 const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
12288 if (index !== -1) {
12289 chart.boxes.splice(index, 1);
12290 }
12291 },
12292 configure (chart, item, options) {
12293 item.fullSize = options.fullSize;
12294 item.position = options.position;
12295 item.weight = options.weight;
12296 },
12297 update (chart, width, height, minPadding) {
12298 if (!chart) {
12299 return;
12300 }
12301 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(chart.options.layout.padding);
12302 const availableWidth = Math.max(width - padding.width, 0);
12303 const availableHeight = Math.max(height - padding.height, 0);
12304 const boxes = buildLayoutBoxes(chart.boxes);
12305 const verticalBoxes = boxes.vertical;
12306 const horizontalBoxes = boxes.horizontal;
12307 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(chart.boxes, (box)=>{
12308 if (typeof box.beforeLayout === 'function') {
12309 box.beforeLayout();
12310 }
12311 });
12312 const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
12313 const params = Object.freeze({
12314 outerWidth: width,
12315 outerHeight: height,
12316 padding,
12317 availableWidth,
12318 availableHeight,
12319 vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
12320 hBoxMaxHeight: availableHeight / 2
12321 });
12322 const maxPadding = Object.assign({}, padding);
12323 updateMaxPadding(maxPadding, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(minPadding));
12324 const chartArea = Object.assign({
12325 maxPadding,
12326 w: availableWidth,
12327 h: availableHeight,
12328 x: padding.left,
12329 y: padding.top
12330 }, padding);
12331 const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
12332 fitBoxes(boxes.fullSize, chartArea, params, stacks);
12333 fitBoxes(verticalBoxes, chartArea, params, stacks);
12334 if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
12335 fitBoxes(verticalBoxes, chartArea, params, stacks);
12336 }
12337 handleMaxPadding(chartArea);
12338 placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
12339 chartArea.x += chartArea.w;
12340 chartArea.y += chartArea.h;
12341 placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
12342 chart.chartArea = {
12343 left: chartArea.left,
12344 top: chartArea.top,
12345 right: chartArea.left + chartArea.w,
12346 bottom: chartArea.top + chartArea.h,
12347 height: chartArea.h,
12348 width: chartArea.w
12349 };
12350 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(boxes.chartArea, (layout)=>{
12351 const box = layout.box;
12352 Object.assign(box, chart.chartArea);
12353 box.update(chartArea.w, chartArea.h, {
12354 left: 0,
12355 top: 0,
12356 right: 0,
12357 bottom: 0
12358 });
12359 });
12360 }
12361 };
12362
12363 class BasePlatform {
12364 acquireContext(canvas, aspectRatio) {}
12365 releaseContext(context) {
12366 return false;
12367 }
12368 addEventListener(chart, type, listener) {}
12369 removeEventListener(chart, type, listener) {}
12370 getDevicePixelRatio() {
12371 return 1;
12372 }
12373 getMaximumSize(element, width, height, aspectRatio) {
12374 width = Math.max(0, width || element.width);
12375 height = height || element.height;
12376 return {
12377 width,
12378 height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
12379 };
12380 }
12381 isAttached(canvas) {
12382 return true;
12383 }
12384 updateConfig(config) {
12385 }
12386 }
12387
12388 class BasicPlatform extends BasePlatform {
12389 acquireContext(item) {
12390 return item && item.getContext && item.getContext('2d') || null;
12391 }
12392 updateConfig(config) {
12393 config.options.animation = false;
12394 }
12395 }
12396
12397 const EXPANDO_KEY = '$chartjs';
12398 const EVENT_TYPES = {
12399 touchstart: 'mousedown',
12400 touchmove: 'mousemove',
12401 touchend: 'mouseup',
12402 pointerenter: 'mouseenter',
12403 pointerdown: 'mousedown',
12404 pointermove: 'mousemove',
12405 pointerup: 'mouseup',
12406 pointerleave: 'mouseout',
12407 pointerout: 'mouseout'
12408 };
12409 const isNullOrEmpty = (value)=>value === null || value === '';
12410 function initCanvas(canvas, aspectRatio) {
12411 const style = canvas.style;
12412 const renderHeight = canvas.getAttribute('height');
12413 const renderWidth = canvas.getAttribute('width');
12414 canvas[EXPANDO_KEY] = {
12415 initial: {
12416 height: renderHeight,
12417 width: renderWidth,
12418 style: {
12419 display: style.display,
12420 height: style.height,
12421 width: style.width
12422 }
12423 }
12424 };
12425 style.display = style.display || 'block';
12426 style.boxSizing = style.boxSizing || 'border-box';
12427 if (isNullOrEmpty(renderWidth)) {
12428 const displayWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'width');
12429 if (displayWidth !== undefined) {
12430 canvas.width = displayWidth;
12431 }
12432 }
12433 if (isNullOrEmpty(renderHeight)) {
12434 if (canvas.style.height === '') {
12435 canvas.height = canvas.width / (aspectRatio || 2);
12436 } else {
12437 const displayHeight = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'height');
12438 if (displayHeight !== undefined) {
12439 canvas.height = displayHeight;
12440 }
12441 }
12442 }
12443 return canvas;
12444 }
12445 const eventListenerOptions = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.K ? {
12446 passive: true
12447 } : false;
12448 function addListener(node, type, listener) {
12449 if (node) {
12450 node.addEventListener(type, listener, eventListenerOptions);
12451 }
12452 }
12453 function removeListener(chart, type, listener) {
12454 if (chart && chart.canvas) {
12455 chart.canvas.removeEventListener(type, listener, eventListenerOptions);
12456 }
12457 }
12458 function fromNativeEvent(event, chart) {
12459 const type = EVENT_TYPES[event.type] || event.type;
12460 const { x , y } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(event, chart);
12461 return {
12462 type,
12463 chart,
12464 native: event,
12465 x: x !== undefined ? x : null,
12466 y: y !== undefined ? y : null
12467 };
12468 }
12469 function nodeListContains(nodeList, canvas) {
12470 for (const node of nodeList){
12471 if (node === canvas || node.contains(canvas)) {
12472 return true;
12473 }
12474 }
12475 }
12476 function createAttachObserver(chart, type, listener) {
12477 const canvas = chart.canvas;
12478 const observer = new MutationObserver((entries)=>{
12479 let trigger = false;
12480 for (const entry of entries){
12481 trigger = trigger || nodeListContains(entry.addedNodes, canvas);
12482 trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
12483 }
12484 if (trigger) {
12485 listener();
12486 }
12487 });
12488 observer.observe(document, {
12489 childList: true,
12490 subtree: true
12491 });
12492 return observer;
12493 }
12494 function createDetachObserver(chart, type, listener) {
12495 const canvas = chart.canvas;
12496 const observer = new MutationObserver((entries)=>{
12497 let trigger = false;
12498 for (const entry of entries){
12499 trigger = trigger || nodeListContains(entry.removedNodes, canvas);
12500 trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
12501 }
12502 if (trigger) {
12503 listener();
12504 }
12505 });
12506 observer.observe(document, {
12507 childList: true,
12508 subtree: true
12509 });
12510 return observer;
12511 }
12512 const drpListeningCharts = new Map();
12513 let oldDevicePixelRatio = 0;
12514 function onWindowResize() {
12515 const dpr = window.devicePixelRatio;
12516 if (dpr === oldDevicePixelRatio) {
12517 return;
12518 }
12519 oldDevicePixelRatio = dpr;
12520 drpListeningCharts.forEach((resize, chart)=>{
12521 if (chart.currentDevicePixelRatio !== dpr) {
12522 resize();
12523 }
12524 });
12525 }
12526 function listenDevicePixelRatioChanges(chart, resize) {
12527 if (!drpListeningCharts.size) {
12528 window.addEventListener('resize', onWindowResize);
12529 }
12530 drpListeningCharts.set(chart, resize);
12531 }
12532 function unlistenDevicePixelRatioChanges(chart) {
12533 drpListeningCharts.delete(chart);
12534 if (!drpListeningCharts.size) {
12535 window.removeEventListener('resize', onWindowResize);
12536 }
12537 }
12538 function createResizeObserver(chart, type, listener) {
12539 const canvas = chart.canvas;
12540 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12541 if (!container) {
12542 return;
12543 }
12544 const resize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((width, height)=>{
12545 const w = container.clientWidth;
12546 listener(width, height);
12547 if (w < container.clientWidth) {
12548 listener();
12549 }
12550 }, window);
12551 const observer = new ResizeObserver((entries)=>{
12552 const entry = entries[0];
12553 const width = entry.contentRect.width;
12554 const height = entry.contentRect.height;
12555 if (width === 0 && height === 0) {
12556 return;
12557 }
12558 resize(width, height);
12559 });
12560 observer.observe(container);
12561 listenDevicePixelRatioChanges(chart, resize);
12562 return observer;
12563 }
12564 function releaseObserver(chart, type, observer) {
12565 if (observer) {
12566 observer.disconnect();
12567 }
12568 if (type === 'resize') {
12569 unlistenDevicePixelRatioChanges(chart);
12570 }
12571 }
12572 function createProxyAndListen(chart, type, listener) {
12573 const canvas = chart.canvas;
12574 const proxy = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((event)=>{
12575 if (chart.ctx !== null) {
12576 listener(fromNativeEvent(event, chart));
12577 }
12578 }, chart);
12579 addListener(canvas, type, proxy);
12580 return proxy;
12581 }
12582 class DomPlatform extends BasePlatform {
12583 acquireContext(canvas, aspectRatio) {
12584 const context = canvas && canvas.getContext && canvas.getContext('2d');
12585 if (context && context.canvas === canvas) {
12586 initCanvas(canvas, aspectRatio);
12587 return context;
12588 }
12589 return null;
12590 }
12591 releaseContext(context) {
12592 const canvas = context.canvas;
12593 if (!canvas[EXPANDO_KEY]) {
12594 return false;
12595 }
12596 const initial = canvas[EXPANDO_KEY].initial;
12597 [
12598 'height',
12599 'width'
12600 ].forEach((prop)=>{
12601 const value = initial[prop];
12602 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
12603 canvas.removeAttribute(prop);
12604 } else {
12605 canvas.setAttribute(prop, value);
12606 }
12607 });
12608 const style = initial.style || {};
12609 Object.keys(style).forEach((key)=>{
12610 canvas.style[key] = style[key];
12611 });
12612 canvas.width = canvas.width;
12613 delete canvas[EXPANDO_KEY];
12614 return true;
12615 }
12616 addEventListener(chart, type, listener) {
12617 this.removeEventListener(chart, type);
12618 const proxies = chart.$proxies || (chart.$proxies = {});
12619 const handlers = {
12620 attach: createAttachObserver,
12621 detach: createDetachObserver,
12622 resize: createResizeObserver
12623 };
12624 const handler = handlers[type] || createProxyAndListen;
12625 proxies[type] = handler(chart, type, listener);
12626 }
12627 removeEventListener(chart, type) {
12628 const proxies = chart.$proxies || (chart.$proxies = {});
12629 const proxy = proxies[type];
12630 if (!proxy) {
12631 return;
12632 }
12633 const handlers = {
12634 attach: releaseObserver,
12635 detach: releaseObserver,
12636 resize: releaseObserver
12637 };
12638 const handler = handlers[type] || removeListener;
12639 handler(chart, type, proxy);
12640 proxies[type] = undefined;
12641 }
12642 getDevicePixelRatio() {
12643 return window.devicePixelRatio;
12644 }
12645 getMaximumSize(canvas, width, height, aspectRatio) {
12646 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.G)(canvas, width, height, aspectRatio);
12647 }
12648 isAttached(canvas) {
12649 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12650 return !!(container && container.isConnected);
12651 }
12652 }
12653
12654 function _detectPlatform(canvas) {
12655 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
12656 return BasicPlatform;
12657 }
12658 return DomPlatform;
12659 }
12660
12661 class Element {
12662 static defaults = {};
12663 static defaultRoutes = undefined;
12664 x;
12665 y;
12666 active = false;
12667 options;
12668 $animations;
12669 tooltipPosition(useFinalPosition) {
12670 const { x , y } = this.getProps([
12671 'x',
12672 'y'
12673 ], useFinalPosition);
12674 return {
12675 x,
12676 y
12677 };
12678 }
12679 hasValue() {
12680 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);
12681 }
12682 getProps(props, final) {
12683 const anims = this.$animations;
12684 if (!final || !anims) {
12685 // let's not create an object, if not needed
12686 return this;
12687 }
12688 const ret = {};
12689 props.forEach((prop)=>{
12690 ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
12691 });
12692 return ret;
12693 }
12694 }
12695
12696 function autoSkip(scale, ticks) {
12697 const tickOpts = scale.options.ticks;
12698 const determinedMaxTicks = determineMaxTicks(scale);
12699 const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);
12700 const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
12701 const numMajorIndices = majorIndices.length;
12702 const first = majorIndices[0];
12703 const last = majorIndices[numMajorIndices - 1];
12704 const newTicks = [];
12705 if (numMajorIndices > ticksLimit) {
12706 skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
12707 return newTicks;
12708 }
12709 const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
12710 if (numMajorIndices > 0) {
12711 let i, ilen;
12712 const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
12713 skip(ticks, newTicks, spacing, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
12714 for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){
12715 skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
12716 }
12717 skip(ticks, newTicks, spacing, last, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
12718 return newTicks;
12719 }
12720 skip(ticks, newTicks, spacing);
12721 return newTicks;
12722 }
12723 function determineMaxTicks(scale) {
12724 const offset = scale.options.offset;
12725 const tickLength = scale._tickSize();
12726 const maxScale = scale._length / tickLength + (offset ? 0 : 1);
12727 const maxChart = scale._maxLength / tickLength;
12728 return Math.floor(Math.min(maxScale, maxChart));
12729 }
12730 function calculateSpacing(majorIndices, ticks, ticksLimit) {
12731 const evenMajorSpacing = getEvenSpacing(majorIndices);
12732 const spacing = ticks.length / ticksLimit;
12733 if (!evenMajorSpacing) {
12734 return Math.max(spacing, 1);
12735 }
12736 const factors = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.N)(evenMajorSpacing);
12737 for(let i = 0, ilen = factors.length - 1; i < ilen; i++){
12738 const factor = factors[i];
12739 if (factor > spacing) {
12740 return factor;
12741 }
12742 }
12743 return Math.max(spacing, 1);
12744 }
12745 function getMajorIndices(ticks) {
12746 const result = [];
12747 let i, ilen;
12748 for(i = 0, ilen = ticks.length; i < ilen; i++){
12749 if (ticks[i].major) {
12750 result.push(i);
12751 }
12752 }
12753 return result;
12754 }
12755 function skipMajors(ticks, newTicks, majorIndices, spacing) {
12756 let count = 0;
12757 let next = majorIndices[0];
12758 let i;
12759 spacing = Math.ceil(spacing);
12760 for(i = 0; i < ticks.length; i++){
12761 if (i === next) {
12762 newTicks.push(ticks[i]);
12763 count++;
12764 next = majorIndices[count * spacing];
12765 }
12766 }
12767 }
12768 function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
12769 const start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorStart, 0);
12770 const end = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorEnd, ticks.length), ticks.length);
12771 let count = 0;
12772 let length, i, next;
12773 spacing = Math.ceil(spacing);
12774 if (majorEnd) {
12775 length = majorEnd - majorStart;
12776 spacing = length / Math.floor(length / spacing);
12777 }
12778 next = start;
12779 while(next < 0){
12780 count++;
12781 next = Math.round(start + count * spacing);
12782 }
12783 for(i = Math.max(start, 0); i < end; i++){
12784 if (i === next) {
12785 newTicks.push(ticks[i]);
12786 count++;
12787 next = Math.round(start + count * spacing);
12788 }
12789 }
12790 }
12791 function getEvenSpacing(arr) {
12792 const len = arr.length;
12793 let i, diff;
12794 if (len < 2) {
12795 return false;
12796 }
12797 for(diff = arr[0], i = 1; i < len; ++i){
12798 if (arr[i] - arr[i - 1] !== diff) {
12799 return false;
12800 }
12801 }
12802 return diff;
12803 }
12804
12805 const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align;
12806 const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
12807 const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength);
12808 function sample(arr, numItems) {
12809 const result = [];
12810 const increment = arr.length / numItems;
12811 const len = arr.length;
12812 let i = 0;
12813 for(; i < len; i += increment){
12814 result.push(arr[Math.floor(i)]);
12815 }
12816 return result;
12817 }
12818 function getPixelForGridLine(scale, index, offsetGridLines) {
12819 const length = scale.ticks.length;
12820 const validIndex = Math.min(index, length - 1);
12821 const start = scale._startPixel;
12822 const end = scale._endPixel;
12823 const epsilon = 1e-6;
12824 let lineValue = scale.getPixelForTick(validIndex);
12825 let offset;
12826 if (offsetGridLines) {
12827 if (length === 1) {
12828 offset = Math.max(lineValue - start, end - lineValue);
12829 } else if (index === 0) {
12830 offset = (scale.getPixelForTick(1) - lineValue) / 2;
12831 } else {
12832 offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
12833 }
12834 lineValue += validIndex < index ? offset : -offset;
12835 if (lineValue < start - epsilon || lineValue > end + epsilon) {
12836 return;
12837 }
12838 }
12839 return lineValue;
12840 }
12841 function garbageCollect(caches, length) {
12842 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(caches, (cache)=>{
12843 const gc = cache.gc;
12844 const gcLen = gc.length / 2;
12845 let i;
12846 if (gcLen > length) {
12847 for(i = 0; i < gcLen; ++i){
12848 delete cache.data[gc[i]];
12849 }
12850 gc.splice(0, gcLen);
12851 }
12852 });
12853 }
12854 function getTickMarkLength(options) {
12855 return options.drawTicks ? options.tickLength : 0;
12856 }
12857 function getTitleHeight(options, fallback) {
12858 if (!options.display) {
12859 return 0;
12860 }
12861 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.font, fallback);
12862 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
12863 const lines = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(options.text) ? options.text.length : 1;
12864 return lines * font.lineHeight + padding.height;
12865 }
12866 function createScaleContext(parent, scale) {
12867 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12868 scale,
12869 type: 'scale'
12870 });
12871 }
12872 function createTickContext(parent, index, tick) {
12873 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12874 tick,
12875 index,
12876 type: 'tick'
12877 });
12878 }
12879 function titleAlign(align, position, reverse) {
12880 let ret = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(align);
12881 if (reverse && position !== 'right' || !reverse && position === 'right') {
12882 ret = reverseAlign(ret);
12883 }
12884 return ret;
12885 }
12886 function titleArgs(scale, offset, position, align) {
12887 const { top , left , bottom , right , chart } = scale;
12888 const { chartArea , scales } = chart;
12889 let rotation = 0;
12890 let maxWidth, titleX, titleY;
12891 const height = bottom - top;
12892 const width = right - left;
12893 if (scale.isHorizontal()) {
12894 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
12895 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12896 const positionAxisID = Object.keys(position)[0];
12897 const value = position[positionAxisID];
12898 titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
12899 } else if (position === 'center') {
12900 titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
12901 } else {
12902 titleY = offsetFromEdge(scale, position, offset);
12903 }
12904 maxWidth = right - left;
12905 } else {
12906 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12907 const positionAxisID = Object.keys(position)[0];
12908 const value = position[positionAxisID];
12909 titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
12910 } else if (position === 'center') {
12911 titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
12912 } else {
12913 titleX = offsetFromEdge(scale, position, offset);
12914 }
12915 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
12916 rotation = position === 'left' ? -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H;
12917 }
12918 return {
12919 titleX,
12920 titleY,
12921 maxWidth,
12922 rotation
12923 };
12924 }
12925 class Scale extends Element {
12926 constructor(cfg){
12927 super();
12928 this.id = cfg.id;
12929 this.type = cfg.type;
12930 this.options = undefined;
12931 this.ctx = cfg.ctx;
12932 this.chart = cfg.chart;
12933 this.top = undefined;
12934 this.bottom = undefined;
12935 this.left = undefined;
12936 this.right = undefined;
12937 this.width = undefined;
12938 this.height = undefined;
12939 this._margins = {
12940 left: 0,
12941 right: 0,
12942 top: 0,
12943 bottom: 0
12944 };
12945 this.maxWidth = undefined;
12946 this.maxHeight = undefined;
12947 this.paddingTop = undefined;
12948 this.paddingBottom = undefined;
12949 this.paddingLeft = undefined;
12950 this.paddingRight = undefined;
12951 this.axis = undefined;
12952 this.labelRotation = undefined;
12953 this.min = undefined;
12954 this.max = undefined;
12955 this._range = undefined;
12956 this.ticks = [];
12957 this._gridLineItems = null;
12958 this._labelItems = null;
12959 this._labelSizes = null;
12960 this._length = 0;
12961 this._maxLength = 0;
12962 this._longestTextCache = {};
12963 this._startPixel = undefined;
12964 this._endPixel = undefined;
12965 this._reversePixels = false;
12966 this._userMax = undefined;
12967 this._userMin = undefined;
12968 this._suggestedMax = undefined;
12969 this._suggestedMin = undefined;
12970 this._ticksLength = 0;
12971 this._borderValue = 0;
12972 this._cache = {};
12973 this._dataLimitsCached = false;
12974 this.$context = undefined;
12975 }
12976 init(options) {
12977 this.options = options.setContext(this.getContext());
12978 this.axis = options.axis;
12979 this._userMin = this.parse(options.min);
12980 this._userMax = this.parse(options.max);
12981 this._suggestedMin = this.parse(options.suggestedMin);
12982 this._suggestedMax = this.parse(options.suggestedMax);
12983 }
12984 parse(raw, index) {
12985 return raw;
12986 }
12987 getUserBounds() {
12988 let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this;
12989 _userMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, Number.POSITIVE_INFINITY);
12990 _userMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, Number.NEGATIVE_INFINITY);
12991 _suggestedMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMin, Number.POSITIVE_INFINITY);
12992 _suggestedMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMax, Number.NEGATIVE_INFINITY);
12993 return {
12994 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, _suggestedMin),
12995 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, _suggestedMax),
12996 minDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMin),
12997 maxDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMax)
12998 };
12999 }
13000 getMinMax(canStack) {
13001 let { min , max , minDefined , maxDefined } = this.getUserBounds();
13002 let range;
13003 if (minDefined && maxDefined) {
13004 return {
13005 min,
13006 max
13007 };
13008 }
13009 const metas = this.getMatchingVisibleMetas();
13010 for(let i = 0, ilen = metas.length; i < ilen; ++i){
13011 range = metas[i].controller.getMinMax(this, canStack);
13012 if (!minDefined) {
13013 min = Math.min(min, range.min);
13014 }
13015 if (!maxDefined) {
13016 max = Math.max(max, range.max);
13017 }
13018 }
13019 min = maxDefined && min > max ? max : min;
13020 max = minDefined && min > max ? min : max;
13021 return {
13022 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, min)),
13023 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, max))
13024 };
13025 }
13026 getPadding() {
13027 return {
13028 left: this.paddingLeft || 0,
13029 top: this.paddingTop || 0,
13030 right: this.paddingRight || 0,
13031 bottom: this.paddingBottom || 0
13032 };
13033 }
13034 getTicks() {
13035 return this.ticks;
13036 }
13037 getLabels() {
13038 const data = this.chart.data;
13039 return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
13040 }
13041 getLabelItems(chartArea = this.chart.chartArea) {
13042 const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
13043 return items;
13044 }
13045 beforeLayout() {
13046 this._cache = {};
13047 this._dataLimitsCached = false;
13048 }
13049 beforeUpdate() {
13050 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeUpdate, [
13051 this
13052 ]);
13053 }
13054 update(maxWidth, maxHeight, margins) {
13055 const { beginAtZero , grace , ticks: tickOpts } = this.options;
13056 const sampleSize = tickOpts.sampleSize;
13057 this.beforeUpdate();
13058 this.maxWidth = maxWidth;
13059 this.maxHeight = maxHeight;
13060 this._margins = margins = Object.assign({
13061 left: 0,
13062 right: 0,
13063 top: 0,
13064 bottom: 0
13065 }, margins);
13066 this.ticks = null;
13067 this._labelSizes = null;
13068 this._gridLineItems = null;
13069 this._labelItems = null;
13070 this.beforeSetDimensions();
13071 this.setDimensions();
13072 this.afterSetDimensions();
13073 this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;
13074 if (!this._dataLimitsCached) {
13075 this.beforeDataLimits();
13076 this.determineDataLimits();
13077 this.afterDataLimits();
13078 this._range = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.R)(this, grace, beginAtZero);
13079 this._dataLimitsCached = true;
13080 }
13081 this.beforeBuildTicks();
13082 this.ticks = this.buildTicks() || [];
13083 this.afterBuildTicks();
13084 const samplingEnabled = sampleSize < this.ticks.length;
13085 this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
13086 this.configure();
13087 this.beforeCalculateLabelRotation();
13088 this.calculateLabelRotation();
13089 this.afterCalculateLabelRotation();
13090 if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
13091 this.ticks = autoSkip(this, this.ticks);
13092 this._labelSizes = null;
13093 this.afterAutoSkip();
13094 }
13095 if (samplingEnabled) {
13096 this._convertTicksToLabels(this.ticks);
13097 }
13098 this.beforeFit();
13099 this.fit();
13100 this.afterFit();
13101 this.afterUpdate();
13102 }
13103 configure() {
13104 let reversePixels = this.options.reverse;
13105 let startPixel, endPixel;
13106 if (this.isHorizontal()) {
13107 startPixel = this.left;
13108 endPixel = this.right;
13109 } else {
13110 startPixel = this.top;
13111 endPixel = this.bottom;
13112 reversePixels = !reversePixels;
13113 }
13114 this._startPixel = startPixel;
13115 this._endPixel = endPixel;
13116 this._reversePixels = reversePixels;
13117 this._length = endPixel - startPixel;
13118 this._alignToPixels = this.options.alignToPixels;
13119 }
13120 afterUpdate() {
13121 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterUpdate, [
13122 this
13123 ]);
13124 }
13125 beforeSetDimensions() {
13126 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeSetDimensions, [
13127 this
13128 ]);
13129 }
13130 setDimensions() {
13131 if (this.isHorizontal()) {
13132 this.width = this.maxWidth;
13133 this.left = 0;
13134 this.right = this.width;
13135 } else {
13136 this.height = this.maxHeight;
13137 this.top = 0;
13138 this.bottom = this.height;
13139 }
13140 this.paddingLeft = 0;
13141 this.paddingTop = 0;
13142 this.paddingRight = 0;
13143 this.paddingBottom = 0;
13144 }
13145 afterSetDimensions() {
13146 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterSetDimensions, [
13147 this
13148 ]);
13149 }
13150 _callHooks(name) {
13151 this.chart.notifyPlugins(name, this.getContext());
13152 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options[name], [
13153 this
13154 ]);
13155 }
13156 beforeDataLimits() {
13157 this._callHooks('beforeDataLimits');
13158 }
13159 determineDataLimits() {}
13160 afterDataLimits() {
13161 this._callHooks('afterDataLimits');
13162 }
13163 beforeBuildTicks() {
13164 this._callHooks('beforeBuildTicks');
13165 }
13166 buildTicks() {
13167 return [];
13168 }
13169 afterBuildTicks() {
13170 this._callHooks('afterBuildTicks');
13171 }
13172 beforeTickToLabelConversion() {
13173 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeTickToLabelConversion, [
13174 this
13175 ]);
13176 }
13177 generateTickLabels(ticks) {
13178 const tickOpts = this.options.ticks;
13179 let i, ilen, tick;
13180 for(i = 0, ilen = ticks.length; i < ilen; i++){
13181 tick = ticks[i];
13182 tick.label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(tickOpts.callback, [
13183 tick.value,
13184 i,
13185 ticks
13186 ], this);
13187 }
13188 }
13189 afterTickToLabelConversion() {
13190 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterTickToLabelConversion, [
13191 this
13192 ]);
13193 }
13194 beforeCalculateLabelRotation() {
13195 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeCalculateLabelRotation, [
13196 this
13197 ]);
13198 }
13199 calculateLabelRotation() {
13200 const options = this.options;
13201 const tickOpts = options.ticks;
13202 const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);
13203 const minRotation = tickOpts.minRotation || 0;
13204 const maxRotation = tickOpts.maxRotation;
13205 let labelRotation = minRotation;
13206 let tickWidth, maxHeight, maxLabelDiagonal;
13207 if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
13208 this.labelRotation = minRotation;
13209 return;
13210 }
13211 const labelSizes = this._getLabelSizes();
13212 const maxLabelWidth = labelSizes.widest.width;
13213 const maxLabelHeight = labelSizes.highest.height;
13214 const maxWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(this.chart.width - maxLabelWidth, 0, this.maxWidth);
13215 tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
13216 if (maxLabelWidth + 6 > tickWidth) {
13217 tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
13218 maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
13219 maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
13220 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))));
13221 labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
13222 }
13223 this.labelRotation = labelRotation;
13224 }
13225 afterCalculateLabelRotation() {
13226 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterCalculateLabelRotation, [
13227 this
13228 ]);
13229 }
13230 afterAutoSkip() {}
13231 beforeFit() {
13232 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeFit, [
13233 this
13234 ]);
13235 }
13236 fit() {
13237 const minSize = {
13238 width: 0,
13239 height: 0
13240 };
13241 const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this;
13242 const display = this._isVisible();
13243 const isHorizontal = this.isHorizontal();
13244 if (display) {
13245 const titleHeight = getTitleHeight(titleOpts, chart.options.font);
13246 if (isHorizontal) {
13247 minSize.width = this.maxWidth;
13248 minSize.height = getTickMarkLength(gridOpts) + titleHeight;
13249 } else {
13250 minSize.height = this.maxHeight;
13251 minSize.width = getTickMarkLength(gridOpts) + titleHeight;
13252 }
13253 if (tickOpts.display && this.ticks.length) {
13254 const { first , last , widest , highest } = this._getLabelSizes();
13255 const tickPadding = tickOpts.padding * 2;
13256 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13257 const cos = Math.cos(angleRadians);
13258 const sin = Math.sin(angleRadians);
13259 if (isHorizontal) {
13260 const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
13261 minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
13262 } else {
13263 const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
13264 minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
13265 }
13266 this._calculatePadding(first, last, sin, cos);
13267 }
13268 }
13269 this._handleMargins();
13270 if (isHorizontal) {
13271 this.width = this._length = chart.width - this._margins.left - this._margins.right;
13272 this.height = minSize.height;
13273 } else {
13274 this.width = minSize.width;
13275 this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
13276 }
13277 }
13278 _calculatePadding(first, last, sin, cos) {
13279 const { ticks: { align , padding } , position } = this.options;
13280 const isRotated = this.labelRotation !== 0;
13281 const labelsBelowTicks = position !== 'top' && this.axis === 'x';
13282 if (this.isHorizontal()) {
13283 const offsetLeft = this.getPixelForTick(0) - this.left;
13284 const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
13285 let paddingLeft = 0;
13286 let paddingRight = 0;
13287 if (isRotated) {
13288 if (labelsBelowTicks) {
13289 paddingLeft = cos * first.width;
13290 paddingRight = sin * last.height;
13291 } else {
13292 paddingLeft = sin * first.height;
13293 paddingRight = cos * last.width;
13294 }
13295 } else if (align === 'start') {
13296 paddingRight = last.width;
13297 } else if (align === 'end') {
13298 paddingLeft = first.width;
13299 } else if (align !== 'inner') {
13300 paddingLeft = first.width / 2;
13301 paddingRight = last.width / 2;
13302 }
13303 this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
13304 this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
13305 } else {
13306 let paddingTop = last.height / 2;
13307 let paddingBottom = first.height / 2;
13308 if (align === 'start') {
13309 paddingTop = 0;
13310 paddingBottom = first.height;
13311 } else if (align === 'end') {
13312 paddingTop = last.height;
13313 paddingBottom = 0;
13314 }
13315 this.paddingTop = paddingTop + padding;
13316 this.paddingBottom = paddingBottom + padding;
13317 }
13318 }
13319 _handleMargins() {
13320 if (this._margins) {
13321 this._margins.left = Math.max(this.paddingLeft, this._margins.left);
13322 this._margins.top = Math.max(this.paddingTop, this._margins.top);
13323 this._margins.right = Math.max(this.paddingRight, this._margins.right);
13324 this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
13325 }
13326 }
13327 afterFit() {
13328 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterFit, [
13329 this
13330 ]);
13331 }
13332 isHorizontal() {
13333 const { axis , position } = this.options;
13334 return position === 'top' || position === 'bottom' || axis === 'x';
13335 }
13336 isFullSize() {
13337 return this.options.fullSize;
13338 }
13339 _convertTicksToLabels(ticks) {
13340 this.beforeTickToLabelConversion();
13341 this.generateTickLabels(ticks);
13342 let i, ilen;
13343 for(i = 0, ilen = ticks.length; i < ilen; i++){
13344 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(ticks[i].label)) {
13345 ticks.splice(i, 1);
13346 ilen--;
13347 i--;
13348 }
13349 }
13350 this.afterTickToLabelConversion();
13351 }
13352 _getLabelSizes() {
13353 let labelSizes = this._labelSizes;
13354 if (!labelSizes) {
13355 const sampleSize = this.options.ticks.sampleSize;
13356 let ticks = this.ticks;
13357 if (sampleSize < ticks.length) {
13358 ticks = sample(ticks, sampleSize);
13359 }
13360 this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);
13361 }
13362 return labelSizes;
13363 }
13364 _computeLabelSizes(ticks, length, maxTicksLimit) {
13365 const { ctx , _longestTextCache: caches } = this;
13366 const widths = [];
13367 const heights = [];
13368 const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));
13369 let widestLabelSize = 0;
13370 let highestLabelSize = 0;
13371 let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
13372 for(i = 0; i < length; i += increment){
13373 label = ticks[i].label;
13374 tickFont = this._resolveTickFontOptions(i);
13375 ctx.font = fontString = tickFont.string;
13376 cache = caches[fontString] = caches[fontString] || {
13377 data: {},
13378 gc: []
13379 };
13380 lineHeight = tickFont.lineHeight;
13381 width = height = 0;
13382 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(label) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13383 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, label);
13384 height = lineHeight;
13385 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13386 for(j = 0, jlen = label.length; j < jlen; ++j){
13387 nestedLabel = label[j];
13388 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(nestedLabel) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(nestedLabel)) {
13389 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, nestedLabel);
13390 height += lineHeight;
13391 }
13392 }
13393 }
13394 widths.push(width);
13395 heights.push(height);
13396 widestLabelSize = Math.max(width, widestLabelSize);
13397 highestLabelSize = Math.max(height, highestLabelSize);
13398 }
13399 garbageCollect(caches, length);
13400 const widest = widths.indexOf(widestLabelSize);
13401 const highest = heights.indexOf(highestLabelSize);
13402 const valueAt = (idx)=>({
13403 width: widths[idx] || 0,
13404 height: heights[idx] || 0
13405 });
13406 return {
13407 first: valueAt(0),
13408 last: valueAt(length - 1),
13409 widest: valueAt(widest),
13410 highest: valueAt(highest),
13411 widths,
13412 heights
13413 };
13414 }
13415 getLabelForValue(value) {
13416 return value;
13417 }
13418 getPixelForValue(value, index) {
13419 return NaN;
13420 }
13421 getValueForPixel(pixel) {}
13422 getPixelForTick(index) {
13423 const ticks = this.ticks;
13424 if (index < 0 || index > ticks.length - 1) {
13425 return null;
13426 }
13427 return this.getPixelForValue(ticks[index].value);
13428 }
13429 getPixelForDecimal(decimal) {
13430 if (this._reversePixels) {
13431 decimal = 1 - decimal;
13432 }
13433 const pixel = this._startPixel + decimal * this._length;
13434 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);
13435 }
13436 getDecimalForPixel(pixel) {
13437 const decimal = (pixel - this._startPixel) / this._length;
13438 return this._reversePixels ? 1 - decimal : decimal;
13439 }
13440 getBasePixel() {
13441 return this.getPixelForValue(this.getBaseValue());
13442 }
13443 getBaseValue() {
13444 const { min , max } = this;
13445 return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;
13446 }
13447 getContext(index) {
13448 const ticks = this.ticks || [];
13449 if (index >= 0 && index < ticks.length) {
13450 const tick = ticks[index];
13451 return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));
13452 }
13453 return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));
13454 }
13455 _tickSize() {
13456 const optionTicks = this.options.ticks;
13457 const rot = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13458 const cos = Math.abs(Math.cos(rot));
13459 const sin = Math.abs(Math.sin(rot));
13460 const labelSizes = this._getLabelSizes();
13461 const padding = optionTicks.autoSkipPadding || 0;
13462 const w = labelSizes ? labelSizes.widest.width + padding : 0;
13463 const h = labelSizes ? labelSizes.highest.height + padding : 0;
13464 return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin;
13465 }
13466 _isVisible() {
13467 const display = this.options.display;
13468 if (display !== 'auto') {
13469 return !!display;
13470 }
13471 return this.getMatchingVisibleMetas().length > 0;
13472 }
13473 _computeGridLineItems(chartArea) {
13474 const axis = this.axis;
13475 const chart = this.chart;
13476 const options = this.options;
13477 const { grid , position , border } = options;
13478 const offset = grid.offset;
13479 const isHorizontal = this.isHorizontal();
13480 const ticks = this.ticks;
13481 const ticksLength = ticks.length + (offset ? 1 : 0);
13482 const tl = getTickMarkLength(grid);
13483 const items = [];
13484 const borderOpts = border.setContext(this.getContext());
13485 const axisWidth = borderOpts.display ? borderOpts.width : 0;
13486 const axisHalfWidth = axisWidth / 2;
13487 const alignBorderValue = function(pixel) {
13488 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, pixel, axisWidth);
13489 };
13490 let borderValue, i, lineValue, alignedLineValue;
13491 let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
13492 if (position === 'top') {
13493 borderValue = alignBorderValue(this.bottom);
13494 ty1 = this.bottom - tl;
13495 ty2 = borderValue - axisHalfWidth;
13496 y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
13497 y2 = chartArea.bottom;
13498 } else if (position === 'bottom') {
13499 borderValue = alignBorderValue(this.top);
13500 y1 = chartArea.top;
13501 y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
13502 ty1 = borderValue + axisHalfWidth;
13503 ty2 = this.top + tl;
13504 } else if (position === 'left') {
13505 borderValue = alignBorderValue(this.right);
13506 tx1 = this.right - tl;
13507 tx2 = borderValue - axisHalfWidth;
13508 x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
13509 x2 = chartArea.right;
13510 } else if (position === 'right') {
13511 borderValue = alignBorderValue(this.left);
13512 x1 = chartArea.left;
13513 x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
13514 tx1 = borderValue + axisHalfWidth;
13515 tx2 = this.left + tl;
13516 } else if (axis === 'x') {
13517 if (position === 'center') {
13518 borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
13519 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13520 const positionAxisID = Object.keys(position)[0];
13521 const value = position[positionAxisID];
13522 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13523 }
13524 y1 = chartArea.top;
13525 y2 = chartArea.bottom;
13526 ty1 = borderValue + axisHalfWidth;
13527 ty2 = ty1 + tl;
13528 } else if (axis === 'y') {
13529 if (position === 'center') {
13530 borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
13531 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13532 const positionAxisID = Object.keys(position)[0];
13533 const value = position[positionAxisID];
13534 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13535 }
13536 tx1 = borderValue - axisHalfWidth;
13537 tx2 = tx1 - tl;
13538 x1 = chartArea.left;
13539 x2 = chartArea.right;
13540 }
13541 const limit = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.maxTicksLimit, ticksLength);
13542 const step = Math.max(1, Math.ceil(ticksLength / limit));
13543 for(i = 0; i < ticksLength; i += step){
13544 const context = this.getContext(i);
13545 const optsAtIndex = grid.setContext(context);
13546 const optsAtIndexBorder = border.setContext(context);
13547 const lineWidth = optsAtIndex.lineWidth;
13548 const lineColor = optsAtIndex.color;
13549 const borderDash = optsAtIndexBorder.dash || [];
13550 const borderDashOffset = optsAtIndexBorder.dashOffset;
13551 const tickWidth = optsAtIndex.tickWidth;
13552 const tickColor = optsAtIndex.tickColor;
13553 const tickBorderDash = optsAtIndex.tickBorderDash || [];
13554 const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
13555 lineValue = getPixelForGridLine(this, i, offset);
13556 if (lineValue === undefined) {
13557 continue;
13558 }
13559 alignedLineValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, lineValue, lineWidth);
13560 if (isHorizontal) {
13561 tx1 = tx2 = x1 = x2 = alignedLineValue;
13562 } else {
13563 ty1 = ty2 = y1 = y2 = alignedLineValue;
13564 }
13565 items.push({
13566 tx1,
13567 ty1,
13568 tx2,
13569 ty2,
13570 x1,
13571 y1,
13572 x2,
13573 y2,
13574 width: lineWidth,
13575 color: lineColor,
13576 borderDash,
13577 borderDashOffset,
13578 tickWidth,
13579 tickColor,
13580 tickBorderDash,
13581 tickBorderDashOffset
13582 });
13583 }
13584 this._ticksLength = ticksLength;
13585 this._borderValue = borderValue;
13586 return items;
13587 }
13588 _computeLabelItems(chartArea) {
13589 const axis = this.axis;
13590 const options = this.options;
13591 const { position , ticks: optionTicks } = options;
13592 const isHorizontal = this.isHorizontal();
13593 const ticks = this.ticks;
13594 const { align , crossAlign , padding , mirror } = optionTicks;
13595 const tl = getTickMarkLength(options.grid);
13596 const tickAndPadding = tl + padding;
13597 const hTickAndPadding = mirror ? -padding : tickAndPadding;
13598 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13599 const items = [];
13600 let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
13601 let textBaseline = 'middle';
13602 if (position === 'top') {
13603 y = this.bottom - hTickAndPadding;
13604 textAlign = this._getXAxisLabelAlignment();
13605 } else if (position === 'bottom') {
13606 y = this.top + hTickAndPadding;
13607 textAlign = this._getXAxisLabelAlignment();
13608 } else if (position === 'left') {
13609 const ret = this._getYAxisLabelAlignment(tl);
13610 textAlign = ret.textAlign;
13611 x = ret.x;
13612 } else if (position === 'right') {
13613 const ret = this._getYAxisLabelAlignment(tl);
13614 textAlign = ret.textAlign;
13615 x = ret.x;
13616 } else if (axis === 'x') {
13617 if (position === 'center') {
13618 y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;
13619 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13620 const positionAxisID = Object.keys(position)[0];
13621 const value = position[positionAxisID];
13622 y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
13623 }
13624 textAlign = this._getXAxisLabelAlignment();
13625 } else if (axis === 'y') {
13626 if (position === 'center') {
13627 x = (chartArea.left + chartArea.right) / 2 - tickAndPadding;
13628 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13629 const positionAxisID = Object.keys(position)[0];
13630 const value = position[positionAxisID];
13631 x = this.chart.scales[positionAxisID].getPixelForValue(value);
13632 }
13633 textAlign = this._getYAxisLabelAlignment(tl).textAlign;
13634 }
13635 if (axis === 'y') {
13636 if (align === 'start') {
13637 textBaseline = 'top';
13638 } else if (align === 'end') {
13639 textBaseline = 'bottom';
13640 }
13641 }
13642 const labelSizes = this._getLabelSizes();
13643 for(i = 0, ilen = ticks.length; i < ilen; ++i){
13644 tick = ticks[i];
13645 label = tick.label;
13646 const optsAtIndex = optionTicks.setContext(this.getContext(i));
13647 pixel = this.getPixelForTick(i) + optionTicks.labelOffset;
13648 font = this._resolveTickFontOptions(i);
13649 lineHeight = font.lineHeight;
13650 lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label.length : 1;
13651 const halfCount = lineCount / 2;
13652 const color = optsAtIndex.color;
13653 const strokeColor = optsAtIndex.textStrokeColor;
13654 const strokeWidth = optsAtIndex.textStrokeWidth;
13655 let tickTextAlign = textAlign;
13656 if (isHorizontal) {
13657 x = pixel;
13658 if (textAlign === 'inner') {
13659 if (i === ilen - 1) {
13660 tickTextAlign = !this.options.reverse ? 'right' : 'left';
13661 } else if (i === 0) {
13662 tickTextAlign = !this.options.reverse ? 'left' : 'right';
13663 } else {
13664 tickTextAlign = 'center';
13665 }
13666 }
13667 if (position === 'top') {
13668 if (crossAlign === 'near' || rotation !== 0) {
13669 textOffset = -lineCount * lineHeight + lineHeight / 2;
13670 } else if (crossAlign === 'center') {
13671 textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
13672 } else {
13673 textOffset = -labelSizes.highest.height + lineHeight / 2;
13674 }
13675 } else {
13676 if (crossAlign === 'near' || rotation !== 0) {
13677 textOffset = lineHeight / 2;
13678 } else if (crossAlign === 'center') {
13679 textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
13680 } else {
13681 textOffset = labelSizes.highest.height - lineCount * lineHeight;
13682 }
13683 }
13684 if (mirror) {
13685 textOffset *= -1;
13686 }
13687 if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {
13688 x += lineHeight / 2 * Math.sin(rotation);
13689 }
13690 } else {
13691 y = pixel;
13692 textOffset = (1 - lineCount) * lineHeight / 2;
13693 }
13694 let backdrop;
13695 if (optsAtIndex.showLabelBackdrop) {
13696 const labelPadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
13697 const height = labelSizes.heights[i];
13698 const width = labelSizes.widths[i];
13699 let top = textOffset - labelPadding.top;
13700 let left = 0 - labelPadding.left;
13701 switch(textBaseline){
13702 case 'middle':
13703 top -= height / 2;
13704 break;
13705 case 'bottom':
13706 top -= height;
13707 break;
13708 }
13709 switch(textAlign){
13710 case 'center':
13711 left -= width / 2;
13712 break;
13713 case 'right':
13714 left -= width;
13715 break;
13716 case 'inner':
13717 if (i === ilen - 1) {
13718 left -= width;
13719 } else if (i > 0) {
13720 left -= width / 2;
13721 }
13722 break;
13723 }
13724 backdrop = {
13725 left,
13726 top,
13727 width: width + labelPadding.width,
13728 height: height + labelPadding.height,
13729 color: optsAtIndex.backdropColor
13730 };
13731 }
13732 items.push({
13733 label,
13734 font,
13735 textOffset,
13736 options: {
13737 rotation,
13738 color,
13739 strokeColor,
13740 strokeWidth,
13741 textAlign: tickTextAlign,
13742 textBaseline,
13743 translation: [
13744 x,
13745 y
13746 ],
13747 backdrop
13748 }
13749 });
13750 }
13751 return items;
13752 }
13753 _getXAxisLabelAlignment() {
13754 const { position , ticks } = this.options;
13755 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13756 if (rotation) {
13757 return position === 'top' ? 'left' : 'right';
13758 }
13759 let align = 'center';
13760 if (ticks.align === 'start') {
13761 align = 'left';
13762 } else if (ticks.align === 'end') {
13763 align = 'right';
13764 } else if (ticks.align === 'inner') {
13765 align = 'inner';
13766 }
13767 return align;
13768 }
13769 _getYAxisLabelAlignment(tl) {
13770 const { position , ticks: { crossAlign , mirror , padding } } = this.options;
13771 const labelSizes = this._getLabelSizes();
13772 const tickAndPadding = tl + padding;
13773 const widest = labelSizes.widest.width;
13774 let textAlign;
13775 let x;
13776 if (position === 'left') {
13777 if (mirror) {
13778 x = this.right + padding;
13779 if (crossAlign === 'near') {
13780 textAlign = 'left';
13781 } else if (crossAlign === 'center') {
13782 textAlign = 'center';
13783 x += widest / 2;
13784 } else {
13785 textAlign = 'right';
13786 x += widest;
13787 }
13788 } else {
13789 x = this.right - tickAndPadding;
13790 if (crossAlign === 'near') {
13791 textAlign = 'right';
13792 } else if (crossAlign === 'center') {
13793 textAlign = 'center';
13794 x -= widest / 2;
13795 } else {
13796 textAlign = 'left';
13797 x = this.left;
13798 }
13799 }
13800 } else if (position === 'right') {
13801 if (mirror) {
13802 x = this.left + padding;
13803 if (crossAlign === 'near') {
13804 textAlign = 'right';
13805 } else if (crossAlign === 'center') {
13806 textAlign = 'center';
13807 x -= widest / 2;
13808 } else {
13809 textAlign = 'left';
13810 x -= widest;
13811 }
13812 } else {
13813 x = this.left + tickAndPadding;
13814 if (crossAlign === 'near') {
13815 textAlign = 'left';
13816 } else if (crossAlign === 'center') {
13817 textAlign = 'center';
13818 x += widest / 2;
13819 } else {
13820 textAlign = 'right';
13821 x = this.right;
13822 }
13823 }
13824 } else {
13825 textAlign = 'right';
13826 }
13827 return {
13828 textAlign,
13829 x
13830 };
13831 }
13832 _computeLabelArea() {
13833 if (this.options.ticks.mirror) {
13834 return;
13835 }
13836 const chart = this.chart;
13837 const position = this.options.position;
13838 if (position === 'left' || position === 'right') {
13839 return {
13840 top: 0,
13841 left: this.left,
13842 bottom: chart.height,
13843 right: this.right
13844 };
13845 }
13846 if (position === 'top' || position === 'bottom') {
13847 return {
13848 top: this.top,
13849 left: 0,
13850 bottom: this.bottom,
13851 right: chart.width
13852 };
13853 }
13854 }
13855 drawBackground() {
13856 const { ctx , options: { backgroundColor } , left , top , width , height } = this;
13857 if (backgroundColor) {
13858 ctx.save();
13859 ctx.fillStyle = backgroundColor;
13860 ctx.fillRect(left, top, width, height);
13861 ctx.restore();
13862 }
13863 }
13864 getLineWidthForValue(value) {
13865 const grid = this.options.grid;
13866 if (!this._isVisible() || !grid.display) {
13867 return 0;
13868 }
13869 const ticks = this.ticks;
13870 const index = ticks.findIndex((t)=>t.value === value);
13871 if (index >= 0) {
13872 const opts = grid.setContext(this.getContext(index));
13873 return opts.lineWidth;
13874 }
13875 return 0;
13876 }
13877 drawGrid(chartArea) {
13878 const grid = this.options.grid;
13879 const ctx = this.ctx;
13880 const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
13881 let i, ilen;
13882 const drawLine = (p1, p2, style)=>{
13883 if (!style.width || !style.color) {
13884 return;
13885 }
13886 ctx.save();
13887 ctx.lineWidth = style.width;
13888 ctx.strokeStyle = style.color;
13889 ctx.setLineDash(style.borderDash || []);
13890 ctx.lineDashOffset = style.borderDashOffset;
13891 ctx.beginPath();
13892 ctx.moveTo(p1.x, p1.y);
13893 ctx.lineTo(p2.x, p2.y);
13894 ctx.stroke();
13895 ctx.restore();
13896 };
13897 if (grid.display) {
13898 for(i = 0, ilen = items.length; i < ilen; ++i){
13899 const item = items[i];
13900 if (grid.drawOnChartArea) {
13901 drawLine({
13902 x: item.x1,
13903 y: item.y1
13904 }, {
13905 x: item.x2,
13906 y: item.y2
13907 }, item);
13908 }
13909 if (grid.drawTicks) {
13910 drawLine({
13911 x: item.tx1,
13912 y: item.ty1
13913 }, {
13914 x: item.tx2,
13915 y: item.ty2
13916 }, {
13917 color: item.tickColor,
13918 width: item.tickWidth,
13919 borderDash: item.tickBorderDash,
13920 borderDashOffset: item.tickBorderDashOffset
13921 });
13922 }
13923 }
13924 }
13925 }
13926 drawBorder() {
13927 const { chart , ctx , options: { border , grid } } = this;
13928 const borderOpts = border.setContext(this.getContext());
13929 const axisWidth = border.display ? borderOpts.width : 0;
13930 if (!axisWidth) {
13931 return;
13932 }
13933 const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
13934 const borderValue = this._borderValue;
13935 let x1, x2, y1, y2;
13936 if (this.isHorizontal()) {
13937 x1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.left, axisWidth) - axisWidth / 2;
13938 x2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.right, lastLineWidth) + lastLineWidth / 2;
13939 y1 = y2 = borderValue;
13940 } else {
13941 y1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.top, axisWidth) - axisWidth / 2;
13942 y2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
13943 x1 = x2 = borderValue;
13944 }
13945 ctx.save();
13946 ctx.lineWidth = borderOpts.width;
13947 ctx.strokeStyle = borderOpts.color;
13948 ctx.beginPath();
13949 ctx.moveTo(x1, y1);
13950 ctx.lineTo(x2, y2);
13951 ctx.stroke();
13952 ctx.restore();
13953 }
13954 drawLabels(chartArea) {
13955 const optionTicks = this.options.ticks;
13956 if (!optionTicks.display) {
13957 return;
13958 }
13959 const ctx = this.ctx;
13960 const area = this._computeLabelArea();
13961 if (area) {
13962 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
13963 }
13964 const items = this.getLabelItems(chartArea);
13965 for (const item of items){
13966 const renderTextOptions = item.options;
13967 const tickFont = item.font;
13968 const label = item.label;
13969 const y = item.textOffset;
13970 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, label, 0, y, tickFont, renderTextOptions);
13971 }
13972 if (area) {
13973 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
13974 }
13975 }
13976 drawTitle() {
13977 const { ctx , options: { position , title , reverse } } = this;
13978 if (!title.display) {
13979 return;
13980 }
13981 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(title.font);
13982 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(title.padding);
13983 const align = title.align;
13984 let offset = font.lineHeight / 2;
13985 if (position === 'bottom' || position === 'center' || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13986 offset += padding.bottom;
13987 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(title.text)) {
13988 offset += font.lineHeight * (title.text.length - 1);
13989 }
13990 } else {
13991 offset += padding.top;
13992 }
13993 const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align);
13994 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, title.text, 0, 0, font, {
13995 color: title.color,
13996 maxWidth,
13997 rotation,
13998 textAlign: titleAlign(align, position, reverse),
13999 textBaseline: 'middle',
14000 translation: [
14001 titleX,
14002 titleY
14003 ]
14004 });
14005 }
14006 draw(chartArea) {
14007 if (!this._isVisible()) {
14008 return;
14009 }
14010 this.drawBackground();
14011 this.drawGrid(chartArea);
14012 this.drawBorder();
14013 this.drawTitle();
14014 this.drawLabels(chartArea);
14015 }
14016 _layers() {
14017 const opts = this.options;
14018 const tz = opts.ticks && opts.ticks.z || 0;
14019 const gz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.grid && opts.grid.z, -1);
14020 const bz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.border && opts.border.z, 0);
14021 if (!this._isVisible() || this.draw !== Scale.prototype.draw) {
14022 return [
14023 {
14024 z: tz,
14025 draw: (chartArea)=>{
14026 this.draw(chartArea);
14027 }
14028 }
14029 ];
14030 }
14031 return [
14032 {
14033 z: gz,
14034 draw: (chartArea)=>{
14035 this.drawBackground();
14036 this.drawGrid(chartArea);
14037 this.drawTitle();
14038 }
14039 },
14040 {
14041 z: bz,
14042 draw: ()=>{
14043 this.drawBorder();
14044 }
14045 },
14046 {
14047 z: tz,
14048 draw: (chartArea)=>{
14049 this.drawLabels(chartArea);
14050 }
14051 }
14052 ];
14053 }
14054 getMatchingVisibleMetas(type) {
14055 const metas = this.chart.getSortedVisibleDatasetMetas();
14056 const axisID = this.axis + 'AxisID';
14057 const result = [];
14058 let i, ilen;
14059 for(i = 0, ilen = metas.length; i < ilen; ++i){
14060 const meta = metas[i];
14061 if (meta[axisID] === this.id && (!type || meta.type === type)) {
14062 result.push(meta);
14063 }
14064 }
14065 return result;
14066 }
14067 _resolveTickFontOptions(index) {
14068 const opts = this.options.ticks.setContext(this.getContext(index));
14069 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
14070 }
14071 _maxDigits() {
14072 const fontSize = this._resolveTickFontOptions(0).lineHeight;
14073 return (this.isHorizontal() ? this.width : this.height) / fontSize;
14074 }
14075 }
14076
14077 class TypedRegistry {
14078 constructor(type, scope, override){
14079 this.type = type;
14080 this.scope = scope;
14081 this.override = override;
14082 this.items = Object.create(null);
14083 }
14084 isForType(type) {
14085 return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
14086 }
14087 register(item) {
14088 const proto = Object.getPrototypeOf(item);
14089 let parentScope;
14090 if (isIChartComponent(proto)) {
14091 parentScope = this.register(proto);
14092 }
14093 const items = this.items;
14094 const id = item.id;
14095 const scope = this.scope + '.' + id;
14096 if (!id) {
14097 throw new Error('class does not have id: ' + item);
14098 }
14099 if (id in items) {
14100 return scope;
14101 }
14102 items[id] = item;
14103 registerDefaults(item, scope, parentScope);
14104 if (this.override) {
14105 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.override(item.id, item.overrides);
14106 }
14107 return scope;
14108 }
14109 get(id) {
14110 return this.items[id];
14111 }
14112 unregister(item) {
14113 const items = this.items;
14114 const id = item.id;
14115 const scope = this.scope;
14116 if (id in items) {
14117 delete items[id];
14118 }
14119 if (scope && id in _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope]) {
14120 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope][id];
14121 if (this.override) {
14122 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[id];
14123 }
14124 }
14125 }
14126 }
14127 function registerDefaults(item, scope, parentScope) {
14128 const itemDefaults = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a4)(Object.create(null), [
14129 parentScope ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(parentScope) : {},
14130 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(scope),
14131 item.defaults
14132 ]);
14133 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.set(scope, itemDefaults);
14134 if (item.defaultRoutes) {
14135 routeDefaults(scope, item.defaultRoutes);
14136 }
14137 if (item.descriptors) {
14138 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.describe(scope, item.descriptors);
14139 }
14140 }
14141 function routeDefaults(scope, routes) {
14142 Object.keys(routes).forEach((property)=>{
14143 const propertyParts = property.split('.');
14144 const sourceName = propertyParts.pop();
14145 const sourceScope = [
14146 scope
14147 ].concat(propertyParts).join('.');
14148 const parts = routes[property].split('.');
14149 const targetName = parts.pop();
14150 const targetScope = parts.join('.');
14151 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.route(sourceScope, sourceName, targetScope, targetName);
14152 });
14153 }
14154 function isIChartComponent(proto) {
14155 return 'id' in proto && 'defaults' in proto;
14156 }
14157
14158 class Registry {
14159 constructor(){
14160 this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
14161 this.elements = new TypedRegistry(Element, 'elements');
14162 this.plugins = new TypedRegistry(Object, 'plugins');
14163 this.scales = new TypedRegistry(Scale, 'scales');
14164 this._typedRegistries = [
14165 this.controllers,
14166 this.scales,
14167 this.elements
14168 ];
14169 }
14170 add(...args) {
14171 this._each('register', args);
14172 }
14173 remove(...args) {
14174 this._each('unregister', args);
14175 }
14176 addControllers(...args) {
14177 this._each('register', args, this.controllers);
14178 }
14179 addElements(...args) {
14180 this._each('register', args, this.elements);
14181 }
14182 addPlugins(...args) {
14183 this._each('register', args, this.plugins);
14184 }
14185 addScales(...args) {
14186 this._each('register', args, this.scales);
14187 }
14188 getController(id) {
14189 return this._get(id, this.controllers, 'controller');
14190 }
14191 getElement(id) {
14192 return this._get(id, this.elements, 'element');
14193 }
14194 getPlugin(id) {
14195 return this._get(id, this.plugins, 'plugin');
14196 }
14197 getScale(id) {
14198 return this._get(id, this.scales, 'scale');
14199 }
14200 removeControllers(...args) {
14201 this._each('unregister', args, this.controllers);
14202 }
14203 removeElements(...args) {
14204 this._each('unregister', args, this.elements);
14205 }
14206 removePlugins(...args) {
14207 this._each('unregister', args, this.plugins);
14208 }
14209 removeScales(...args) {
14210 this._each('unregister', args, this.scales);
14211 }
14212 _each(method, args, typedRegistry) {
14213 [
14214 ...args
14215 ].forEach((arg)=>{
14216 const reg = typedRegistry || this._getRegistryForType(arg);
14217 if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {
14218 this._exec(method, reg, arg);
14219 } else {
14220 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(arg, (item)=>{
14221 const itemReg = typedRegistry || this._getRegistryForType(item);
14222 this._exec(method, itemReg, item);
14223 });
14224 }
14225 });
14226 }
14227 _exec(method, registry, component) {
14228 const camelMethod = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a5)(method);
14229 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['before' + camelMethod], [], component);
14230 registry[method](component);
14231 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['after' + camelMethod], [], component);
14232 }
14233 _getRegistryForType(type) {
14234 for(let i = 0; i < this._typedRegistries.length; i++){
14235 const reg = this._typedRegistries[i];
14236 if (reg.isForType(type)) {
14237 return reg;
14238 }
14239 }
14240 return this.plugins;
14241 }
14242 _get(id, typedRegistry, type) {
14243 const item = typedRegistry.get(id);
14244 if (item === undefined) {
14245 throw new Error('"' + id + '" is not a registered ' + type + '.');
14246 }
14247 return item;
14248 }
14249 }
14250 var registry = /* #__PURE__ */ new Registry();
14251
14252 class PluginService {
14253 constructor(){
14254 this._init = undefined;
14255 }
14256 notify(chart, hook, args, filter) {
14257 if (hook === 'beforeInit') {
14258 this._init = this._createDescriptors(chart, true);
14259 this._notify(this._init, chart, 'install');
14260 }
14261 if (this._init === undefined) {
14262 return;
14263 }
14264 const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
14265 const result = this._notify(descriptors, chart, hook, args);
14266 if (hook === 'afterDestroy') {
14267 this._notify(descriptors, chart, 'stop');
14268 this._notify(this._init, chart, 'uninstall');
14269 this._init = undefined;
14270 }
14271 return result;
14272 }
14273 _notify(descriptors, chart, hook, args) {
14274 args = args || {};
14275 for (const descriptor of descriptors){
14276 const plugin = descriptor.plugin;
14277 const method = plugin[hook];
14278 const params = [
14279 chart,
14280 args,
14281 descriptor.options
14282 ];
14283 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(method, params, plugin) === false && args.cancelable) {
14284 return false;
14285 }
14286 }
14287 return true;
14288 }
14289 invalidate() {
14290 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(this._cache)) {
14291 this._oldCache = this._cache;
14292 this._cache = undefined;
14293 }
14294 }
14295 _descriptors(chart) {
14296 if (this._cache) {
14297 return this._cache;
14298 }
14299 const descriptors = this._cache = this._createDescriptors(chart);
14300 this._notifyStateChanges(chart);
14301 return descriptors;
14302 }
14303 _createDescriptors(chart, all) {
14304 const config = chart && chart.config;
14305 const options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(config.options && config.options.plugins, {});
14306 const plugins = allPlugins(config);
14307 return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
14308 }
14309 _notifyStateChanges(chart) {
14310 const previousDescriptors = this._oldCache || [];
14311 const descriptors = this._cache;
14312 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id));
14313 this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
14314 this._notify(diff(descriptors, previousDescriptors), chart, 'start');
14315 }
14316 }
14317 function allPlugins(config) {
14318 const localIds = {};
14319 const plugins = [];
14320 const keys = Object.keys(registry.plugins.items);
14321 for(let i = 0; i < keys.length; i++){
14322 plugins.push(registry.getPlugin(keys[i]));
14323 }
14324 const local = config.plugins || [];
14325 for(let i = 0; i < local.length; i++){
14326 const plugin = local[i];
14327 if (plugins.indexOf(plugin) === -1) {
14328 plugins.push(plugin);
14329 localIds[plugin.id] = true;
14330 }
14331 }
14332 return {
14333 plugins,
14334 localIds
14335 };
14336 }
14337 function getOpts(options, all) {
14338 if (!all && options === false) {
14339 return null;
14340 }
14341 if (options === true) {
14342 return {};
14343 }
14344 return options;
14345 }
14346 function createDescriptors(chart, { plugins , localIds }, options, all) {
14347 const result = [];
14348 const context = chart.getContext();
14349 for (const plugin of plugins){
14350 const id = plugin.id;
14351 const opts = getOpts(options[id], all);
14352 if (opts === null) {
14353 continue;
14354 }
14355 result.push({
14356 plugin,
14357 options: pluginOpts(chart.config, {
14358 plugin,
14359 local: localIds[id]
14360 }, opts, context)
14361 });
14362 }
14363 return result;
14364 }
14365 function pluginOpts(config, { plugin , local }, opts, context) {
14366 const keys = config.pluginScopeKeys(plugin);
14367 const scopes = config.getOptionScopes(opts, keys);
14368 if (local && plugin.defaults) {
14369 scopes.push(plugin.defaults);
14370 }
14371 return config.createResolver(scopes, context, [
14372 ''
14373 ], {
14374 scriptable: false,
14375 indexable: false,
14376 allKeys: true
14377 });
14378 }
14379
14380 function getIndexAxis(type, options) {
14381 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {};
14382 const datasetOptions = (options.datasets || {})[type] || {};
14383 return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
14384 }
14385 function getAxisFromDefaultScaleID(id, indexAxis) {
14386 let axis = id;
14387 if (id === '_index_') {
14388 axis = indexAxis;
14389 } else if (id === '_value_') {
14390 axis = indexAxis === 'x' ? 'y' : 'x';
14391 }
14392 return axis;
14393 }
14394 function getDefaultScaleIDFromAxis(axis, indexAxis) {
14395 return axis === indexAxis ? '_index_' : '_value_';
14396 }
14397 function idMatchesAxis(id) {
14398 if (id === 'x' || id === 'y' || id === 'r') {
14399 return id;
14400 }
14401 }
14402 function axisFromPosition(position) {
14403 if (position === 'top' || position === 'bottom') {
14404 return 'x';
14405 }
14406 if (position === 'left' || position === 'right') {
14407 return 'y';
14408 }
14409 }
14410 function determineAxis(id, ...scaleOptions) {
14411 if (idMatchesAxis(id)) {
14412 return id;
14413 }
14414 for (const opts of scaleOptions){
14415 const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());
14416 if (axis) {
14417 return axis;
14418 }
14419 }
14420 throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
14421 }
14422 function getAxisFromDataset(id, axis, dataset) {
14423 if (dataset[axis + 'AxisID'] === id) {
14424 return {
14425 axis
14426 };
14427 }
14428 }
14429 function retrieveAxisFromDatasets(id, config) {
14430 if (config.data && config.data.datasets) {
14431 const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id);
14432 if (boundDs.length) {
14433 return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);
14434 }
14435 }
14436 return {};
14437 }
14438 function mergeScaleConfig(config, options) {
14439 const chartDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[config.type] || {
14440 scales: {}
14441 };
14442 const configScales = options.scales || {};
14443 const chartIndexAxis = getIndexAxis(config.type, options);
14444 const scales = Object.create(null);
14445 Object.keys(configScales).forEach((id)=>{
14446 const scaleConf = configScales[id];
14447 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(scaleConf)) {
14448 return console.error(`Invalid scale configuration for scale: ${id}`);
14449 }
14450 if (scaleConf._proxy) {
14451 return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
14452 }
14453 const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scaleConf.type]);
14454 const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
14455 const defaultScaleOptions = chartDefaults.scales || {};
14456 scales[id] = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(Object.create(null), [
14457 {
14458 axis
14459 },
14460 scaleConf,
14461 defaultScaleOptions[axis],
14462 defaultScaleOptions[defaultId]
14463 ]);
14464 });
14465 config.data.datasets.forEach((dataset)=>{
14466 const type = dataset.type || config.type;
14467 const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
14468 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {};
14469 const defaultScaleOptions = datasetDefaults.scales || {};
14470 Object.keys(defaultScaleOptions).forEach((defaultID)=>{
14471 const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
14472 const id = dataset[axis + 'AxisID'] || axis;
14473 scales[id] = scales[id] || Object.create(null);
14474 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scales[id], [
14475 {
14476 axis
14477 },
14478 configScales[id],
14479 defaultScaleOptions[defaultID]
14480 ]);
14481 });
14482 });
14483 Object.keys(scales).forEach((key)=>{
14484 const scale = scales[key];
14485 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scale, [
14486 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scale.type],
14487 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scale
14488 ]);
14489 });
14490 return scales;
14491 }
14492 function initOptions(config) {
14493 const options = config.options || (config.options = {});
14494 options.plugins = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.plugins, {});
14495 options.scales = mergeScaleConfig(config, options);
14496 }
14497 function initData(data) {
14498 data = data || {};
14499 data.datasets = data.datasets || [];
14500 data.labels = data.labels || [];
14501 return data;
14502 }
14503 function initConfig(config) {
14504 config = config || {};
14505 config.data = initData(config.data);
14506 initOptions(config);
14507 return config;
14508 }
14509 const keyCache = new Map();
14510 const keysCached = new Set();
14511 function cachedKeys(cacheKey, generate) {
14512 let keys = keyCache.get(cacheKey);
14513 if (!keys) {
14514 keys = generate();
14515 keyCache.set(cacheKey, keys);
14516 keysCached.add(keys);
14517 }
14518 return keys;
14519 }
14520 const addIfFound = (set, obj, key)=>{
14521 const opts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, key);
14522 if (opts !== undefined) {
14523 set.add(opts);
14524 }
14525 };
14526 class Config {
14527 constructor(config){
14528 this._config = initConfig(config);
14529 this._scopeCache = new Map();
14530 this._resolverCache = new Map();
14531 }
14532 get platform() {
14533 return this._config.platform;
14534 }
14535 get type() {
14536 return this._config.type;
14537 }
14538 set type(type) {
14539 this._config.type = type;
14540 }
14541 get data() {
14542 return this._config.data;
14543 }
14544 set data(data) {
14545 this._config.data = initData(data);
14546 }
14547 get options() {
14548 return this._config.options;
14549 }
14550 set options(options) {
14551 this._config.options = options;
14552 }
14553 get plugins() {
14554 return this._config.plugins;
14555 }
14556 update() {
14557 const config = this._config;
14558 this.clearCache();
14559 initOptions(config);
14560 }
14561 clearCache() {
14562 this._scopeCache.clear();
14563 this._resolverCache.clear();
14564 }
14565 datasetScopeKeys(datasetType) {
14566 return cachedKeys(datasetType, ()=>[
14567 [
14568 `datasets.${datasetType}`,
14569 ''
14570 ]
14571 ]);
14572 }
14573 datasetAnimationScopeKeys(datasetType, transition) {
14574 return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[
14575 [
14576 `datasets.${datasetType}.transitions.${transition}`,
14577 `transitions.${transition}`
14578 ],
14579 [
14580 `datasets.${datasetType}`,
14581 ''
14582 ]
14583 ]);
14584 }
14585 datasetElementScopeKeys(datasetType, elementType) {
14586 return cachedKeys(`${datasetType}-${elementType}`, ()=>[
14587 [
14588 `datasets.${datasetType}.elements.${elementType}`,
14589 `datasets.${datasetType}`,
14590 `elements.${elementType}`,
14591 ''
14592 ]
14593 ]);
14594 }
14595 pluginScopeKeys(plugin) {
14596 const id = plugin.id;
14597 const type = this.type;
14598 return cachedKeys(`${type}-plugin-${id}`, ()=>[
14599 [
14600 `plugins.${id}`,
14601 ...plugin.additionalOptionScopes || []
14602 ]
14603 ]);
14604 }
14605 _cachedScopes(mainScope, resetCache) {
14606 const _scopeCache = this._scopeCache;
14607 let cache = _scopeCache.get(mainScope);
14608 if (!cache || resetCache) {
14609 cache = new Map();
14610 _scopeCache.set(mainScope, cache);
14611 }
14612 return cache;
14613 }
14614 getOptionScopes(mainScope, keyLists, resetCache) {
14615 const { options , type } = this;
14616 const cache = this._cachedScopes(mainScope, resetCache);
14617 const cached = cache.get(keyLists);
14618 if (cached) {
14619 return cached;
14620 }
14621 const scopes = new Set();
14622 keyLists.forEach((keys)=>{
14623 if (mainScope) {
14624 scopes.add(mainScope);
14625 keys.forEach((key)=>addIfFound(scopes, mainScope, key));
14626 }
14627 keys.forEach((key)=>addIfFound(scopes, options, key));
14628 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, key));
14629 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, key));
14630 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6, key));
14631 });
14632 const array = Array.from(scopes);
14633 if (array.length === 0) {
14634 array.push(Object.create(null));
14635 }
14636 if (keysCached.has(keyLists)) {
14637 cache.set(keyLists, array);
14638 }
14639 return array;
14640 }
14641 chartOptionScopes() {
14642 const { options , type } = this;
14643 return [
14644 options,
14645 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {},
14646 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {},
14647 {
14648 type
14649 },
14650 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d,
14651 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6
14652 ];
14653 }
14654 resolveNamedOptions(scopes, names, context, prefixes = [
14655 ''
14656 ]) {
14657 const result = {
14658 $shared: true
14659 };
14660 const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);
14661 let options = resolver;
14662 if (needContext(resolver, names)) {
14663 result.$shared = false;
14664 context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(context) ? context() : context;
14665 const subResolver = this.createResolver(scopes, context, subPrefixes);
14666 options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, subResolver);
14667 }
14668 for (const prop of names){
14669 result[prop] = options[prop];
14670 }
14671 return result;
14672 }
14673 createResolver(scopes, context, prefixes = [
14674 ''
14675 ], descriptorDefaults) {
14676 const { resolver } = getResolver(this._resolverCache, scopes, prefixes);
14677 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;
14678 }
14679 }
14680 function getResolver(resolverCache, scopes, prefixes) {
14681 let cache = resolverCache.get(scopes);
14682 if (!cache) {
14683 cache = new Map();
14684 resolverCache.set(scopes, cache);
14685 }
14686 const cacheKey = prefixes.join();
14687 let cached = cache.get(cacheKey);
14688 if (!cached) {
14689 const resolver = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a9)(scopes, prefixes);
14690 cached = {
14691 resolver,
14692 subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover'))
14693 };
14694 cache.set(cacheKey, cached);
14695 }
14696 return cached;
14697 }
14698 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]));
14699 function needContext(proxy, names) {
14700 const { isScriptable , isIndexable } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aa)(proxy);
14701 for (const prop of names){
14702 const scriptable = isScriptable(prop);
14703 const indexable = isIndexable(prop);
14704 const value = (indexable || scriptable) && proxy[prop];
14705 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)) {
14706 return true;
14707 }
14708 }
14709 return false;
14710 }
14711
14712 var version = "4.5.1";
14713
14714 const KNOWN_POSITIONS = [
14715 'top',
14716 'bottom',
14717 'left',
14718 'right',
14719 'chartArea'
14720 ];
14721 function positionIsHorizontal(position, axis) {
14722 return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x';
14723 }
14724 function compare2Level(l1, l2) {
14725 return function(a, b) {
14726 return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1];
14727 };
14728 }
14729 function onAnimationsComplete(context) {
14730 const chart = context.chart;
14731 const animationOptions = chart.options.animation;
14732 chart.notifyPlugins('afterRender');
14733 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onComplete, [
14734 context
14735 ], chart);
14736 }
14737 function onAnimationProgress(context) {
14738 const chart = context.chart;
14739 const animationOptions = chart.options.animation;
14740 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onProgress, [
14741 context
14742 ], chart);
14743 }
14744 function getCanvas(item) {
14745 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() && typeof item === 'string') {
14746 item = document.getElementById(item);
14747 } else if (item && item.length) {
14748 item = item[0];
14749 }
14750 if (item && item.canvas) {
14751 item = item.canvas;
14752 }
14753 return item;
14754 }
14755 const instances = {};
14756 const getChart = (key)=>{
14757 const canvas = getCanvas(key);
14758 return Object.values(instances).filter((c)=>c.canvas === canvas).pop();
14759 };
14760 function moveNumericKeys(obj, start, move) {
14761 const keys = Object.keys(obj);
14762 for (const key of keys){
14763 const intKey = +key;
14764 if (intKey >= start) {
14765 const value = obj[key];
14766 delete obj[key];
14767 if (move > 0 || intKey > start) {
14768 obj[intKey + move] = value;
14769 }
14770 }
14771 }
14772 }
14773 function determineLastEvent(e, lastEvent, inChartArea, isClick) {
14774 if (!inChartArea || e.type === 'mouseout') {
14775 return null;
14776 }
14777 if (isClick) {
14778 return lastEvent;
14779 }
14780 return e;
14781 }
14782 class Chart {
14783 static defaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d;
14784 static instances = instances;
14785 static overrides = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3;
14786 static registry = registry;
14787 static version = version;
14788 static getChart = getChart;
14789 static register(...items) {
14790 registry.add(...items);
14791 invalidatePlugins();
14792 }
14793 static unregister(...items) {
14794 registry.remove(...items);
14795 invalidatePlugins();
14796 }
14797 constructor(item, userConfig){
14798 const config = this.config = new Config(userConfig);
14799 const initialCanvas = getCanvas(item);
14800 const existingChart = getChart(initialCanvas);
14801 if (existingChart) {
14802 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.');
14803 }
14804 const options = config.createResolver(config.chartOptionScopes(), this.getContext());
14805 this.platform = new (config.platform || _detectPlatform(initialCanvas))();
14806 this.platform.updateConfig(config);
14807 const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
14808 const canvas = context && context.canvas;
14809 const height = canvas && canvas.height;
14810 const width = canvas && canvas.width;
14811 this.id = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ac)();
14812 this.ctx = context;
14813 this.canvas = canvas;
14814 this.width = width;
14815 this.height = height;
14816 this._options = options;
14817 this._aspectRatio = this.aspectRatio;
14818 this._layers = [];
14819 this._metasets = [];
14820 this._stacks = undefined;
14821 this.boxes = [];
14822 this.currentDevicePixelRatio = undefined;
14823 this.chartArea = undefined;
14824 this._active = [];
14825 this._lastEvent = undefined;
14826 this._listeners = {};
14827 this._responsiveListeners = undefined;
14828 this._sortedMetasets = [];
14829 this.scales = {};
14830 this._plugins = new PluginService();
14831 this.$proxies = {};
14832 this._hiddenIndices = {};
14833 this.attached = false;
14834 this._animationsDisabled = undefined;
14835 this.$context = undefined;
14836 this._doResize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ad)((mode)=>this.update(mode), options.resizeDelay || 0);
14837 this._dataChanges = [];
14838 instances[this.id] = this;
14839 if (!context || !canvas) {
14840 console.error("Failed to create chart: can't acquire context from the given item");
14841 return;
14842 }
14843 animator.listen(this, 'complete', onAnimationsComplete);
14844 animator.listen(this, 'progress', onAnimationProgress);
14845 this._initialize();
14846 if (this.attached) {
14847 this.update();
14848 }
14849 }
14850 get aspectRatio() {
14851 const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this;
14852 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(aspectRatio)) {
14853 return aspectRatio;
14854 }
14855 if (maintainAspectRatio && _aspectRatio) {
14856 return _aspectRatio;
14857 }
14858 return height ? width / height : null;
14859 }
14860 get data() {
14861 return this.config.data;
14862 }
14863 set data(data) {
14864 this.config.data = data;
14865 }
14866 get options() {
14867 return this._options;
14868 }
14869 set options(options) {
14870 this.config.options = options;
14871 }
14872 get registry() {
14873 return registry;
14874 }
14875 _initialize() {
14876 this.notifyPlugins('beforeInit');
14877 if (this.options.responsive) {
14878 this.resize();
14879 } else {
14880 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, this.options.devicePixelRatio);
14881 }
14882 this.bindEvents();
14883 this.notifyPlugins('afterInit');
14884 return this;
14885 }
14886 clear() {
14887 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(this.canvas, this.ctx);
14888 return this;
14889 }
14890 stop() {
14891 animator.stop(this);
14892 return this;
14893 }
14894 resize(width, height) {
14895 if (!animator.running(this)) {
14896 this._resize(width, height);
14897 } else {
14898 this._resizeBeforeDraw = {
14899 width,
14900 height
14901 };
14902 }
14903 }
14904 _resize(width, height) {
14905 const options = this.options;
14906 const canvas = this.canvas;
14907 const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
14908 const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
14909 const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
14910 const mode = this.width ? 'resize' : 'attach';
14911 this.width = newSize.width;
14912 this.height = newSize.height;
14913 this._aspectRatio = this.aspectRatio;
14914 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, newRatio, true)) {
14915 return;
14916 }
14917 this.notifyPlugins('resize', {
14918 size: newSize
14919 });
14920 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onResize, [
14921 this,
14922 newSize
14923 ], this);
14924 if (this.attached) {
14925 if (this._doResize(mode)) {
14926 this.render();
14927 }
14928 }
14929 }
14930 ensureScalesHaveIDs() {
14931 const options = this.options;
14932 const scalesOptions = options.scales || {};
14933 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scalesOptions, (axisOptions, axisID)=>{
14934 axisOptions.id = axisID;
14935 });
14936 }
14937 buildOrUpdateScales() {
14938 const options = this.options;
14939 const scaleOpts = options.scales;
14940 const scales = this.scales;
14941 const updated = Object.keys(scales).reduce((obj, id)=>{
14942 obj[id] = false;
14943 return obj;
14944 }, {});
14945 let items = [];
14946 if (scaleOpts) {
14947 items = items.concat(Object.keys(scaleOpts).map((id)=>{
14948 const scaleOptions = scaleOpts[id];
14949 const axis = determineAxis(id, scaleOptions);
14950 const isRadial = axis === 'r';
14951 const isHorizontal = axis === 'x';
14952 return {
14953 options: scaleOptions,
14954 dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
14955 dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
14956 };
14957 }));
14958 }
14959 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(items, (item)=>{
14960 const scaleOptions = item.options;
14961 const id = scaleOptions.id;
14962 const axis = determineAxis(id, scaleOptions);
14963 const scaleType = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(scaleOptions.type, item.dtype);
14964 if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
14965 scaleOptions.position = item.dposition;
14966 }
14967 updated[id] = true;
14968 let scale = null;
14969 if (id in scales && scales[id].type === scaleType) {
14970 scale = scales[id];
14971 } else {
14972 const scaleClass = registry.getScale(scaleType);
14973 scale = new scaleClass({
14974 id,
14975 type: scaleType,
14976 ctx: this.ctx,
14977 chart: this
14978 });
14979 scales[scale.id] = scale;
14980 }
14981 scale.init(scaleOptions, options);
14982 });
14983 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(updated, (hasUpdated, id)=>{
14984 if (!hasUpdated) {
14985 delete scales[id];
14986 }
14987 });
14988 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scales, (scale)=>{
14989 layouts.configure(this, scale, scale.options);
14990 layouts.addBox(this, scale);
14991 });
14992 }
14993 _updateMetasets() {
14994 const metasets = this._metasets;
14995 const numData = this.data.datasets.length;
14996 const numMeta = metasets.length;
14997 metasets.sort((a, b)=>a.index - b.index);
14998 if (numMeta > numData) {
14999 for(let i = numData; i < numMeta; ++i){
15000 this._destroyDatasetMeta(i);
15001 }
15002 metasets.splice(numData, numMeta - numData);
15003 }
15004 this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
15005 }
15006 _removeUnreferencedMetasets() {
15007 const { _metasets: metasets , data: { datasets } } = this;
15008 if (metasets.length > datasets.length) {
15009 delete this._stacks;
15010 }
15011 metasets.forEach((meta, index)=>{
15012 if (datasets.filter((x)=>x === meta._dataset).length === 0) {
15013 this._destroyDatasetMeta(index);
15014 }
15015 });
15016 }
15017 buildOrUpdateControllers() {
15018 const newControllers = [];
15019 const datasets = this.data.datasets;
15020 let i, ilen;
15021 this._removeUnreferencedMetasets();
15022 for(i = 0, ilen = datasets.length; i < ilen; i++){
15023 const dataset = datasets[i];
15024 let meta = this.getDatasetMeta(i);
15025 const type = dataset.type || this.config.type;
15026 if (meta.type && meta.type !== type) {
15027 this._destroyDatasetMeta(i);
15028 meta = this.getDatasetMeta(i);
15029 }
15030 meta.type = type;
15031 meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
15032 meta.order = dataset.order || 0;
15033 meta.index = i;
15034 meta.label = '' + dataset.label;
15035 meta.visible = this.isDatasetVisible(i);
15036 if (meta.controller) {
15037 meta.controller.updateIndex(i);
15038 meta.controller.linkScales();
15039 } else {
15040 const ControllerClass = registry.getController(type);
15041 const { datasetElementType , dataElementType } = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type];
15042 Object.assign(ControllerClass, {
15043 dataElementType: registry.getElement(dataElementType),
15044 datasetElementType: datasetElementType && registry.getElement(datasetElementType)
15045 });
15046 meta.controller = new ControllerClass(this, i);
15047 newControllers.push(meta.controller);
15048 }
15049 }
15050 this._updateMetasets();
15051 return newControllers;
15052 }
15053 _resetElements() {
15054 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.data.datasets, (dataset, datasetIndex)=>{
15055 this.getDatasetMeta(datasetIndex).controller.reset();
15056 }, this);
15057 }
15058 reset() {
15059 this._resetElements();
15060 this.notifyPlugins('reset');
15061 }
15062 update(mode) {
15063 const config = this.config;
15064 config.update();
15065 const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
15066 const animsDisabled = this._animationsDisabled = !options.animation;
15067 this._updateScales();
15068 this._checkEventBindings();
15069 this._updateHiddenIndices();
15070 this._plugins.invalidate();
15071 if (this.notifyPlugins('beforeUpdate', {
15072 mode,
15073 cancelable: true
15074 }) === false) {
15075 return;
15076 }
15077 const newControllers = this.buildOrUpdateControllers();
15078 this.notifyPlugins('beforeElementsUpdate');
15079 let minPadding = 0;
15080 for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){
15081 const { controller } = this.getDatasetMeta(i);
15082 const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
15083 controller.buildOrUpdateElements(reset);
15084 minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
15085 }
15086 minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
15087 this._updateLayout(minPadding);
15088 if (!animsDisabled) {
15089 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(newControllers, (controller)=>{
15090 controller.reset();
15091 });
15092 }
15093 this._updateDatasets(mode);
15094 this.notifyPlugins('afterUpdate', {
15095 mode
15096 });
15097 this._layers.sort(compare2Level('z', '_idx'));
15098 const { _active , _lastEvent } = this;
15099 if (_lastEvent) {
15100 this._eventHandler(_lastEvent, true);
15101 } else if (_active.length) {
15102 this._updateHoverStyles(_active, _active, true);
15103 }
15104 this.render();
15105 }
15106 _updateScales() {
15107 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.scales, (scale)=>{
15108 layouts.removeBox(this, scale);
15109 });
15110 this.ensureScalesHaveIDs();
15111 this.buildOrUpdateScales();
15112 }
15113 _checkEventBindings() {
15114 const options = this.options;
15115 const existingEvents = new Set(Object.keys(this._listeners));
15116 const newEvents = new Set(options.events);
15117 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
15118 this.unbindEvents();
15119 this.bindEvents();
15120 }
15121 }
15122 _updateHiddenIndices() {
15123 const { _hiddenIndices } = this;
15124 const changes = this._getUniformDataChanges() || [];
15125 for (const { method , start , count } of changes){
15126 const move = method === '_removeElements' ? -count : count;
15127 moveNumericKeys(_hiddenIndices, start, move);
15128 }
15129 }
15130 _getUniformDataChanges() {
15131 const _dataChanges = this._dataChanges;
15132 if (!_dataChanges || !_dataChanges.length) {
15133 return;
15134 }
15135 this._dataChanges = [];
15136 const datasetCount = this.data.datasets.length;
15137 const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(',')));
15138 const changeSet = makeSet(0);
15139 for(let i = 1; i < datasetCount; i++){
15140 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(changeSet, makeSet(i))) {
15141 return;
15142 }
15143 }
15144 return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({
15145 method: a[1],
15146 start: +a[2],
15147 count: +a[3]
15148 }));
15149 }
15150 _updateLayout(minPadding) {
15151 if (this.notifyPlugins('beforeLayout', {
15152 cancelable: true
15153 }) === false) {
15154 return;
15155 }
15156 layouts.update(this, this.width, this.height, minPadding);
15157 const area = this.chartArea;
15158 const noArea = area.width <= 0 || area.height <= 0;
15159 this._layers = [];
15160 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.boxes, (box)=>{
15161 if (noArea && box.position === 'chartArea') {
15162 return;
15163 }
15164 if (box.configure) {
15165 box.configure();
15166 }
15167 this._layers.push(...box._layers());
15168 }, this);
15169 this._layers.forEach((item, index)=>{
15170 item._idx = index;
15171 });
15172 this.notifyPlugins('afterLayout');
15173 }
15174 _updateDatasets(mode) {
15175 if (this.notifyPlugins('beforeDatasetsUpdate', {
15176 mode,
15177 cancelable: true
15178 }) === false) {
15179 return;
15180 }
15181 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15182 this.getDatasetMeta(i).controller.configure();
15183 }
15184 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15185 this._updateDataset(i, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(mode) ? mode({
15186 datasetIndex: i
15187 }) : mode);
15188 }
15189 this.notifyPlugins('afterDatasetsUpdate', {
15190 mode
15191 });
15192 }
15193 _updateDataset(index, mode) {
15194 const meta = this.getDatasetMeta(index);
15195 const args = {
15196 meta,
15197 index,
15198 mode,
15199 cancelable: true
15200 };
15201 if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {
15202 return;
15203 }
15204 meta.controller._update(mode);
15205 args.cancelable = false;
15206 this.notifyPlugins('afterDatasetUpdate', args);
15207 }
15208 render() {
15209 if (this.notifyPlugins('beforeRender', {
15210 cancelable: true
15211 }) === false) {
15212 return;
15213 }
15214 if (animator.has(this)) {
15215 if (this.attached && !animator.running(this)) {
15216 animator.start(this);
15217 }
15218 } else {
15219 this.draw();
15220 onAnimationsComplete({
15221 chart: this
15222 });
15223 }
15224 }
15225 draw() {
15226 let i;
15227 if (this._resizeBeforeDraw) {
15228 const { width , height } = this._resizeBeforeDraw;
15229 this._resizeBeforeDraw = null;
15230 this._resize(width, height);
15231 }
15232 this.clear();
15233 if (this.width <= 0 || this.height <= 0) {
15234 return;
15235 }
15236 if (this.notifyPlugins('beforeDraw', {
15237 cancelable: true
15238 }) === false) {
15239 return;
15240 }
15241 const layers = this._layers;
15242 for(i = 0; i < layers.length && layers[i].z <= 0; ++i){
15243 layers[i].draw(this.chartArea);
15244 }
15245 this._drawDatasets();
15246 for(; i < layers.length; ++i){
15247 layers[i].draw(this.chartArea);
15248 }
15249 this.notifyPlugins('afterDraw');
15250 }
15251 _getSortedDatasetMetas(filterVisible) {
15252 const metasets = this._sortedMetasets;
15253 const result = [];
15254 let i, ilen;
15255 for(i = 0, ilen = metasets.length; i < ilen; ++i){
15256 const meta = metasets[i];
15257 if (!filterVisible || meta.visible) {
15258 result.push(meta);
15259 }
15260 }
15261 return result;
15262 }
15263 getSortedVisibleDatasetMetas() {
15264 return this._getSortedDatasetMetas(true);
15265 }
15266 _drawDatasets() {
15267 if (this.notifyPlugins('beforeDatasetsDraw', {
15268 cancelable: true
15269 }) === false) {
15270 return;
15271 }
15272 const metasets = this.getSortedVisibleDatasetMetas();
15273 for(let i = metasets.length - 1; i >= 0; --i){
15274 this._drawDataset(metasets[i]);
15275 }
15276 this.notifyPlugins('afterDatasetsDraw');
15277 }
15278 _drawDataset(meta) {
15279 const ctx = this.ctx;
15280 const args = {
15281 meta,
15282 index: meta.index,
15283 cancelable: true
15284 };
15285 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(this, meta);
15286 if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
15287 return;
15288 }
15289 if (clip) {
15290 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, clip);
15291 }
15292 meta.controller.draw();
15293 if (clip) {
15294 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
15295 }
15296 args.cancelable = false;
15297 this.notifyPlugins('afterDatasetDraw', args);
15298 }
15299 isPointInArea(point) {
15300 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(point, this.chartArea, this._minPadding);
15301 }
15302 getElementsAtEventForMode(e, mode, options, useFinalPosition) {
15303 const method = Interaction.modes[mode];
15304 if (typeof method === 'function') {
15305 return method(this, e, options, useFinalPosition);
15306 }
15307 return [];
15308 }
15309 getDatasetMeta(datasetIndex) {
15310 const dataset = this.data.datasets[datasetIndex];
15311 const metasets = this._metasets;
15312 let meta = metasets.filter((x)=>x && x._dataset === dataset).pop();
15313 if (!meta) {
15314 meta = {
15315 type: null,
15316 data: [],
15317 dataset: null,
15318 controller: null,
15319 hidden: null,
15320 xAxisID: null,
15321 yAxisID: null,
15322 order: dataset && dataset.order || 0,
15323 index: datasetIndex,
15324 _dataset: dataset,
15325 _parsed: [],
15326 _sorted: false
15327 };
15328 metasets.push(meta);
15329 }
15330 return meta;
15331 }
15332 getContext() {
15333 return this.$context || (this.$context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(null, {
15334 chart: this,
15335 type: 'chart'
15336 }));
15337 }
15338 getVisibleDatasetCount() {
15339 return this.getSortedVisibleDatasetMetas().length;
15340 }
15341 isDatasetVisible(datasetIndex) {
15342 const dataset = this.data.datasets[datasetIndex];
15343 if (!dataset) {
15344 return false;
15345 }
15346 const meta = this.getDatasetMeta(datasetIndex);
15347 return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
15348 }
15349 setDatasetVisibility(datasetIndex, visible) {
15350 const meta = this.getDatasetMeta(datasetIndex);
15351 meta.hidden = !visible;
15352 }
15353 toggleDataVisibility(index) {
15354 this._hiddenIndices[index] = !this._hiddenIndices[index];
15355 }
15356 getDataVisibility(index) {
15357 return !this._hiddenIndices[index];
15358 }
15359 _updateVisibility(datasetIndex, dataIndex, visible) {
15360 const mode = visible ? 'show' : 'hide';
15361 const meta = this.getDatasetMeta(datasetIndex);
15362 const anims = meta.controller._resolveAnimations(undefined, mode);
15363 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(dataIndex)) {
15364 meta.data[dataIndex].hidden = !visible;
15365 this.update();
15366 } else {
15367 this.setDatasetVisibility(datasetIndex, visible);
15368 anims.update(meta, {
15369 visible
15370 });
15371 this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined);
15372 }
15373 }
15374 hide(datasetIndex, dataIndex) {
15375 this._updateVisibility(datasetIndex, dataIndex, false);
15376 }
15377 show(datasetIndex, dataIndex) {
15378 this._updateVisibility(datasetIndex, dataIndex, true);
15379 }
15380 _destroyDatasetMeta(datasetIndex) {
15381 const meta = this._metasets[datasetIndex];
15382 if (meta && meta.controller) {
15383 meta.controller._destroy();
15384 }
15385 delete this._metasets[datasetIndex];
15386 }
15387 _stop() {
15388 let i, ilen;
15389 this.stop();
15390 animator.remove(this);
15391 for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15392 this._destroyDatasetMeta(i);
15393 }
15394 }
15395 destroy() {
15396 this.notifyPlugins('beforeDestroy');
15397 const { canvas , ctx } = this;
15398 this._stop();
15399 this.config.clearCache();
15400 if (canvas) {
15401 this.unbindEvents();
15402 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(canvas, ctx);
15403 this.platform.releaseContext(ctx);
15404 this.canvas = null;
15405 this.ctx = null;
15406 }
15407 delete instances[this.id];
15408 this.notifyPlugins('afterDestroy');
15409 }
15410 toBase64Image(...args) {
15411 return this.canvas.toDataURL(...args);
15412 }
15413 bindEvents() {
15414 this.bindUserEvents();
15415 if (this.options.responsive) {
15416 this.bindResponsiveEvents();
15417 } else {
15418 this.attached = true;
15419 }
15420 }
15421 bindUserEvents() {
15422 const listeners = this._listeners;
15423 const platform = this.platform;
15424 const _add = (type, listener)=>{
15425 platform.addEventListener(this, type, listener);
15426 listeners[type] = listener;
15427 };
15428 const listener = (e, x, y)=>{
15429 e.offsetX = x;
15430 e.offsetY = y;
15431 this._eventHandler(e);
15432 };
15433 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.options.events, (type)=>_add(type, listener));
15434 }
15435 bindResponsiveEvents() {
15436 if (!this._responsiveListeners) {
15437 this._responsiveListeners = {};
15438 }
15439 const listeners = this._responsiveListeners;
15440 const platform = this.platform;
15441 const _add = (type, listener)=>{
15442 platform.addEventListener(this, type, listener);
15443 listeners[type] = listener;
15444 };
15445 const _remove = (type, listener)=>{
15446 if (listeners[type]) {
15447 platform.removeEventListener(this, type, listener);
15448 delete listeners[type];
15449 }
15450 };
15451 const listener = (width, height)=>{
15452 if (this.canvas) {
15453 this.resize(width, height);
15454 }
15455 };
15456 let detached;
15457 const attached = ()=>{
15458 _remove('attach', attached);
15459 this.attached = true;
15460 this.resize();
15461 _add('resize', listener);
15462 _add('detach', detached);
15463 };
15464 detached = ()=>{
15465 this.attached = false;
15466 _remove('resize', listener);
15467 this._stop();
15468 this._resize(0, 0);
15469 _add('attach', attached);
15470 };
15471 if (platform.isAttached(this.canvas)) {
15472 attached();
15473 } else {
15474 detached();
15475 }
15476 }
15477 unbindEvents() {
15478 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._listeners, (listener, type)=>{
15479 this.platform.removeEventListener(this, type, listener);
15480 });
15481 this._listeners = {};
15482 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._responsiveListeners, (listener, type)=>{
15483 this.platform.removeEventListener(this, type, listener);
15484 });
15485 this._responsiveListeners = undefined;
15486 }
15487 updateHoverStyle(items, mode, enabled) {
15488 const prefix = enabled ? 'set' : 'remove';
15489 let meta, item, i, ilen;
15490 if (mode === 'dataset') {
15491 meta = this.getDatasetMeta(items[0].datasetIndex);
15492 meta.controller['_' + prefix + 'DatasetHoverStyle']();
15493 }
15494 for(i = 0, ilen = items.length; i < ilen; ++i){
15495 item = items[i];
15496 const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
15497 if (controller) {
15498 controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
15499 }
15500 }
15501 }
15502 getActiveElements() {
15503 return this._active || [];
15504 }
15505 setActiveElements(activeElements) {
15506 const lastActive = this._active || [];
15507 const active = activeElements.map(({ datasetIndex , index })=>{
15508 const meta = this.getDatasetMeta(datasetIndex);
15509 if (!meta) {
15510 throw new Error('No dataset found at index ' + datasetIndex);
15511 }
15512 return {
15513 datasetIndex,
15514 element: meta.data[index],
15515 index
15516 };
15517 });
15518 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15519 if (changed) {
15520 this._active = active;
15521 this._lastEvent = null;
15522 this._updateHoverStyles(active, lastActive);
15523 }
15524 }
15525 notifyPlugins(hook, args, filter) {
15526 return this._plugins.notify(this, hook, args, filter);
15527 }
15528 isPluginEnabled(pluginId) {
15529 return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1;
15530 }
15531 _updateHoverStyles(active, lastActive, replay) {
15532 const hoverOptions = this.options.hover;
15533 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index));
15534 const deactivated = diff(lastActive, active);
15535 const activated = replay ? active : diff(active, lastActive);
15536 if (deactivated.length) {
15537 this.updateHoverStyle(deactivated, hoverOptions.mode, false);
15538 }
15539 if (activated.length && hoverOptions.mode) {
15540 this.updateHoverStyle(activated, hoverOptions.mode, true);
15541 }
15542 }
15543 _eventHandler(e, replay) {
15544 const args = {
15545 event: e,
15546 replay,
15547 cancelable: true,
15548 inChartArea: this.isPointInArea(e)
15549 };
15550 const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type);
15551 if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
15552 return;
15553 }
15554 const changed = this._handleEvent(e, replay, args.inChartArea);
15555 args.cancelable = false;
15556 this.notifyPlugins('afterEvent', args, eventFilter);
15557 if (changed || args.changed) {
15558 this.render();
15559 }
15560 return this;
15561 }
15562 _handleEvent(e, replay, inChartArea) {
15563 const { _active: lastActive = [] , options } = this;
15564 const useFinalPosition = replay;
15565 const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
15566 const isClick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aj)(e);
15567 const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
15568 if (inChartArea) {
15569 this._lastEvent = null;
15570 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onHover, [
15571 e,
15572 active,
15573 this
15574 ], this);
15575 if (isClick) {
15576 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onClick, [
15577 e,
15578 active,
15579 this
15580 ], this);
15581 }
15582 }
15583 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15584 if (changed || replay) {
15585 this._active = active;
15586 this._updateHoverStyles(active, lastActive, replay);
15587 }
15588 this._lastEvent = lastEvent;
15589 return changed;
15590 }
15591 _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
15592 if (e.type === 'mouseout') {
15593 return [];
15594 }
15595 if (!inChartArea) {
15596 return lastActive;
15597 }
15598 const hoverOptions = this.options.hover;
15599 return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
15600 }
15601 }
15602 function invalidatePlugins() {
15603 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(Chart.instances, (chart)=>chart._plugins.invalidate());
15604 }
15605
15606 function clipSelf(ctx, element, endAngle) {
15607 const { startAngle , x , y , outerRadius , innerRadius , options } = element;
15608 const { borderWidth , borderJoinStyle } = options;
15609 const outerAngleClip = Math.min(borderWidth / outerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15610 ctx.beginPath();
15611 ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2);
15612 if (innerRadius > 0) {
15613 const innerAngleClip = Math.min(borderWidth / innerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15614 ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true);
15615 } else {
15616 const clipWidth = Math.min(borderWidth / 2, outerRadius * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15617 if (borderJoinStyle === 'round') {
15618 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);
15619 } else if (borderJoinStyle === 'bevel') {
15620 const r = 2 * clipWidth * clipWidth;
15621 const endX = -r * Math.cos(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15622 const endY = -r * Math.sin(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15623 const startX = r * Math.cos(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15624 const startY = r * Math.sin(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15625 ctx.lineTo(endX, endY);
15626 ctx.lineTo(startX, startY);
15627 }
15628 }
15629 ctx.closePath();
15630 ctx.moveTo(0, 0);
15631 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
15632 ctx.clip('evenodd');
15633 }
15634 function clipArc(ctx, element, endAngle) {
15635 const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element;
15636 let angleMargin = pixelMargin / outerRadius;
15637 // Draw an inner border by clipping the arc and drawing a double-width border
15638 // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
15639 ctx.beginPath();
15640 ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
15641 if (innerRadius > pixelMargin) {
15642 angleMargin = pixelMargin / innerRadius;
15643 ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
15644 } else {
15645 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);
15646 }
15647 ctx.closePath();
15648 ctx.clip();
15649 }
15650 function toRadiusCorners(value) {
15651 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.am)(value, [
15652 'outerStart',
15653 'outerEnd',
15654 'innerStart',
15655 'innerEnd'
15656 ]);
15657 }
15658 /**
15659 * Parse border radius from the provided options
15660 */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
15661 const o = toRadiusCorners(arc.options.borderRadius);
15662 const halfThickness = (outerRadius - innerRadius) / 2;
15663 const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
15664 // Outer limits are complicated. We want to compute the available angular distance at
15665 // a radius of outerRadius - borderRadius because for small angular distances, this term limits.
15666 // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners.
15667 //
15668 // If the borderRadius is large, that value can become negative.
15669 // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius
15670 // we know that the thickness term will dominate and compute the limits at that point
15671 const computeOuterLimit = (val)=>{
15672 const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
15673 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(val, 0, Math.min(halfThickness, outerArcLimit));
15674 };
15675 return {
15676 outerStart: computeOuterLimit(o.outerStart),
15677 outerEnd: computeOuterLimit(o.outerEnd),
15678 innerStart: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerStart, 0, innerLimit),
15679 innerEnd: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerEnd, 0, innerLimit)
15680 };
15681 }
15682 /**
15683 * Convert (r, 𝜃) to (x, y)
15684 */ function rThetaToXY(r, theta, x, y) {
15685 return {
15686 x: x + r * Math.cos(theta),
15687 y: y + r * Math.sin(theta)
15688 };
15689 }
15690 /**
15691 * Path the arc, respecting border radius by separating into left and right halves.
15692 *
15693 * Start End
15694 *
15695 * 1--->a--->2 Outer
15696 * / \
15697 * 8 3
15698 * | |
15699 * | |
15700 * 7 4
15701 * \ /
15702 * 6<---b<---5 Inner
15703 */ function pathArc(ctx, element, offset, spacing, end, circular) {
15704 const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element;
15705 const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
15706 const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
15707 let spacingOffset = 0;
15708 const alpha = end - start;
15709 if (spacing) {
15710 // When spacing is present, it is the same for all items
15711 // So we adjust the start and end angle of the arc such that
15712 // the distance is the same as it would be without the spacing
15713 const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
15714 const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
15715 const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
15716 const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha;
15717 spacingOffset = (alpha - adjustedAngle) / 2;
15718 }
15719 const beta = Math.max(0.001, alpha * outerRadius - offset / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P) / outerRadius;
15720 const angleOffset = (alpha - beta) / 2;
15721 const startAngle = start + angleOffset + spacingOffset;
15722 const endAngle = end - angleOffset - spacingOffset;
15723 const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
15724 const outerStartAdjustedRadius = outerRadius - outerStart;
15725 const outerEndAdjustedRadius = outerRadius - outerEnd;
15726 const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
15727 const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
15728 const innerStartAdjustedRadius = innerRadius + innerStart;
15729 const innerEndAdjustedRadius = innerRadius + innerEnd;
15730 const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
15731 const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
15732 ctx.beginPath();
15733 if (circular) {
15734 // The first arc segments from point 1 to point a to point 2
15735 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;
15736 ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);
15737 ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);
15738 // The corner segment from point 2 to point 3
15739 if (outerEnd > 0) {
15740 const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
15741 ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15742 }
15743 // The line from point 3 to point 4
15744 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
15745 ctx.lineTo(p4.x, p4.y);
15746 // The corner segment from point 4 to point 5
15747 if (innerEnd > 0) {
15748 const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
15749 ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, innerEndAdjustedAngle + Math.PI);
15750 }
15751 // The inner arc from point 5 to point b to point 6
15752 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;
15753 ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);
15754 ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);
15755 // The corner segment from point 6 to point 7
15756 if (innerStart > 0) {
15757 const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
15758 ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15759 }
15760 // The line from point 7 to point 8
15761 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
15762 ctx.lineTo(p8.x, p8.y);
15763 // The corner segment from point 8 to point 1
15764 if (outerStart > 0) {
15765 const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
15766 ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, outerStartAdjustedAngle);
15767 }
15768 } else {
15769 ctx.moveTo(x, y);
15770 const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;
15771 const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;
15772 ctx.lineTo(outerStartX, outerStartY);
15773 const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;
15774 const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;
15775 ctx.lineTo(outerEndX, outerEndY);
15776 }
15777 ctx.closePath();
15778 }
15779 function drawArc(ctx, element, offset, spacing, circular) {
15780 const { fullCircles , startAngle , circumference } = element;
15781 let endAngle = element.endAngle;
15782 if (fullCircles) {
15783 pathArc(ctx, element, offset, spacing, endAngle, circular);
15784 for(let i = 0; i < fullCircles; ++i){
15785 ctx.fill();
15786 }
15787 if (!isNaN(circumference)) {
15788 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15789 }
15790 }
15791 pathArc(ctx, element, offset, spacing, endAngle, circular);
15792 ctx.fill();
15793 return endAngle;
15794 }
15795 function drawBorder(ctx, element, offset, spacing, circular) {
15796 const { fullCircles , startAngle , circumference , options } = element;
15797 const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options;
15798 const inner = options.borderAlign === 'inner';
15799 if (!borderWidth) {
15800 return;
15801 }
15802 ctx.setLineDash(borderDash || []);
15803 ctx.lineDashOffset = borderDashOffset;
15804 if (inner) {
15805 ctx.lineWidth = borderWidth * 2;
15806 ctx.lineJoin = borderJoinStyle || 'round';
15807 } else {
15808 ctx.lineWidth = borderWidth;
15809 ctx.lineJoin = borderJoinStyle || 'bevel';
15810 }
15811 let endAngle = element.endAngle;
15812 if (fullCircles) {
15813 pathArc(ctx, element, offset, spacing, endAngle, circular);
15814 for(let i = 0; i < fullCircles; ++i){
15815 ctx.stroke();
15816 }
15817 if (!isNaN(circumference)) {
15818 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15819 }
15820 }
15821 if (inner) {
15822 clipArc(ctx, element, endAngle);
15823 }
15824 if (options.selfJoin && endAngle - startAngle >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P && borderRadius === 0 && borderJoinStyle !== 'miter') {
15825 clipSelf(ctx, element, endAngle);
15826 }
15827 if (!fullCircles) {
15828 pathArc(ctx, element, offset, spacing, endAngle, circular);
15829 ctx.stroke();
15830 }
15831 }
15832 class ArcElement extends Element {
15833 static id = 'arc';
15834 static defaults = {
15835 borderAlign: 'center',
15836 borderColor: '#fff',
15837 borderDash: [],
15838 borderDashOffset: 0,
15839 borderJoinStyle: undefined,
15840 borderRadius: 0,
15841 borderWidth: 2,
15842 offset: 0,
15843 spacing: 0,
15844 angle: undefined,
15845 circular: true,
15846 selfJoin: false
15847 };
15848 static defaultRoutes = {
15849 backgroundColor: 'backgroundColor'
15850 };
15851 static descriptors = {
15852 _scriptable: true,
15853 _indexable: (name)=>name !== 'borderDash'
15854 };
15855 circumference;
15856 endAngle;
15857 fullCircles;
15858 innerRadius;
15859 outerRadius;
15860 pixelMargin;
15861 startAngle;
15862 constructor(cfg){
15863 super();
15864 this.options = undefined;
15865 this.circumference = undefined;
15866 this.startAngle = undefined;
15867 this.endAngle = undefined;
15868 this.innerRadius = undefined;
15869 this.outerRadius = undefined;
15870 this.pixelMargin = 0;
15871 this.fullCircles = 0;
15872 if (cfg) {
15873 Object.assign(this, cfg);
15874 }
15875 }
15876 inRange(chartX, chartY, useFinalPosition) {
15877 const point = this.getProps([
15878 'x',
15879 'y'
15880 ], useFinalPosition);
15881 const { angle , distance } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(point, {
15882 x: chartX,
15883 y: chartY
15884 });
15885 const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([
15886 'startAngle',
15887 'endAngle',
15888 'innerRadius',
15889 'outerRadius',
15890 'circumference'
15891 ], useFinalPosition);
15892 const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;
15893 const _circumference = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(circumference, endAngle - startAngle);
15894 const nonZeroBetween = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle) && startAngle !== endAngle;
15895 const betweenAngles = _circumference >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || nonZeroBetween;
15896 const withinRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(distance, innerRadius + rAdjust, outerRadius + rAdjust);
15897 return betweenAngles && withinRadius;
15898 }
15899 getCenterPoint(useFinalPosition) {
15900 const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([
15901 'x',
15902 'y',
15903 'startAngle',
15904 'endAngle',
15905 'innerRadius',
15906 'outerRadius'
15907 ], useFinalPosition);
15908 const { offset , spacing } = this.options;
15909 const halfAngle = (startAngle + endAngle) / 2;
15910 const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
15911 return {
15912 x: x + Math.cos(halfAngle) * halfRadius,
15913 y: y + Math.sin(halfAngle) * halfRadius
15914 };
15915 }
15916 tooltipPosition(useFinalPosition) {
15917 return this.getCenterPoint(useFinalPosition);
15918 }
15919 draw(ctx) {
15920 const { options , circumference } = this;
15921 const offset = (options.offset || 0) / 4;
15922 const spacing = (options.spacing || 0) / 2;
15923 const circular = options.circular;
15924 this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0;
15925 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;
15926 if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
15927 return;
15928 }
15929 ctx.save();
15930 const halfAngle = (this.startAngle + this.endAngle) / 2;
15931 ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
15932 const fix = 1 - Math.sin(Math.min(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, circumference || 0));
15933 const radiusOffset = offset * fix;
15934 ctx.fillStyle = options.backgroundColor;
15935 ctx.strokeStyle = options.borderColor;
15936 drawArc(ctx, this, radiusOffset, spacing, circular);
15937 drawBorder(ctx, this, radiusOffset, spacing, circular);
15938 ctx.restore();
15939 }
15940 }
15941
15942 function setStyle(ctx, options, style = options) {
15943 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderCapStyle, options.borderCapStyle);
15944 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDash, options.borderDash));
15945 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDashOffset, options.borderDashOffset);
15946 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderJoinStyle, options.borderJoinStyle);
15947 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderWidth, options.borderWidth);
15948 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderColor, options.borderColor);
15949 }
15950 function lineTo(ctx, previous, target) {
15951 ctx.lineTo(target.x, target.y);
15952 }
15953 function getLineMethod(options) {
15954 if (options.stepped) {
15955 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.at;
15956 }
15957 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15958 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.au;
15959 }
15960 return lineTo;
15961 }
15962 function pathVars(points, segment, params = {}) {
15963 const count = points.length;
15964 const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params;
15965 const { start: segmentStart , end: segmentEnd } = segment;
15966 const start = Math.max(paramsStart, segmentStart);
15967 const end = Math.min(paramsEnd, segmentEnd);
15968 const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;
15969 return {
15970 count,
15971 start,
15972 loop: segment.loop,
15973 ilen: end < start && !outside ? count + end - start : end - start
15974 };
15975 }
15976 function pathSegment(ctx, line, segment, params) {
15977 const { points , options } = line;
15978 const { count , start , loop , ilen } = pathVars(points, segment, params);
15979 const lineMethod = getLineMethod(options);
15980 let { move =true , reverse } = params || {};
15981 let i, point, prev;
15982 for(i = 0; i <= ilen; ++i){
15983 point = points[(start + (reverse ? ilen - i : i)) % count];
15984 if (point.skip) {
15985 continue;
15986 } else if (move) {
15987 ctx.moveTo(point.x, point.y);
15988 move = false;
15989 } else {
15990 lineMethod(ctx, prev, point, reverse, options.stepped);
15991 }
15992 prev = point;
15993 }
15994 if (loop) {
15995 point = points[(start + (reverse ? ilen : 0)) % count];
15996 lineMethod(ctx, prev, point, reverse, options.stepped);
15997 }
15998 return !!loop;
15999 }
16000 function fastPathSegment(ctx, line, segment, params) {
16001 const points = line.points;
16002 const { count , start , ilen } = pathVars(points, segment, params);
16003 const { move =true , reverse } = params || {};
16004 let avgX = 0;
16005 let countX = 0;
16006 let i, point, prevX, minY, maxY, lastY;
16007 const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count;
16008 const drawX = ()=>{
16009 if (minY !== maxY) {
16010 ctx.lineTo(avgX, maxY);
16011 ctx.lineTo(avgX, minY);
16012 ctx.lineTo(avgX, lastY);
16013 }
16014 };
16015 if (move) {
16016 point = points[pointIndex(0)];
16017 ctx.moveTo(point.x, point.y);
16018 }
16019 for(i = 0; i <= ilen; ++i){
16020 point = points[pointIndex(i)];
16021 if (point.skip) {
16022 continue;
16023 }
16024 const x = point.x;
16025 const y = point.y;
16026 const truncX = x | 0;
16027 if (truncX === prevX) {
16028 if (y < minY) {
16029 minY = y;
16030 } else if (y > maxY) {
16031 maxY = y;
16032 }
16033 avgX = (countX * avgX + x) / ++countX;
16034 } else {
16035 drawX();
16036 ctx.lineTo(x, y);
16037 prevX = truncX;
16038 countX = 0;
16039 minY = maxY = y;
16040 }
16041 lastY = y;
16042 }
16043 drawX();
16044 }
16045 function _getSegmentMethod(line) {
16046 const opts = line.options;
16047 const borderDash = opts.borderDash && opts.borderDash.length;
16048 const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;
16049 return useFastPath ? fastPathSegment : pathSegment;
16050 }
16051 function _getInterpolationMethod(options) {
16052 if (options.stepped) {
16053 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aq;
16054 }
16055 if (options.tension || options.cubicInterpolationMode === 'monotone') {
16056 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ar;
16057 }
16058 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.as;
16059 }
16060 function strokePathWithCache(ctx, line, start, count) {
16061 let path = line._path;
16062 if (!path) {
16063 path = line._path = new Path2D();
16064 if (line.path(path, start, count)) {
16065 path.closePath();
16066 }
16067 }
16068 setStyle(ctx, line.options);
16069 ctx.stroke(path);
16070 }
16071 function strokePathDirect(ctx, line, start, count) {
16072 const { segments , options } = line;
16073 const segmentMethod = _getSegmentMethod(line);
16074 for (const segment of segments){
16075 setStyle(ctx, options, segment.style);
16076 ctx.beginPath();
16077 if (segmentMethod(ctx, line, segment, {
16078 start,
16079 end: start + count - 1
16080 })) {
16081 ctx.closePath();
16082 }
16083 ctx.stroke();
16084 }
16085 }
16086 const usePath2D = typeof Path2D === 'function';
16087 function draw(ctx, line, start, count) {
16088 if (usePath2D && !line.options.segment) {
16089 strokePathWithCache(ctx, line, start, count);
16090 } else {
16091 strokePathDirect(ctx, line, start, count);
16092 }
16093 }
16094 class LineElement extends Element {
16095 static id = 'line';
16096 static defaults = {
16097 borderCapStyle: 'butt',
16098 borderDash: [],
16099 borderDashOffset: 0,
16100 borderJoinStyle: 'miter',
16101 borderWidth: 3,
16102 capBezierPoints: true,
16103 cubicInterpolationMode: 'default',
16104 fill: false,
16105 spanGaps: false,
16106 stepped: false,
16107 tension: 0
16108 };
16109 static defaultRoutes = {
16110 backgroundColor: 'backgroundColor',
16111 borderColor: 'borderColor'
16112 };
16113 static descriptors = {
16114 _scriptable: true,
16115 _indexable: (name)=>name !== 'borderDash' && name !== 'fill'
16116 };
16117 constructor(cfg){
16118 super();
16119 this.animated = true;
16120 this.options = undefined;
16121 this._chart = undefined;
16122 this._loop = undefined;
16123 this._fullLoop = undefined;
16124 this._path = undefined;
16125 this._points = undefined;
16126 this._segments = undefined;
16127 this._decimated = false;
16128 this._pointsUpdated = false;
16129 this._datasetIndex = undefined;
16130 if (cfg) {
16131 Object.assign(this, cfg);
16132 }
16133 }
16134 updateControlPoints(chartArea, indexAxis) {
16135 const options = this.options;
16136 if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {
16137 const loop = options.spanGaps ? this._loop : this._fullLoop;
16138 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.an)(this._points, options, chartArea, loop, indexAxis);
16139 this._pointsUpdated = true;
16140 }
16141 }
16142 set points(points) {
16143 this._points = points;
16144 delete this._segments;
16145 delete this._path;
16146 this._pointsUpdated = false;
16147 }
16148 get points() {
16149 return this._points;
16150 }
16151 get segments() {
16152 return this._segments || (this._segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ao)(this, this.options.segment));
16153 }
16154 first() {
16155 const segments = this.segments;
16156 const points = this.points;
16157 return segments.length && points[segments[0].start];
16158 }
16159 last() {
16160 const segments = this.segments;
16161 const points = this.points;
16162 const count = segments.length;
16163 return count && points[segments[count - 1].end];
16164 }
16165 interpolate(point, property) {
16166 const options = this.options;
16167 const value = point[property];
16168 const points = this.points;
16169 const segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(this, {
16170 property,
16171 start: value,
16172 end: value
16173 });
16174 if (!segments.length) {
16175 return;
16176 }
16177 const result = [];
16178 const _interpolate = _getInterpolationMethod(options);
16179 let i, ilen;
16180 for(i = 0, ilen = segments.length; i < ilen; ++i){
16181 const { start , end } = segments[i];
16182 const p1 = points[start];
16183 const p2 = points[end];
16184 if (p1 === p2) {
16185 result.push(p1);
16186 continue;
16187 }
16188 const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
16189 const interpolated = _interpolate(p1, p2, t, options.stepped);
16190 interpolated[property] = point[property];
16191 result.push(interpolated);
16192 }
16193 return result.length === 1 ? result[0] : result;
16194 }
16195 pathSegment(ctx, segment, params) {
16196 const segmentMethod = _getSegmentMethod(this);
16197 return segmentMethod(ctx, this, segment, params);
16198 }
16199 path(ctx, start, count) {
16200 const segments = this.segments;
16201 const segmentMethod = _getSegmentMethod(this);
16202 let loop = this._loop;
16203 start = start || 0;
16204 count = count || this.points.length - start;
16205 for (const segment of segments){
16206 loop &= segmentMethod(ctx, this, segment, {
16207 start,
16208 end: start + count - 1
16209 });
16210 }
16211 return !!loop;
16212 }
16213 draw(ctx, chartArea, start, count) {
16214 const options = this.options || {};
16215 const points = this.points || [];
16216 if (points.length && options.borderWidth) {
16217 ctx.save();
16218 draw(ctx, this, start, count);
16219 ctx.restore();
16220 }
16221 if (this.animated) {
16222 this._pointsUpdated = false;
16223 this._path = undefined;
16224 }
16225 }
16226 }
16227
16228 function inRange$1(el, pos, axis, useFinalPosition) {
16229 const options = el.options;
16230 const { [axis]: value } = el.getProps([
16231 axis
16232 ], useFinalPosition);
16233 return Math.abs(pos - value) < options.radius + options.hitRadius;
16234 }
16235 class PointElement extends Element {
16236 static id = 'point';
16237 parsed;
16238 skip;
16239 stop;
16240 /**
16241 * @type {any}
16242 */ static defaults = {
16243 borderWidth: 1,
16244 hitRadius: 1,
16245 hoverBorderWidth: 1,
16246 hoverRadius: 4,
16247 pointStyle: 'circle',
16248 radius: 3,
16249 rotation: 0
16250 };
16251 /**
16252 * @type {any}
16253 */ static defaultRoutes = {
16254 backgroundColor: 'backgroundColor',
16255 borderColor: 'borderColor'
16256 };
16257 constructor(cfg){
16258 super();
16259 this.options = undefined;
16260 this.parsed = undefined;
16261 this.skip = undefined;
16262 this.stop = undefined;
16263 if (cfg) {
16264 Object.assign(this, cfg);
16265 }
16266 }
16267 inRange(mouseX, mouseY, useFinalPosition) {
16268 const options = this.options;
16269 const { x , y } = this.getProps([
16270 'x',
16271 'y'
16272 ], useFinalPosition);
16273 return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2);
16274 }
16275 inXRange(mouseX, useFinalPosition) {
16276 return inRange$1(this, mouseX, 'x', useFinalPosition);
16277 }
16278 inYRange(mouseY, useFinalPosition) {
16279 return inRange$1(this, mouseY, 'y', useFinalPosition);
16280 }
16281 getCenterPoint(useFinalPosition) {
16282 const { x , y } = this.getProps([
16283 'x',
16284 'y'
16285 ], useFinalPosition);
16286 return {
16287 x,
16288 y
16289 };
16290 }
16291 size(options) {
16292 options = options || this.options || {};
16293 let radius = options.radius || 0;
16294 radius = Math.max(radius, radius && options.hoverRadius || 0);
16295 const borderWidth = radius && options.borderWidth || 0;
16296 return (radius + borderWidth) * 2;
16297 }
16298 draw(ctx, area) {
16299 const options = this.options;
16300 if (this.skip || options.radius < 0.1 || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(this, area, this.size(options) / 2)) {
16301 return;
16302 }
16303 ctx.strokeStyle = options.borderColor;
16304 ctx.lineWidth = options.borderWidth;
16305 ctx.fillStyle = options.backgroundColor;
16306 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, options, this.x, this.y);
16307 }
16308 getRange() {
16309 const options = this.options || {};
16310 // @ts-expect-error Fallbacks should never be hit in practice
16311 return options.radius + options.hitRadius;
16312 }
16313 }
16314
16315 function getBarBounds(bar, useFinalPosition) {
16316 const { x , y , base , width , height } = bar.getProps([
16317 'x',
16318 'y',
16319 'base',
16320 'width',
16321 'height'
16322 ], useFinalPosition);
16323 let left, right, top, bottom, half;
16324 if (bar.horizontal) {
16325 half = height / 2;
16326 left = Math.min(x, base);
16327 right = Math.max(x, base);
16328 top = y - half;
16329 bottom = y + half;
16330 } else {
16331 half = width / 2;
16332 left = x - half;
16333 right = x + half;
16334 top = Math.min(y, base);
16335 bottom = Math.max(y, base);
16336 }
16337 return {
16338 left,
16339 top,
16340 right,
16341 bottom
16342 };
16343 }
16344 function skipOrLimit(skip, value, min, max) {
16345 return skip ? 0 : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(value, min, max);
16346 }
16347 function parseBorderWidth(bar, maxW, maxH) {
16348 const value = bar.options.borderWidth;
16349 const skip = bar.borderSkipped;
16350 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ax)(value);
16351 return {
16352 t: skipOrLimit(skip.top, o.top, 0, maxH),
16353 r: skipOrLimit(skip.right, o.right, 0, maxW),
16354 b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
16355 l: skipOrLimit(skip.left, o.left, 0, maxW)
16356 };
16357 }
16358 function parseBorderRadius(bar, maxW, maxH) {
16359 const { enableBorderRadius } = bar.getProps([
16360 'enableBorderRadius'
16361 ]);
16362 const value = bar.options.borderRadius;
16363 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(value);
16364 const maxR = Math.min(maxW, maxH);
16365 const skip = bar.borderSkipped;
16366 const enableBorder = enableBorderRadius || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value);
16367 return {
16368 topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
16369 topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
16370 bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
16371 bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
16372 };
16373 }
16374 function boundingRects(bar) {
16375 const bounds = getBarBounds(bar);
16376 const width = bounds.right - bounds.left;
16377 const height = bounds.bottom - bounds.top;
16378 const border = parseBorderWidth(bar, width / 2, height / 2);
16379 const radius = parseBorderRadius(bar, width / 2, height / 2);
16380 return {
16381 outer: {
16382 x: bounds.left,
16383 y: bounds.top,
16384 w: width,
16385 h: height,
16386 radius
16387 },
16388 inner: {
16389 x: bounds.left + border.l,
16390 y: bounds.top + border.t,
16391 w: width - border.l - border.r,
16392 h: height - border.t - border.b,
16393 radius: {
16394 topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
16395 topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
16396 bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
16397 bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))
16398 }
16399 }
16400 };
16401 }
16402 function inRange(bar, x, y, useFinalPosition) {
16403 const skipX = x === null;
16404 const skipY = y === null;
16405 const skipBoth = skipX && skipY;
16406 const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
16407 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));
16408 }
16409 function hasRadius(radius) {
16410 return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
16411 }
16412 function addNormalRectPath(ctx, rect) {
16413 ctx.rect(rect.x, rect.y, rect.w, rect.h);
16414 }
16415 function inflateRect(rect, amount, refRect = {}) {
16416 const x = rect.x !== refRect.x ? -amount : 0;
16417 const y = rect.y !== refRect.y ? -amount : 0;
16418 const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;
16419 const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;
16420 return {
16421 x: rect.x + x,
16422 y: rect.y + y,
16423 w: rect.w + w,
16424 h: rect.h + h,
16425 radius: rect.radius
16426 };
16427 }
16428 class BarElement extends Element {
16429 static id = 'bar';
16430 static defaults = {
16431 borderSkipped: 'start',
16432 borderWidth: 0,
16433 borderRadius: 0,
16434 inflateAmount: 'auto',
16435 pointStyle: undefined
16436 };
16437 static defaultRoutes = {
16438 backgroundColor: 'backgroundColor',
16439 borderColor: 'borderColor'
16440 };
16441 constructor(cfg){
16442 super();
16443 this.options = undefined;
16444 this.horizontal = undefined;
16445 this.base = undefined;
16446 this.width = undefined;
16447 this.height = undefined;
16448 this.inflateAmount = undefined;
16449 if (cfg) {
16450 Object.assign(this, cfg);
16451 }
16452 }
16453 draw(ctx) {
16454 const { inflateAmount , options: { borderColor , backgroundColor } } = this;
16455 const { inner , outer } = boundingRects(this);
16456 const addRectPath = hasRadius(outer.radius) ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw : addNormalRectPath;
16457 ctx.save();
16458 if (outer.w !== inner.w || outer.h !== inner.h) {
16459 ctx.beginPath();
16460 addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
16461 ctx.clip();
16462 addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
16463 ctx.fillStyle = borderColor;
16464 ctx.fill('evenodd');
16465 }
16466 ctx.beginPath();
16467 addRectPath(ctx, inflateRect(inner, inflateAmount));
16468 ctx.fillStyle = backgroundColor;
16469 ctx.fill();
16470 ctx.restore();
16471 }
16472 inRange(mouseX, mouseY, useFinalPosition) {
16473 return inRange(this, mouseX, mouseY, useFinalPosition);
16474 }
16475 inXRange(mouseX, useFinalPosition) {
16476 return inRange(this, mouseX, null, useFinalPosition);
16477 }
16478 inYRange(mouseY, useFinalPosition) {
16479 return inRange(this, null, mouseY, useFinalPosition);
16480 }
16481 getCenterPoint(useFinalPosition) {
16482 const { x , y , base , horizontal } = this.getProps([
16483 'x',
16484 'y',
16485 'base',
16486 'horizontal'
16487 ], useFinalPosition);
16488 return {
16489 x: horizontal ? (x + base) / 2 : x,
16490 y: horizontal ? y : (y + base) / 2
16491 };
16492 }
16493 getRange(axis) {
16494 return axis === 'x' ? this.width / 2 : this.height / 2;
16495 }
16496 }
16497
16498 var elements = /*#__PURE__*/Object.freeze({
16499 __proto__: null,
16500 ArcElement: ArcElement,
16501 BarElement: BarElement,
16502 LineElement: LineElement,
16503 PointElement: PointElement
16504 });
16505
16506 const BORDER_COLORS = [
16507 'rgb(54, 162, 235)',
16508 'rgb(255, 99, 132)',
16509 'rgb(255, 159, 64)',
16510 'rgb(255, 205, 86)',
16511 'rgb(75, 192, 192)',
16512 'rgb(153, 102, 255)',
16513 'rgb(201, 203, 207)' // grey
16514 ];
16515 // Border colors with 50% transparency
16516 const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)'));
16517 function getBorderColor(i) {
16518 return BORDER_COLORS[i % BORDER_COLORS.length];
16519 }
16520 function getBackgroundColor(i) {
16521 return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length];
16522 }
16523 function colorizeDefaultDataset(dataset, i) {
16524 dataset.borderColor = getBorderColor(i);
16525 dataset.backgroundColor = getBackgroundColor(i);
16526 return ++i;
16527 }
16528 function colorizeDoughnutDataset(dataset, i) {
16529 dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++));
16530 return i;
16531 }
16532 function colorizePolarAreaDataset(dataset, i) {
16533 dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++));
16534 return i;
16535 }
16536 function getColorizer(chart) {
16537 let i = 0;
16538 return (dataset, datasetIndex)=>{
16539 const controller = chart.getDatasetMeta(datasetIndex).controller;
16540 if (controller instanceof DoughnutController) {
16541 i = colorizeDoughnutDataset(dataset, i);
16542 } else if (controller instanceof PolarAreaController) {
16543 i = colorizePolarAreaDataset(dataset, i);
16544 } else if (controller) {
16545 i = colorizeDefaultDataset(dataset, i);
16546 }
16547 };
16548 }
16549 function containsColorsDefinitions(descriptors) {
16550 let k;
16551 for(k in descriptors){
16552 if (descriptors[k].borderColor || descriptors[k].backgroundColor) {
16553 return true;
16554 }
16555 }
16556 return false;
16557 }
16558 function containsColorsDefinition(descriptor) {
16559 return descriptor && (descriptor.borderColor || descriptor.backgroundColor);
16560 }
16561 function containsDefaultColorsDefenitions() {
16562 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)';
16563 }
16564 var plugin_colors = {
16565 id: 'colors',
16566 defaults: {
16567 enabled: true,
16568 forceOverride: false
16569 },
16570 beforeLayout (chart, _args, options) {
16571 if (!options.enabled) {
16572 return;
16573 }
16574 const { data: { datasets } , options: chartOptions } = chart.config;
16575 const { elements } = chartOptions;
16576 const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions();
16577 if (!options.forceOverride && containsColorDefenition) {
16578 return;
16579 }
16580 const colorizer = getColorizer(chart);
16581 datasets.forEach(colorizer);
16582 }
16583 };
16584
16585 function lttbDecimation(data, start, count, availableWidth, options) {
16586 const samples = options.samples || availableWidth;
16587 if (samples >= count) {
16588 return data.slice(start, start + count);
16589 }
16590 const decimated = [];
16591 const bucketWidth = (count - 2) / (samples - 2);
16592 let sampledIndex = 0;
16593 const endIndex = start + count - 1;
16594 let a = start;
16595 let i, maxAreaPoint, maxArea, area, nextA;
16596 decimated[sampledIndex++] = data[a];
16597 for(i = 0; i < samples - 2; i++){
16598 let avgX = 0;
16599 let avgY = 0;
16600 let j;
16601 const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;
16602 const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;
16603 const avgRangeLength = avgRangeEnd - avgRangeStart;
16604 for(j = avgRangeStart; j < avgRangeEnd; j++){
16605 avgX += data[j].x;
16606 avgY += data[j].y;
16607 }
16608 avgX /= avgRangeLength;
16609 avgY /= avgRangeLength;
16610 const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;
16611 const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;
16612 const { x: pointAx , y: pointAy } = data[a];
16613 maxArea = area = -1;
16614 for(j = rangeOffs; j < rangeTo; j++){
16615 area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy));
16616 if (area > maxArea) {
16617 maxArea = area;
16618 maxAreaPoint = data[j];
16619 nextA = j;
16620 }
16621 }
16622 decimated[sampledIndex++] = maxAreaPoint;
16623 a = nextA;
16624 }
16625 decimated[sampledIndex++] = data[endIndex];
16626 return decimated;
16627 }
16628 function minMaxDecimation(data, start, count, availableWidth) {
16629 let avgX = 0;
16630 let countX = 0;
16631 let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
16632 const decimated = [];
16633 const endIndex = start + count - 1;
16634 const xMin = data[start].x;
16635 const xMax = data[endIndex].x;
16636 const dx = xMax - xMin;
16637 for(i = start; i < start + count; ++i){
16638 point = data[i];
16639 x = (point.x - xMin) / dx * availableWidth;
16640 y = point.y;
16641 const truncX = x | 0;
16642 if (truncX === prevX) {
16643 if (y < minY) {
16644 minY = y;
16645 minIndex = i;
16646 } else if (y > maxY) {
16647 maxY = y;
16648 maxIndex = i;
16649 }
16650 avgX = (countX * avgX + point.x) / ++countX;
16651 } else {
16652 const lastIndex = i - 1;
16653 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(minIndex) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(maxIndex)) {
16654 const intermediateIndex1 = Math.min(minIndex, maxIndex);
16655 const intermediateIndex2 = Math.max(minIndex, maxIndex);
16656 if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
16657 decimated.push({
16658 ...data[intermediateIndex1],
16659 x: avgX
16660 });
16661 }
16662 if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
16663 decimated.push({
16664 ...data[intermediateIndex2],
16665 x: avgX
16666 });
16667 }
16668 }
16669 if (i > 0 && lastIndex !== startIndex) {
16670 decimated.push(data[lastIndex]);
16671 }
16672 decimated.push(point);
16673 prevX = truncX;
16674 countX = 0;
16675 minY = maxY = y;
16676 minIndex = maxIndex = startIndex = i;
16677 }
16678 }
16679 return decimated;
16680 }
16681 function cleanDecimatedDataset(dataset) {
16682 if (dataset._decimated) {
16683 const data = dataset._data;
16684 delete dataset._decimated;
16685 delete dataset._data;
16686 Object.defineProperty(dataset, 'data', {
16687 configurable: true,
16688 enumerable: true,
16689 writable: true,
16690 value: data
16691 });
16692 }
16693 }
16694 function cleanDecimatedData(chart) {
16695 chart.data.datasets.forEach((dataset)=>{
16696 cleanDecimatedDataset(dataset);
16697 });
16698 }
16699 function getStartAndCountOfVisiblePointsSimplified(meta, points) {
16700 const pointCount = points.length;
16701 let start = 0;
16702 let count;
16703 const { iScale } = meta;
16704 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
16705 if (minDefined) {
16706 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);
16707 }
16708 if (maxDefined) {
16709 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;
16710 } else {
16711 count = pointCount - start;
16712 }
16713 return {
16714 start,
16715 count
16716 };
16717 }
16718 var plugin_decimation = {
16719 id: 'decimation',
16720 defaults: {
16721 algorithm: 'min-max',
16722 enabled: false
16723 },
16724 beforeElementsUpdate: (chart, args, options)=>{
16725 if (!options.enabled) {
16726 cleanDecimatedData(chart);
16727 return;
16728 }
16729 const availableWidth = chart.width;
16730 chart.data.datasets.forEach((dataset, datasetIndex)=>{
16731 const { _data , indexAxis } = dataset;
16732 const meta = chart.getDatasetMeta(datasetIndex);
16733 const data = _data || dataset.data;
16734 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
16735 indexAxis,
16736 chart.options.indexAxis
16737 ]) === 'y') {
16738 return;
16739 }
16740 if (!meta.controller.supportsDecimation) {
16741 return;
16742 }
16743 const xAxis = chart.scales[meta.xAxisID];
16744 if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
16745 return;
16746 }
16747 if (chart.options.parsing) {
16748 return;
16749 }
16750 let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data);
16751 const threshold = options.threshold || 4 * availableWidth;
16752 if (count <= threshold) {
16753 cleanDecimatedDataset(dataset);
16754 return;
16755 }
16756 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(_data)) {
16757 dataset._data = data;
16758 delete dataset.data;
16759 Object.defineProperty(dataset, 'data', {
16760 configurable: true,
16761 enumerable: true,
16762 get: function() {
16763 return this._decimated;
16764 },
16765 set: function(d) {
16766 this._data = d;
16767 }
16768 });
16769 }
16770 let decimated;
16771 switch(options.algorithm){
16772 case 'lttb':
16773 decimated = lttbDecimation(data, start, count, availableWidth, options);
16774 break;
16775 case 'min-max':
16776 decimated = minMaxDecimation(data, start, count, availableWidth);
16777 break;
16778 default:
16779 throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
16780 }
16781 dataset._decimated = decimated;
16782 });
16783 },
16784 destroy (chart) {
16785 cleanDecimatedData(chart);
16786 }
16787 };
16788
16789 function _segments(line, target, property) {
16790 const segments = line.segments;
16791 const points = line.points;
16792 const tpoints = target.points;
16793 const parts = [];
16794 for (const segment of segments){
16795 let { start , end } = segment;
16796 end = _findSegmentEnd(start, end, points);
16797 const bounds = _getBounds(property, points[start], points[end], segment.loop);
16798 if (!target.segments) {
16799 parts.push({
16800 source: segment,
16801 target: bounds,
16802 start: points[start],
16803 end: points[end]
16804 });
16805 continue;
16806 }
16807 const targetSegments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(target, bounds);
16808 for (const tgt of targetSegments){
16809 const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);
16810 const fillSources = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.az)(segment, points, subBounds);
16811 for (const fillSource of fillSources){
16812 parts.push({
16813 source: fillSource,
16814 target: tgt,
16815 start: {
16816 [property]: _getEdge(bounds, subBounds, 'start', Math.max)
16817 },
16818 end: {
16819 [property]: _getEdge(bounds, subBounds, 'end', Math.min)
16820 }
16821 });
16822 }
16823 }
16824 }
16825 return parts;
16826 }
16827 function _getBounds(property, first, last, loop) {
16828 if (loop) {
16829 return;
16830 }
16831 let start = first[property];
16832 let end = last[property];
16833 if (property === 'angle') {
16834 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(start);
16835 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(end);
16836 }
16837 return {
16838 property,
16839 start,
16840 end
16841 };
16842 }
16843 function _pointsFromSegments(boundary, line) {
16844 const { x =null , y =null } = boundary || {};
16845 const linePoints = line.points;
16846 const points = [];
16847 line.segments.forEach(({ start , end })=>{
16848 end = _findSegmentEnd(start, end, linePoints);
16849 const first = linePoints[start];
16850 const last = linePoints[end];
16851 if (y !== null) {
16852 points.push({
16853 x: first.x,
16854 y
16855 });
16856 points.push({
16857 x: last.x,
16858 y
16859 });
16860 } else if (x !== null) {
16861 points.push({
16862 x,
16863 y: first.y
16864 });
16865 points.push({
16866 x,
16867 y: last.y
16868 });
16869 }
16870 });
16871 return points;
16872 }
16873 function _findSegmentEnd(start, end, points) {
16874 for(; end > start; end--){
16875 const point = points[end];
16876 if (!isNaN(point.x) && !isNaN(point.y)) {
16877 break;
16878 }
16879 }
16880 return end;
16881 }
16882 function _getEdge(a, b, prop, fn) {
16883 if (a && b) {
16884 return fn(a[prop], b[prop]);
16885 }
16886 return a ? a[prop] : b ? b[prop] : 0;
16887 }
16888
16889 function _createBoundaryLine(boundary, line) {
16890 let points = [];
16891 let _loop = false;
16892 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(boundary)) {
16893 _loop = true;
16894 points = boundary;
16895 } else {
16896 points = _pointsFromSegments(boundary, line);
16897 }
16898 return points.length ? new LineElement({
16899 points,
16900 options: {
16901 tension: 0
16902 },
16903 _loop,
16904 _fullLoop: _loop
16905 }) : null;
16906 }
16907 function _shouldApplyFill(source) {
16908 return source && source.fill !== false;
16909 }
16910
16911 function _resolveTarget(sources, index, propagate) {
16912 const source = sources[index];
16913 let fill = source.fill;
16914 const visited = [
16915 index
16916 ];
16917 let target;
16918 if (!propagate) {
16919 return fill;
16920 }
16921 while(fill !== false && visited.indexOf(fill) === -1){
16922 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16923 return fill;
16924 }
16925 target = sources[fill];
16926 if (!target) {
16927 return false;
16928 }
16929 if (target.visible) {
16930 return fill;
16931 }
16932 visited.push(fill);
16933 fill = target.fill;
16934 }
16935 return false;
16936 }
16937 function _decodeFill(line, index, count) {
16938 const fill = parseFillOption(line);
16939 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16940 return isNaN(fill.value) ? false : fill;
16941 }
16942 let target = parseFloat(fill);
16943 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(target) && Math.floor(target) === target) {
16944 return decodeTargetIndex(fill[0], index, target, count);
16945 }
16946 return [
16947 'origin',
16948 'start',
16949 'end',
16950 'stack',
16951 'shape'
16952 ].indexOf(fill) >= 0 && fill;
16953 }
16954 function decodeTargetIndex(firstCh, index, target, count) {
16955 if (firstCh === '-' || firstCh === '+') {
16956 target = index + target;
16957 }
16958 if (target === index || target < 0 || target >= count) {
16959 return false;
16960 }
16961 return target;
16962 }
16963 function _getTargetPixel(fill, scale) {
16964 let pixel = null;
16965 if (fill === 'start') {
16966 pixel = scale.bottom;
16967 } else if (fill === 'end') {
16968 pixel = scale.top;
16969 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16970 pixel = scale.getPixelForValue(fill.value);
16971 } else if (scale.getBasePixel) {
16972 pixel = scale.getBasePixel();
16973 }
16974 return pixel;
16975 }
16976 function _getTargetValue(fill, scale, startValue) {
16977 let value;
16978 if (fill === 'start') {
16979 value = startValue;
16980 } else if (fill === 'end') {
16981 value = scale.options.reverse ? scale.min : scale.max;
16982 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16983 value = fill.value;
16984 } else {
16985 value = scale.getBaseValue();
16986 }
16987 return value;
16988 }
16989 function parseFillOption(line) {
16990 const options = line.options;
16991 const fillOption = options.fill;
16992 let fill = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(fillOption && fillOption.target, fillOption);
16993 if (fill === undefined) {
16994 fill = !!options.backgroundColor;
16995 }
16996 if (fill === false || fill === null) {
16997 return false;
16998 }
16999 if (fill === true) {
17000 return 'origin';
17001 }
17002 return fill;
17003 }
17004
17005 function _buildStackLine(source) {
17006 const { scale , index , line } = source;
17007 const points = [];
17008 const segments = line.segments;
17009 const sourcePoints = line.points;
17010 const linesBelow = getLinesBelow(scale, index);
17011 linesBelow.push(_createBoundaryLine({
17012 x: null,
17013 y: scale.bottom
17014 }, line));
17015 for(let i = 0; i < segments.length; i++){
17016 const segment = segments[i];
17017 for(let j = segment.start; j <= segment.end; j++){
17018 addPointsBelow(points, sourcePoints[j], linesBelow);
17019 }
17020 }
17021 return new LineElement({
17022 points,
17023 options: {}
17024 });
17025 }
17026 function getLinesBelow(scale, index) {
17027 const below = [];
17028 const metas = scale.getMatchingVisibleMetas('line');
17029 for(let i = 0; i < metas.length; i++){
17030 const meta = metas[i];
17031 if (meta.index === index) {
17032 break;
17033 }
17034 if (!meta.hidden) {
17035 below.unshift(meta.dataset);
17036 }
17037 }
17038 return below;
17039 }
17040 function addPointsBelow(points, sourcePoint, linesBelow) {
17041 const postponed = [];
17042 for(let j = 0; j < linesBelow.length; j++){
17043 const line = linesBelow[j];
17044 const { first , last , point } = findPoint(line, sourcePoint, 'x');
17045 if (!point || first && last) {
17046 continue;
17047 }
17048 if (first) {
17049 postponed.unshift(point);
17050 } else {
17051 points.push(point);
17052 if (!last) {
17053 break;
17054 }
17055 }
17056 }
17057 points.push(...postponed);
17058 }
17059 function findPoint(line, sourcePoint, property) {
17060 const point = line.interpolate(sourcePoint, property);
17061 if (!point) {
17062 return {};
17063 }
17064 const pointValue = point[property];
17065 const segments = line.segments;
17066 const linePoints = line.points;
17067 let first = false;
17068 let last = false;
17069 for(let i = 0; i < segments.length; i++){
17070 const segment = segments[i];
17071 const firstValue = linePoints[segment.start][property];
17072 const lastValue = linePoints[segment.end][property];
17073 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(pointValue, firstValue, lastValue)) {
17074 first = pointValue === firstValue;
17075 last = pointValue === lastValue;
17076 break;
17077 }
17078 }
17079 return {
17080 first,
17081 last,
17082 point
17083 };
17084 }
17085
17086 class simpleArc {
17087 constructor(opts){
17088 this.x = opts.x;
17089 this.y = opts.y;
17090 this.radius = opts.radius;
17091 }
17092 pathSegment(ctx, bounds, opts) {
17093 const { x , y , radius } = this;
17094 bounds = bounds || {
17095 start: 0,
17096 end: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T
17097 };
17098 ctx.arc(x, y, radius, bounds.end, bounds.start, true);
17099 return !opts.bounds;
17100 }
17101 interpolate(point) {
17102 const { x , y , radius } = this;
17103 const angle = point.angle;
17104 return {
17105 x: x + Math.cos(angle) * radius,
17106 y: y + Math.sin(angle) * radius,
17107 angle
17108 };
17109 }
17110 }
17111
17112 function _getTarget(source) {
17113 const { chart , fill , line } = source;
17114 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
17115 return getLineByIndex(chart, fill);
17116 }
17117 if (fill === 'stack') {
17118 return _buildStackLine(source);
17119 }
17120 if (fill === 'shape') {
17121 return true;
17122 }
17123 const boundary = computeBoundary(source);
17124 if (boundary instanceof simpleArc) {
17125 return boundary;
17126 }
17127 return _createBoundaryLine(boundary, line);
17128 }
17129 function getLineByIndex(chart, index) {
17130 const meta = chart.getDatasetMeta(index);
17131 const visible = meta && chart.isDatasetVisible(index);
17132 return visible ? meta.dataset : null;
17133 }
17134 function computeBoundary(source) {
17135 const scale = source.scale || {};
17136 if (scale.getPointPositionForValue) {
17137 return computeCircularBoundary(source);
17138 }
17139 return computeLinearBoundary(source);
17140 }
17141 function computeLinearBoundary(source) {
17142 const { scale ={} , fill } = source;
17143 const pixel = _getTargetPixel(fill, scale);
17144 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(pixel)) {
17145 const horizontal = scale.isHorizontal();
17146 return {
17147 x: horizontal ? pixel : null,
17148 y: horizontal ? null : pixel
17149 };
17150 }
17151 return null;
17152 }
17153 function computeCircularBoundary(source) {
17154 const { scale , fill } = source;
17155 const options = scale.options;
17156 const length = scale.getLabels().length;
17157 const start = options.reverse ? scale.max : scale.min;
17158 const value = _getTargetValue(fill, scale, start);
17159 const target = [];
17160 if (options.grid.circular) {
17161 const center = scale.getPointPositionForValue(0, start);
17162 return new simpleArc({
17163 x: center.x,
17164 y: center.y,
17165 radius: scale.getDistanceFromCenterForValue(value)
17166 });
17167 }
17168 for(let i = 0; i < length; ++i){
17169 target.push(scale.getPointPositionForValue(i, value));
17170 }
17171 return target;
17172 }
17173
17174 function _drawfill(ctx, source, area) {
17175 const target = _getTarget(source);
17176 const { chart , index , line , scale , axis } = source;
17177 const lineOpts = line.options;
17178 const fillOption = lineOpts.fill;
17179 const color = lineOpts.backgroundColor;
17180 const { above =color , below =color } = fillOption || {};
17181 const meta = chart.getDatasetMeta(index);
17182 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(chart, meta);
17183 if (target && line.points.length) {
17184 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
17185 doFill(ctx, {
17186 line,
17187 target,
17188 above,
17189 below,
17190 area,
17191 scale,
17192 axis,
17193 clip
17194 });
17195 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17196 }
17197 }
17198 function doFill(ctx, cfg) {
17199 const { line , target , above , below , area , scale , clip } = cfg;
17200 const property = line._loop ? 'angle' : cfg.axis;
17201 ctx.save();
17202 let fillColor = below;
17203 if (below !== above) {
17204 if (property === 'x') {
17205 clipVertical(ctx, target, area.top);
17206 fill(ctx, {
17207 line,
17208 target,
17209 color: above,
17210 scale,
17211 property,
17212 clip
17213 });
17214 ctx.restore();
17215 ctx.save();
17216 clipVertical(ctx, target, area.bottom);
17217 } else if (property === 'y') {
17218 clipHorizontal(ctx, target, area.left);
17219 fill(ctx, {
17220 line,
17221 target,
17222 color: below,
17223 scale,
17224 property,
17225 clip
17226 });
17227 ctx.restore();
17228 ctx.save();
17229 clipHorizontal(ctx, target, area.right);
17230 fillColor = above;
17231 }
17232 }
17233 fill(ctx, {
17234 line,
17235 target,
17236 color: fillColor,
17237 scale,
17238 property,
17239 clip
17240 });
17241 ctx.restore();
17242 }
17243 function clipVertical(ctx, target, clipY) {
17244 const { segments , points } = target;
17245 let first = true;
17246 let lineLoop = false;
17247 ctx.beginPath();
17248 for (const segment of segments){
17249 const { start , end } = segment;
17250 const firstPoint = points[start];
17251 const lastPoint = points[_findSegmentEnd(start, end, points)];
17252 if (first) {
17253 ctx.moveTo(firstPoint.x, firstPoint.y);
17254 first = false;
17255 } else {
17256 ctx.lineTo(firstPoint.x, clipY);
17257 ctx.lineTo(firstPoint.x, firstPoint.y);
17258 }
17259 lineLoop = !!target.pathSegment(ctx, segment, {
17260 move: lineLoop
17261 });
17262 if (lineLoop) {
17263 ctx.closePath();
17264 } else {
17265 ctx.lineTo(lastPoint.x, clipY);
17266 }
17267 }
17268 ctx.lineTo(target.first().x, clipY);
17269 ctx.closePath();
17270 ctx.clip();
17271 }
17272 function clipHorizontal(ctx, target, clipX) {
17273 const { segments , points } = target;
17274 let first = true;
17275 let lineLoop = false;
17276 ctx.beginPath();
17277 for (const segment of segments){
17278 const { start , end } = segment;
17279 const firstPoint = points[start];
17280 const lastPoint = points[_findSegmentEnd(start, end, points)];
17281 if (first) {
17282 ctx.moveTo(firstPoint.x, firstPoint.y);
17283 first = false;
17284 } else {
17285 ctx.lineTo(clipX, firstPoint.y);
17286 ctx.lineTo(firstPoint.x, firstPoint.y);
17287 }
17288 lineLoop = !!target.pathSegment(ctx, segment, {
17289 move: lineLoop
17290 });
17291 if (lineLoop) {
17292 ctx.closePath();
17293 } else {
17294 ctx.lineTo(clipX, lastPoint.y);
17295 }
17296 }
17297 ctx.lineTo(clipX, target.first().y);
17298 ctx.closePath();
17299 ctx.clip();
17300 }
17301 function fill(ctx, cfg) {
17302 const { line , target , property , color , scale , clip } = cfg;
17303 const segments = _segments(line, target, property);
17304 for (const { source: src , target: tgt , start , end } of segments){
17305 const { style: { backgroundColor =color } = {} } = src;
17306 const notShape = target !== true;
17307 ctx.save();
17308 ctx.fillStyle = backgroundColor;
17309 clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end));
17310 ctx.beginPath();
17311 const lineLoop = !!line.pathSegment(ctx, src);
17312 let loop;
17313 if (notShape) {
17314 if (lineLoop) {
17315 ctx.closePath();
17316 } else {
17317 interpolatedLineTo(ctx, target, end, property);
17318 }
17319 const targetLoop = !!target.pathSegment(ctx, tgt, {
17320 move: lineLoop,
17321 reverse: true
17322 });
17323 loop = lineLoop && targetLoop;
17324 if (!loop) {
17325 interpolatedLineTo(ctx, target, start, property);
17326 }
17327 }
17328 ctx.closePath();
17329 ctx.fill(loop ? 'evenodd' : 'nonzero');
17330 ctx.restore();
17331 }
17332 }
17333 function clipBounds(ctx, scale, clip, bounds) {
17334 const chartArea = scale.chart.chartArea;
17335 const { property , start , end } = bounds || {};
17336 if (property === 'x' || property === 'y') {
17337 let left, top, right, bottom;
17338 if (property === 'x') {
17339 left = start;
17340 top = chartArea.top;
17341 right = end;
17342 bottom = chartArea.bottom;
17343 } else {
17344 left = chartArea.left;
17345 top = start;
17346 right = chartArea.right;
17347 bottom = end;
17348 }
17349 ctx.beginPath();
17350 if (clip) {
17351 left = Math.max(left, clip.left);
17352 right = Math.min(right, clip.right);
17353 top = Math.max(top, clip.top);
17354 bottom = Math.min(bottom, clip.bottom);
17355 }
17356 ctx.rect(left, top, right - left, bottom - top);
17357 ctx.clip();
17358 }
17359 }
17360 function interpolatedLineTo(ctx, target, point, property) {
17361 const interpolatedPoint = target.interpolate(point, property);
17362 if (interpolatedPoint) {
17363 ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
17364 }
17365 }
17366
17367 var index = {
17368 id: 'filler',
17369 afterDatasetsUpdate (chart, _args, options) {
17370 const count = (chart.data.datasets || []).length;
17371 const sources = [];
17372 let meta, i, line, source;
17373 for(i = 0; i < count; ++i){
17374 meta = chart.getDatasetMeta(i);
17375 line = meta.dataset;
17376 source = null;
17377 if (line && line.options && line instanceof LineElement) {
17378 source = {
17379 visible: chart.isDatasetVisible(i),
17380 index: i,
17381 fill: _decodeFill(line, i, count),
17382 chart,
17383 axis: meta.controller.options.indexAxis,
17384 scale: meta.vScale,
17385 line
17386 };
17387 }
17388 meta.$filler = source;
17389 sources.push(source);
17390 }
17391 for(i = 0; i < count; ++i){
17392 source = sources[i];
17393 if (!source || source.fill === false) {
17394 continue;
17395 }
17396 source.fill = _resolveTarget(sources, i, options.propagate);
17397 }
17398 },
17399 beforeDraw (chart, _args, options) {
17400 const draw = options.drawTime === 'beforeDraw';
17401 const metasets = chart.getSortedVisibleDatasetMetas();
17402 const area = chart.chartArea;
17403 for(let i = metasets.length - 1; i >= 0; --i){
17404 const source = metasets[i].$filler;
17405 if (!source) {
17406 continue;
17407 }
17408 source.line.updateControlPoints(area, source.axis);
17409 if (draw && source.fill) {
17410 _drawfill(chart.ctx, source, area);
17411 }
17412 }
17413 },
17414 beforeDatasetsDraw (chart, _args, options) {
17415 if (options.drawTime !== 'beforeDatasetsDraw') {
17416 return;
17417 }
17418 const metasets = chart.getSortedVisibleDatasetMetas();
17419 for(let i = metasets.length - 1; i >= 0; --i){
17420 const source = metasets[i].$filler;
17421 if (_shouldApplyFill(source)) {
17422 _drawfill(chart.ctx, source, chart.chartArea);
17423 }
17424 }
17425 },
17426 beforeDatasetDraw (chart, args, options) {
17427 const source = args.meta.$filler;
17428 if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') {
17429 return;
17430 }
17431 _drawfill(chart.ctx, source, chart.chartArea);
17432 },
17433 defaults: {
17434 propagate: true,
17435 drawTime: 'beforeDatasetDraw'
17436 }
17437 };
17438
17439 const getBoxSize = (labelOpts, fontSize)=>{
17440 let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts;
17441 if (labelOpts.usePointStyle) {
17442 boxHeight = Math.min(boxHeight, fontSize);
17443 boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);
17444 }
17445 return {
17446 boxWidth,
17447 boxHeight,
17448 itemHeight: Math.max(fontSize, boxHeight)
17449 };
17450 };
17451 const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
17452 class Legend extends Element {
17453 constructor(config){
17454 super();
17455 this._added = false;
17456 this.legendHitBoxes = [];
17457 this._hoveredItem = null;
17458 this.doughnutMode = false;
17459 this.chart = config.chart;
17460 this.options = config.options;
17461 this.ctx = config.ctx;
17462 this.legendItems = undefined;
17463 this.columnSizes = undefined;
17464 this.lineWidths = undefined;
17465 this.maxHeight = undefined;
17466 this.maxWidth = undefined;
17467 this.top = undefined;
17468 this.bottom = undefined;
17469 this.left = undefined;
17470 this.right = undefined;
17471 this.height = undefined;
17472 this.width = undefined;
17473 this._margins = undefined;
17474 this.position = undefined;
17475 this.weight = undefined;
17476 this.fullSize = undefined;
17477 }
17478 update(maxWidth, maxHeight, margins) {
17479 this.maxWidth = maxWidth;
17480 this.maxHeight = maxHeight;
17481 this._margins = margins;
17482 this.setDimensions();
17483 this.buildLabels();
17484 this.fit();
17485 }
17486 setDimensions() {
17487 if (this.isHorizontal()) {
17488 this.width = this.maxWidth;
17489 this.left = this._margins.left;
17490 this.right = this.width;
17491 } else {
17492 this.height = this.maxHeight;
17493 this.top = this._margins.top;
17494 this.bottom = this.height;
17495 }
17496 }
17497 buildLabels() {
17498 const labelOpts = this.options.labels || {};
17499 let legendItems = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(labelOpts.generateLabels, [
17500 this.chart
17501 ], this) || [];
17502 if (labelOpts.filter) {
17503 legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data));
17504 }
17505 if (labelOpts.sort) {
17506 legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data));
17507 }
17508 if (this.options.reverse) {
17509 legendItems.reverse();
17510 }
17511 this.legendItems = legendItems;
17512 }
17513 fit() {
17514 const { options , ctx } = this;
17515 if (!options.display) {
17516 this.width = this.height = 0;
17517 return;
17518 }
17519 const labelOpts = options.labels;
17520 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17521 const fontSize = labelFont.size;
17522 const titleHeight = this._computeTitleHeight();
17523 const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize);
17524 let width, height;
17525 ctx.font = labelFont.string;
17526 if (this.isHorizontal()) {
17527 width = this.maxWidth;
17528 height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
17529 } else {
17530 height = this.maxHeight;
17531 width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;
17532 }
17533 this.width = Math.min(width, options.maxWidth || this.maxWidth);
17534 this.height = Math.min(height, options.maxHeight || this.maxHeight);
17535 }
17536 _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
17537 const { ctx , maxWidth , options: { labels: { padding } } } = this;
17538 const hitboxes = this.legendHitBoxes = [];
17539 const lineWidths = this.lineWidths = [
17540 0
17541 ];
17542 const lineHeight = itemHeight + padding;
17543 let totalHeight = titleHeight;
17544 ctx.textAlign = 'left';
17545 ctx.textBaseline = 'middle';
17546 let row = -1;
17547 let top = -lineHeight;
17548 this.legendItems.forEach((legendItem, i)=>{
17549 const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;
17550 if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
17551 totalHeight += lineHeight;
17552 lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
17553 top += lineHeight;
17554 row++;
17555 }
17556 hitboxes[i] = {
17557 left: 0,
17558 top,
17559 row,
17560 width: itemWidth,
17561 height: itemHeight
17562 };
17563 lineWidths[lineWidths.length - 1] += itemWidth + padding;
17564 });
17565 return totalHeight;
17566 }
17567 _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {
17568 const { ctx , maxHeight , options: { labels: { padding } } } = this;
17569 const hitboxes = this.legendHitBoxes = [];
17570 const columnSizes = this.columnSizes = [];
17571 const heightLimit = maxHeight - titleHeight;
17572 let totalWidth = padding;
17573 let currentColWidth = 0;
17574 let currentColHeight = 0;
17575 let left = 0;
17576 let col = 0;
17577 this.legendItems.forEach((legendItem, i)=>{
17578 const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);
17579 if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
17580 totalWidth += currentColWidth + padding;
17581 columnSizes.push({
17582 width: currentColWidth,
17583 height: currentColHeight
17584 });
17585 left += currentColWidth + padding;
17586 col++;
17587 currentColWidth = currentColHeight = 0;
17588 }
17589 hitboxes[i] = {
17590 left,
17591 top: currentColHeight,
17592 col,
17593 width: itemWidth,
17594 height: itemHeight
17595 };
17596 currentColWidth = Math.max(currentColWidth, itemWidth);
17597 currentColHeight += itemHeight + padding;
17598 });
17599 totalWidth += currentColWidth;
17600 columnSizes.push({
17601 width: currentColWidth,
17602 height: currentColHeight
17603 });
17604 return totalWidth;
17605 }
17606 adjustHitBoxes() {
17607 if (!this.options.display) {
17608 return;
17609 }
17610 const titleHeight = this._computeTitleHeight();
17611 const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this;
17612 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(rtl, this.left, this.width);
17613 if (this.isHorizontal()) {
17614 let row = 0;
17615 let left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17616 for (const hitbox of hitboxes){
17617 if (row !== hitbox.row) {
17618 row = hitbox.row;
17619 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17620 }
17621 hitbox.top += this.top + titleHeight + padding;
17622 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
17623 left += hitbox.width + padding;
17624 }
17625 } else {
17626 let col = 0;
17627 let top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17628 for (const hitbox of hitboxes){
17629 if (hitbox.col !== col) {
17630 col = hitbox.col;
17631 top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17632 }
17633 hitbox.top = top;
17634 hitbox.left += this.left + padding;
17635 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
17636 top += hitbox.height + padding;
17637 }
17638 }
17639 }
17640 isHorizontal() {
17641 return this.options.position === 'top' || this.options.position === 'bottom';
17642 }
17643 draw() {
17644 if (this.options.display) {
17645 const ctx = this.ctx;
17646 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, this);
17647 this._draw();
17648 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17649 }
17650 }
17651 _draw() {
17652 const { options: opts , columnSizes , lineWidths , ctx } = this;
17653 const { align , labels: labelOpts } = opts;
17654 const defaultColor = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.color;
17655 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17656 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17657 const { padding } = labelOpts;
17658 const fontSize = labelFont.size;
17659 const halfFontSize = fontSize / 2;
17660 let cursor;
17661 this.drawTitle();
17662 ctx.textAlign = rtlHelper.textAlign('left');
17663 ctx.textBaseline = 'middle';
17664 ctx.lineWidth = 0.5;
17665 ctx.font = labelFont.string;
17666 const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize);
17667 const drawLegendBox = function(x, y, legendItem) {
17668 if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
17669 return;
17670 }
17671 ctx.save();
17672 const lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineWidth, 1);
17673 ctx.fillStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.fillStyle, defaultColor);
17674 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineCap, 'butt');
17675 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDashOffset, 0);
17676 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineJoin, 'miter');
17677 ctx.lineWidth = lineWidth;
17678 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.strokeStyle, defaultColor);
17679 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDash, []));
17680 if (labelOpts.usePointStyle) {
17681 const drawOptions = {
17682 radius: boxHeight * Math.SQRT2 / 2,
17683 pointStyle: legendItem.pointStyle,
17684 rotation: legendItem.rotation,
17685 borderWidth: lineWidth
17686 };
17687 const centerX = rtlHelper.xPlus(x, boxWidth / 2);
17688 const centerY = y + halfFontSize;
17689 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aE)(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);
17690 } else {
17691 const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
17692 const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);
17693 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(legendItem.borderRadius);
17694 ctx.beginPath();
17695 if (Object.values(borderRadius).some((v)=>v !== 0)) {
17696 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
17697 x: xBoxLeft,
17698 y: yBoxTop,
17699 w: boxWidth,
17700 h: boxHeight,
17701 radius: borderRadius
17702 });
17703 } else {
17704 ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
17705 }
17706 ctx.fill();
17707 if (lineWidth !== 0) {
17708 ctx.stroke();
17709 }
17710 }
17711 ctx.restore();
17712 };
17713 const fillText = function(x, y, legendItem) {
17714 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, {
17715 strikethrough: legendItem.hidden,
17716 textAlign: rtlHelper.textAlign(legendItem.textAlign)
17717 });
17718 };
17719 const isHorizontal = this.isHorizontal();
17720 const titleHeight = this._computeTitleHeight();
17721 if (isHorizontal) {
17722 cursor = {
17723 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[0]),
17724 y: this.top + padding + titleHeight,
17725 line: 0
17726 };
17727 } else {
17728 cursor = {
17729 x: this.left + padding,
17730 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
17731 line: 0
17732 };
17733 }
17734 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(this.ctx, opts.textDirection);
17735 const lineHeight = itemHeight + padding;
17736 this.legendItems.forEach((legendItem, i)=>{
17737 ctx.strokeStyle = legendItem.fontColor;
17738 ctx.fillStyle = legendItem.fontColor;
17739 const textWidth = ctx.measureText(legendItem.text).width;
17740 const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
17741 const width = boxWidth + halfFontSize + textWidth;
17742 let x = cursor.x;
17743 let y = cursor.y;
17744 rtlHelper.setWidth(this.width);
17745 if (isHorizontal) {
17746 if (i > 0 && x + width + padding > this.right) {
17747 y = cursor.y += lineHeight;
17748 cursor.line++;
17749 x = cursor.x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[cursor.line]);
17750 }
17751 } else if (i > 0 && y + lineHeight > this.bottom) {
17752 x = cursor.x = x + columnSizes[cursor.line].width + padding;
17753 cursor.line++;
17754 y = cursor.y = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
17755 }
17756 const realX = rtlHelper.x(x);
17757 drawLegendBox(realX, y, legendItem);
17758 x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aC)(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
17759 fillText(rtlHelper.x(x), y, legendItem);
17760 if (isHorizontal) {
17761 cursor.x += width + padding;
17762 } else if (typeof legendItem.text !== 'string') {
17763 const fontLineHeight = labelFont.lineHeight;
17764 cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;
17765 } else {
17766 cursor.y += lineHeight;
17767 }
17768 });
17769 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(this.ctx, opts.textDirection);
17770 }
17771 drawTitle() {
17772 const opts = this.options;
17773 const titleOpts = opts.title;
17774 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17775 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17776 if (!titleOpts.display) {
17777 return;
17778 }
17779 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17780 const ctx = this.ctx;
17781 const position = titleOpts.position;
17782 const halfFontSize = titleFont.size / 2;
17783 const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
17784 let y;
17785 let left = this.left;
17786 let maxWidth = this.width;
17787 if (this.isHorizontal()) {
17788 maxWidth = Math.max(...this.lineWidths);
17789 y = this.top + topPaddingPlusHalfFontSize;
17790 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, left, this.right - maxWidth);
17791 } else {
17792 const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0);
17793 y = topPaddingPlusHalfFontSize + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
17794 }
17795 const x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(position, left, left + maxWidth);
17796 ctx.textAlign = rtlHelper.textAlign((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(position));
17797 ctx.textBaseline = 'middle';
17798 ctx.strokeStyle = titleOpts.color;
17799 ctx.fillStyle = titleOpts.color;
17800 ctx.font = titleFont.string;
17801 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, titleOpts.text, x, y, titleFont);
17802 }
17803 _computeTitleHeight() {
17804 const titleOpts = this.options.title;
17805 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17806 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17807 return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
17808 }
17809 _getLegendItemAt(x, y) {
17810 let i, hitBox, lh;
17811 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)) {
17812 lh = this.legendHitBoxes;
17813 for(i = 0; i < lh.length; ++i){
17814 hitBox = lh[i];
17815 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)) {
17816 return this.legendItems[i];
17817 }
17818 }
17819 }
17820 return null;
17821 }
17822 handleEvent(e) {
17823 const opts = this.options;
17824 if (!isListened(e.type, opts)) {
17825 return;
17826 }
17827 const hoveredItem = this._getLegendItemAt(e.x, e.y);
17828 if (e.type === 'mousemove' || e.type === 'mouseout') {
17829 const previous = this._hoveredItem;
17830 const sameItem = itemsEqual(previous, hoveredItem);
17831 if (previous && !sameItem) {
17832 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onLeave, [
17833 e,
17834 previous,
17835 this
17836 ], this);
17837 }
17838 this._hoveredItem = hoveredItem;
17839 if (hoveredItem && !sameItem) {
17840 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onHover, [
17841 e,
17842 hoveredItem,
17843 this
17844 ], this);
17845 }
17846 } else if (hoveredItem) {
17847 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onClick, [
17848 e,
17849 hoveredItem,
17850 this
17851 ], this);
17852 }
17853 }
17854 }
17855 function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {
17856 const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);
17857 const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);
17858 return {
17859 itemWidth,
17860 itemHeight
17861 };
17862 }
17863 function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {
17864 let legendItemText = legendItem.text;
17865 if (legendItemText && typeof legendItemText !== 'string') {
17866 legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b);
17867 }
17868 return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;
17869 }
17870 function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {
17871 let itemHeight = _itemHeight;
17872 if (typeof legendItem.text !== 'string') {
17873 itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);
17874 }
17875 return itemHeight;
17876 }
17877 function calculateLegendItemHeight(legendItem, fontLineHeight) {
17878 const labelHeight = legendItem.text ? legendItem.text.length : 0;
17879 return fontLineHeight * labelHeight;
17880 }
17881 function isListened(type, opts) {
17882 if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) {
17883 return true;
17884 }
17885 if (opts.onClick && (type === 'click' || type === 'mouseup')) {
17886 return true;
17887 }
17888 return false;
17889 }
17890 var plugin_legend = {
17891 id: 'legend',
17892 _element: Legend,
17893 start (chart, _args, options) {
17894 const legend = chart.legend = new Legend({
17895 ctx: chart.ctx,
17896 options,
17897 chart
17898 });
17899 layouts.configure(chart, legend, options);
17900 layouts.addBox(chart, legend);
17901 },
17902 stop (chart) {
17903 layouts.removeBox(chart, chart.legend);
17904 delete chart.legend;
17905 },
17906 beforeUpdate (chart, _args, options) {
17907 const legend = chart.legend;
17908 layouts.configure(chart, legend, options);
17909 legend.options = options;
17910 },
17911 afterUpdate (chart) {
17912 const legend = chart.legend;
17913 legend.buildLabels();
17914 legend.adjustHitBoxes();
17915 },
17916 afterEvent (chart, args) {
17917 if (!args.replay) {
17918 chart.legend.handleEvent(args.event);
17919 }
17920 },
17921 defaults: {
17922 display: true,
17923 position: 'top',
17924 align: 'center',
17925 fullSize: true,
17926 reverse: false,
17927 weight: 1000,
17928 onClick (e, legendItem, legend) {
17929 const index = legendItem.datasetIndex;
17930 const ci = legend.chart;
17931 if (ci.isDatasetVisible(index)) {
17932 ci.hide(index);
17933 legendItem.hidden = true;
17934 } else {
17935 ci.show(index);
17936 legendItem.hidden = false;
17937 }
17938 },
17939 onHover: null,
17940 onLeave: null,
17941 labels: {
17942 color: (ctx)=>ctx.chart.options.color,
17943 boxWidth: 40,
17944 padding: 10,
17945 generateLabels (chart) {
17946 const datasets = chart.data.datasets;
17947 const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
17948 return chart._getSortedDatasetMetas().map((meta)=>{
17949 const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
17950 const borderWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(style.borderWidth);
17951 return {
17952 text: datasets[meta.index].label,
17953 fillStyle: style.backgroundColor,
17954 fontColor: color,
17955 hidden: !meta.visible,
17956 lineCap: style.borderCapStyle,
17957 lineDash: style.borderDash,
17958 lineDashOffset: style.borderDashOffset,
17959 lineJoin: style.borderJoinStyle,
17960 lineWidth: (borderWidth.width + borderWidth.height) / 4,
17961 strokeStyle: style.borderColor,
17962 pointStyle: pointStyle || style.pointStyle,
17963 rotation: style.rotation,
17964 textAlign: textAlign || style.textAlign,
17965 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
17966 datasetIndex: meta.index
17967 };
17968 }, this);
17969 }
17970 },
17971 title: {
17972 color: (ctx)=>ctx.chart.options.color,
17973 display: false,
17974 position: 'center',
17975 text: ''
17976 }
17977 },
17978 descriptors: {
17979 _scriptable: (name)=>!name.startsWith('on'),
17980 labels: {
17981 _scriptable: (name)=>![
17982 'generateLabels',
17983 'filter',
17984 'sort'
17985 ].includes(name)
17986 }
17987 }
17988 };
17989
17990 class Title extends Element {
17991 constructor(config){
17992 super();
17993 this.chart = config.chart;
17994 this.options = config.options;
17995 this.ctx = config.ctx;
17996 this._padding = undefined;
17997 this.top = undefined;
17998 this.bottom = undefined;
17999 this.left = undefined;
18000 this.right = undefined;
18001 this.width = undefined;
18002 this.height = undefined;
18003 this.position = undefined;
18004 this.weight = undefined;
18005 this.fullSize = undefined;
18006 }
18007 update(maxWidth, maxHeight) {
18008 const opts = this.options;
18009 this.left = 0;
18010 this.top = 0;
18011 if (!opts.display) {
18012 this.width = this.height = this.right = this.bottom = 0;
18013 return;
18014 }
18015 this.width = this.right = maxWidth;
18016 this.height = this.bottom = maxHeight;
18017 const lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(opts.text) ? opts.text.length : 1;
18018 this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.padding);
18019 const textSize = lineCount * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font).lineHeight + this._padding.height;
18020 if (this.isHorizontal()) {
18021 this.height = textSize;
18022 } else {
18023 this.width = textSize;
18024 }
18025 }
18026 isHorizontal() {
18027 const pos = this.options.position;
18028 return pos === 'top' || pos === 'bottom';
18029 }
18030 _drawArgs(offset) {
18031 const { top , left , bottom , right , options } = this;
18032 const align = options.align;
18033 let rotation = 0;
18034 let maxWidth, titleX, titleY;
18035 if (this.isHorizontal()) {
18036 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
18037 titleY = top + offset;
18038 maxWidth = right - left;
18039 } else {
18040 if (options.position === 'left') {
18041 titleX = left + offset;
18042 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
18043 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * -0.5;
18044 } else {
18045 titleX = right - offset;
18046 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, top, bottom);
18047 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * 0.5;
18048 }
18049 maxWidth = bottom - top;
18050 }
18051 return {
18052 titleX,
18053 titleY,
18054 maxWidth,
18055 rotation
18056 };
18057 }
18058 draw() {
18059 const ctx = this.ctx;
18060 const opts = this.options;
18061 if (!opts.display) {
18062 return;
18063 }
18064 const fontOpts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
18065 const lineHeight = fontOpts.lineHeight;
18066 const offset = lineHeight / 2 + this._padding.top;
18067 const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset);
18068 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, opts.text, 0, 0, fontOpts, {
18069 color: opts.color,
18070 maxWidth,
18071 rotation,
18072 textAlign: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(opts.align),
18073 textBaseline: 'middle',
18074 translation: [
18075 titleX,
18076 titleY
18077 ]
18078 });
18079 }
18080 }
18081 function createTitle(chart, titleOpts) {
18082 const title = new Title({
18083 ctx: chart.ctx,
18084 options: titleOpts,
18085 chart
18086 });
18087 layouts.configure(chart, title, titleOpts);
18088 layouts.addBox(chart, title);
18089 chart.titleBlock = title;
18090 }
18091 var plugin_title = {
18092 id: 'title',
18093 _element: Title,
18094 start (chart, _args, options) {
18095 createTitle(chart, options);
18096 },
18097 stop (chart) {
18098 const titleBlock = chart.titleBlock;
18099 layouts.removeBox(chart, titleBlock);
18100 delete chart.titleBlock;
18101 },
18102 beforeUpdate (chart, _args, options) {
18103 const title = chart.titleBlock;
18104 layouts.configure(chart, title, options);
18105 title.options = options;
18106 },
18107 defaults: {
18108 align: 'center',
18109 display: false,
18110 font: {
18111 weight: 'bold'
18112 },
18113 fullSize: true,
18114 padding: 10,
18115 position: 'top',
18116 text: '',
18117 weight: 2000
18118 },
18119 defaultRoutes: {
18120 color: 'color'
18121 },
18122 descriptors: {
18123 _scriptable: true,
18124 _indexable: false
18125 }
18126 };
18127
18128 const map = new WeakMap();
18129 var plugin_subtitle = {
18130 id: 'subtitle',
18131 start (chart, _args, options) {
18132 const title = new Title({
18133 ctx: chart.ctx,
18134 options,
18135 chart
18136 });
18137 layouts.configure(chart, title, options);
18138 layouts.addBox(chart, title);
18139 map.set(chart, title);
18140 },
18141 stop (chart) {
18142 layouts.removeBox(chart, map.get(chart));
18143 map.delete(chart);
18144 },
18145 beforeUpdate (chart, _args, options) {
18146 const title = map.get(chart);
18147 layouts.configure(chart, title, options);
18148 title.options = options;
18149 },
18150 defaults: {
18151 align: 'center',
18152 display: false,
18153 font: {
18154 weight: 'normal'
18155 },
18156 fullSize: true,
18157 padding: 0,
18158 position: 'top',
18159 text: '',
18160 weight: 1500
18161 },
18162 defaultRoutes: {
18163 color: 'color'
18164 },
18165 descriptors: {
18166 _scriptable: true,
18167 _indexable: false
18168 }
18169 };
18170
18171 const positioners = {
18172 average (items) {
18173 if (!items.length) {
18174 return false;
18175 }
18176 let i, len;
18177 let xSet = new Set();
18178 let y = 0;
18179 let count = 0;
18180 for(i = 0, len = items.length; i < len; ++i){
18181 const el = items[i].element;
18182 if (el && el.hasValue()) {
18183 const pos = el.tooltipPosition();
18184 xSet.add(pos.x);
18185 y += pos.y;
18186 ++count;
18187 }
18188 }
18189 if (count === 0 || xSet.size === 0) {
18190 return false;
18191 }
18192 const xAverage = [
18193 ...xSet
18194 ].reduce((a, b)=>a + b) / xSet.size;
18195 return {
18196 x: xAverage,
18197 y: y / count
18198 };
18199 },
18200 nearest (items, eventPosition) {
18201 if (!items.length) {
18202 return false;
18203 }
18204 let x = eventPosition.x;
18205 let y = eventPosition.y;
18206 let minDistance = Number.POSITIVE_INFINITY;
18207 let i, len, nearestElement;
18208 for(i = 0, len = items.length; i < len; ++i){
18209 const el = items[i].element;
18210 if (el && el.hasValue()) {
18211 const center = el.getCenterPoint();
18212 const d = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aF)(eventPosition, center);
18213 if (d < minDistance) {
18214 minDistance = d;
18215 nearestElement = el;
18216 }
18217 }
18218 }
18219 if (nearestElement) {
18220 const tp = nearestElement.tooltipPosition();
18221 x = tp.x;
18222 y = tp.y;
18223 }
18224 return {
18225 x,
18226 y
18227 };
18228 }
18229 };
18230 function pushOrConcat(base, toPush) {
18231 if (toPush) {
18232 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(toPush)) {
18233 Array.prototype.push.apply(base, toPush);
18234 } else {
18235 base.push(toPush);
18236 }
18237 }
18238 return base;
18239 }
18240 function splitNewlines(str) {
18241 if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
18242 return str.split('\n');
18243 }
18244 return str;
18245 }
18246 function createTooltipItem(chart, item) {
18247 const { element , datasetIndex , index } = item;
18248 const controller = chart.getDatasetMeta(datasetIndex).controller;
18249 const { label , value } = controller.getLabelAndValue(index);
18250 return {
18251 chart,
18252 label,
18253 parsed: controller.getParsed(index),
18254 raw: chart.data.datasets[datasetIndex].data[index],
18255 formattedValue: value,
18256 dataset: controller.getDataset(),
18257 dataIndex: index,
18258 datasetIndex,
18259 element
18260 };
18261 }
18262 function getTooltipSize(tooltip, options) {
18263 const ctx = tooltip.chart.ctx;
18264 const { body , footer , title } = tooltip;
18265 const { boxWidth , boxHeight } = options;
18266 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18267 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18268 const footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18269 const titleLineCount = title.length;
18270 const footerLineCount = footer.length;
18271 const bodyLineItemCount = body.length;
18272 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18273 let height = padding.height;
18274 let width = 0;
18275 let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
18276 combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
18277 if (titleLineCount) {
18278 height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;
18279 }
18280 if (combinedBodyLength) {
18281 const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
18282 height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;
18283 }
18284 if (footerLineCount) {
18285 height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;
18286 }
18287 let widthPadding = 0;
18288 const maxLineWidth = function(line) {
18289 width = Math.max(width, ctx.measureText(line).width + widthPadding);
18290 };
18291 ctx.save();
18292 ctx.font = titleFont.string;
18293 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.title, maxLineWidth);
18294 ctx.font = bodyFont.string;
18295 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
18296 widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;
18297 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(body, (bodyItem)=>{
18298 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, maxLineWidth);
18299 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.lines, maxLineWidth);
18300 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, maxLineWidth);
18301 });
18302 widthPadding = 0;
18303 ctx.font = footerFont.string;
18304 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.footer, maxLineWidth);
18305 ctx.restore();
18306 width += padding.width;
18307 return {
18308 width,
18309 height
18310 };
18311 }
18312 function determineYAlign(chart, size) {
18313 const { y , height } = size;
18314 if (y < height / 2) {
18315 return 'top';
18316 } else if (y > chart.height - height / 2) {
18317 return 'bottom';
18318 }
18319 return 'center';
18320 }
18321 function doesNotFitWithAlign(xAlign, chart, options, size) {
18322 const { x , width } = size;
18323 const caret = options.caretSize + options.caretPadding;
18324 if (xAlign === 'left' && x + width + caret > chart.width) {
18325 return true;
18326 }
18327 if (xAlign === 'right' && x - width - caret < 0) {
18328 return true;
18329 }
18330 }
18331 function determineXAlign(chart, options, size, yAlign) {
18332 const { x , width } = size;
18333 const { width: chartWidth , chartArea: { left , right } } = chart;
18334 let xAlign = 'center';
18335 if (yAlign === 'center') {
18336 xAlign = x <= (left + right) / 2 ? 'left' : 'right';
18337 } else if (x <= width / 2) {
18338 xAlign = 'left';
18339 } else if (x >= chartWidth - width / 2) {
18340 xAlign = 'right';
18341 }
18342 if (doesNotFitWithAlign(xAlign, chart, options, size)) {
18343 xAlign = 'center';
18344 }
18345 return xAlign;
18346 }
18347 function determineAlignment(chart, options, size) {
18348 const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
18349 return {
18350 xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
18351 yAlign
18352 };
18353 }
18354 function alignX(size, xAlign) {
18355 let { x , width } = size;
18356 if (xAlign === 'right') {
18357 x -= width;
18358 } else if (xAlign === 'center') {
18359 x -= width / 2;
18360 }
18361 return x;
18362 }
18363 function alignY(size, yAlign, paddingAndSize) {
18364 let { y , height } = size;
18365 if (yAlign === 'top') {
18366 y += paddingAndSize;
18367 } else if (yAlign === 'bottom') {
18368 y -= height + paddingAndSize;
18369 } else {
18370 y -= height / 2;
18371 }
18372 return y;
18373 }
18374 function getBackgroundPoint(options, size, alignment, chart) {
18375 const { caretSize , caretPadding , cornerRadius } = options;
18376 const { xAlign , yAlign } = alignment;
18377 const paddingAndSize = caretSize + caretPadding;
18378 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18379 let x = alignX(size, xAlign);
18380 const y = alignY(size, yAlign, paddingAndSize);
18381 if (yAlign === 'center') {
18382 if (xAlign === 'left') {
18383 x += paddingAndSize;
18384 } else if (xAlign === 'right') {
18385 x -= paddingAndSize;
18386 }
18387 } else if (xAlign === 'left') {
18388 x -= Math.max(topLeft, bottomLeft) + caretSize;
18389 } else if (xAlign === 'right') {
18390 x += Math.max(topRight, bottomRight) + caretSize;
18391 }
18392 return {
18393 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(x, 0, chart.width - size.width),
18394 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(y, 0, chart.height - size.height)
18395 };
18396 }
18397 function getAlignedX(tooltip, align, options) {
18398 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18399 return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;
18400 }
18401 function getBeforeAfterBodyLines(callback) {
18402 return pushOrConcat([], splitNewlines(callback));
18403 }
18404 function createTooltipContext(parent, tooltip, tooltipItems) {
18405 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
18406 tooltip,
18407 tooltipItems,
18408 type: 'tooltip'
18409 });
18410 }
18411 function overrideCallbacks(callbacks, context) {
18412 const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
18413 return override ? callbacks.override(override) : callbacks;
18414 }
18415 const defaultCallbacks = {
18416 beforeTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18417 title (tooltipItems) {
18418 if (tooltipItems.length > 0) {
18419 const item = tooltipItems[0];
18420 const labels = item.chart.data.labels;
18421 const labelCount = labels ? labels.length : 0;
18422 if (this && this.options && this.options.mode === 'dataset') {
18423 return item.dataset.label || '';
18424 } else if (item.label) {
18425 return item.label;
18426 } else if (labelCount > 0 && item.dataIndex < labelCount) {
18427 return labels[item.dataIndex];
18428 }
18429 }
18430 return '';
18431 },
18432 afterTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18433 beforeBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18434 beforeLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18435 label (tooltipItem) {
18436 if (this && this.options && this.options.mode === 'dataset') {
18437 return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
18438 }
18439 let label = tooltipItem.dataset.label || '';
18440 if (label) {
18441 label += ': ';
18442 }
18443 const value = tooltipItem.formattedValue;
18444 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
18445 label += value;
18446 }
18447 return label;
18448 },
18449 labelColor (tooltipItem) {
18450 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18451 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18452 return {
18453 borderColor: options.borderColor,
18454 backgroundColor: options.backgroundColor,
18455 borderWidth: options.borderWidth,
18456 borderDash: options.borderDash,
18457 borderDashOffset: options.borderDashOffset,
18458 borderRadius: 0
18459 };
18460 },
18461 labelTextColor () {
18462 return this.options.bodyColor;
18463 },
18464 labelPointStyle (tooltipItem) {
18465 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18466 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18467 return {
18468 pointStyle: options.pointStyle,
18469 rotation: options.rotation
18470 };
18471 },
18472 afterLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18473 afterBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18474 beforeFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18475 footer: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18476 afterFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG
18477 };
18478 function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
18479 const result = callbacks[name].call(ctx, arg);
18480 if (typeof result === 'undefined') {
18481 return defaultCallbacks[name].call(ctx, arg);
18482 }
18483 return result;
18484 }
18485 class Tooltip extends Element {
18486 static positioners = positioners;
18487 constructor(config){
18488 super();
18489 this.opacity = 0;
18490 this._active = [];
18491 this._eventPosition = undefined;
18492 this._size = undefined;
18493 this._cachedAnimations = undefined;
18494 this._tooltipItems = [];
18495 this.$animations = undefined;
18496 this.$context = undefined;
18497 this.chart = config.chart;
18498 this.options = config.options;
18499 this.dataPoints = undefined;
18500 this.title = undefined;
18501 this.beforeBody = undefined;
18502 this.body = undefined;
18503 this.afterBody = undefined;
18504 this.footer = undefined;
18505 this.xAlign = undefined;
18506 this.yAlign = undefined;
18507 this.x = undefined;
18508 this.y = undefined;
18509 this.height = undefined;
18510 this.width = undefined;
18511 this.caretX = undefined;
18512 this.caretY = undefined;
18513 this.labelColors = undefined;
18514 this.labelPointStyles = undefined;
18515 this.labelTextColors = undefined;
18516 }
18517 initialize(options) {
18518 this.options = options;
18519 this._cachedAnimations = undefined;
18520 this.$context = undefined;
18521 }
18522 _resolveAnimations() {
18523 const cached = this._cachedAnimations;
18524 if (cached) {
18525 return cached;
18526 }
18527 const chart = this.chart;
18528 const options = this.options.setContext(this.getContext());
18529 const opts = options.enabled && chart.options.animation && options.animations;
18530 const animations = new Animations(this.chart, opts);
18531 if (opts._cacheable) {
18532 this._cachedAnimations = Object.freeze(animations);
18533 }
18534 return animations;
18535 }
18536 getContext() {
18537 return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
18538 }
18539 getTitle(context, options) {
18540 const { callbacks } = options;
18541 const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);
18542 const title = invokeCallbackWithFallback(callbacks, 'title', this, context);
18543 const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);
18544 let lines = [];
18545 lines = pushOrConcat(lines, splitNewlines(beforeTitle));
18546 lines = pushOrConcat(lines, splitNewlines(title));
18547 lines = pushOrConcat(lines, splitNewlines(afterTitle));
18548 return lines;
18549 }
18550 getBeforeBody(tooltipItems, options) {
18551 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems));
18552 }
18553 getBody(tooltipItems, options) {
18554 const { callbacks } = options;
18555 const bodyItems = [];
18556 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18557 const bodyItem = {
18558 before: [],
18559 lines: [],
18560 after: []
18561 };
18562 const scoped = overrideCallbacks(callbacks, context);
18563 pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));
18564 pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));
18565 pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));
18566 bodyItems.push(bodyItem);
18567 });
18568 return bodyItems;
18569 }
18570 getAfterBody(tooltipItems, options) {
18571 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems));
18572 }
18573 getFooter(tooltipItems, options) {
18574 const { callbacks } = options;
18575 const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);
18576 const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);
18577 const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);
18578 let lines = [];
18579 lines = pushOrConcat(lines, splitNewlines(beforeFooter));
18580 lines = pushOrConcat(lines, splitNewlines(footer));
18581 lines = pushOrConcat(lines, splitNewlines(afterFooter));
18582 return lines;
18583 }
18584 _createItems(options) {
18585 const active = this._active;
18586 const data = this.chart.data;
18587 const labelColors = [];
18588 const labelPointStyles = [];
18589 const labelTextColors = [];
18590 let tooltipItems = [];
18591 let i, len;
18592 for(i = 0, len = active.length; i < len; ++i){
18593 tooltipItems.push(createTooltipItem(this.chart, active[i]));
18594 }
18595 if (options.filter) {
18596 tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data));
18597 }
18598 if (options.itemSort) {
18599 tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data));
18600 }
18601 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18602 const scoped = overrideCallbacks(options.callbacks, context);
18603 labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));
18604 labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));
18605 labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));
18606 });
18607 this.labelColors = labelColors;
18608 this.labelPointStyles = labelPointStyles;
18609 this.labelTextColors = labelTextColors;
18610 this.dataPoints = tooltipItems;
18611 return tooltipItems;
18612 }
18613 update(changed, replay) {
18614 const options = this.options.setContext(this.getContext());
18615 const active = this._active;
18616 let properties;
18617 let tooltipItems = [];
18618 if (!active.length) {
18619 if (this.opacity !== 0) {
18620 properties = {
18621 opacity: 0
18622 };
18623 }
18624 } else {
18625 const position = positioners[options.position].call(this, active, this._eventPosition);
18626 tooltipItems = this._createItems(options);
18627 this.title = this.getTitle(tooltipItems, options);
18628 this.beforeBody = this.getBeforeBody(tooltipItems, options);
18629 this.body = this.getBody(tooltipItems, options);
18630 this.afterBody = this.getAfterBody(tooltipItems, options);
18631 this.footer = this.getFooter(tooltipItems, options);
18632 const size = this._size = getTooltipSize(this, options);
18633 const positionAndSize = Object.assign({}, position, size);
18634 const alignment = determineAlignment(this.chart, options, positionAndSize);
18635 const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
18636 this.xAlign = alignment.xAlign;
18637 this.yAlign = alignment.yAlign;
18638 properties = {
18639 opacity: 1,
18640 x: backgroundPoint.x,
18641 y: backgroundPoint.y,
18642 width: size.width,
18643 height: size.height,
18644 caretX: position.x,
18645 caretY: position.y
18646 };
18647 }
18648 this._tooltipItems = tooltipItems;
18649 this.$context = undefined;
18650 if (properties) {
18651 this._resolveAnimations().update(this, properties);
18652 }
18653 if (changed && options.external) {
18654 options.external.call(this, {
18655 chart: this.chart,
18656 tooltip: this,
18657 replay
18658 });
18659 }
18660 }
18661 drawCaret(tooltipPoint, ctx, size, options) {
18662 const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
18663 ctx.lineTo(caretPosition.x1, caretPosition.y1);
18664 ctx.lineTo(caretPosition.x2, caretPosition.y2);
18665 ctx.lineTo(caretPosition.x3, caretPosition.y3);
18666 }
18667 getCaretPosition(tooltipPoint, size, options) {
18668 const { xAlign , yAlign } = this;
18669 const { caretSize , cornerRadius } = options;
18670 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18671 const { x: ptX , y: ptY } = tooltipPoint;
18672 const { width , height } = size;
18673 let x1, x2, x3, y1, y2, y3;
18674 if (yAlign === 'center') {
18675 y2 = ptY + height / 2;
18676 if (xAlign === 'left') {
18677 x1 = ptX;
18678 x2 = x1 - caretSize;
18679 y1 = y2 + caretSize;
18680 y3 = y2 - caretSize;
18681 } else {
18682 x1 = ptX + width;
18683 x2 = x1 + caretSize;
18684 y1 = y2 - caretSize;
18685 y3 = y2 + caretSize;
18686 }
18687 x3 = x1;
18688 } else {
18689 if (xAlign === 'left') {
18690 x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;
18691 } else if (xAlign === 'right') {
18692 x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
18693 } else {
18694 x2 = this.caretX;
18695 }
18696 if (yAlign === 'top') {
18697 y1 = ptY;
18698 y2 = y1 - caretSize;
18699 x1 = x2 - caretSize;
18700 x3 = x2 + caretSize;
18701 } else {
18702 y1 = ptY + height;
18703 y2 = y1 + caretSize;
18704 x1 = x2 + caretSize;
18705 x3 = x2 - caretSize;
18706 }
18707 y3 = y1;
18708 }
18709 return {
18710 x1,
18711 x2,
18712 x3,
18713 y1,
18714 y2,
18715 y3
18716 };
18717 }
18718 drawTitle(pt, ctx, options) {
18719 const title = this.title;
18720 const length = title.length;
18721 let titleFont, titleSpacing, i;
18722 if (length) {
18723 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18724 pt.x = getAlignedX(this, options.titleAlign, options);
18725 ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
18726 ctx.textBaseline = 'middle';
18727 titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18728 titleSpacing = options.titleSpacing;
18729 ctx.fillStyle = options.titleColor;
18730 ctx.font = titleFont.string;
18731 for(i = 0; i < length; ++i){
18732 ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
18733 pt.y += titleFont.lineHeight + titleSpacing;
18734 if (i + 1 === length) {
18735 pt.y += options.titleMarginBottom - titleSpacing;
18736 }
18737 }
18738 }
18739 }
18740 _drawColorBox(ctx, pt, i, rtlHelper, options) {
18741 const labelColor = this.labelColors[i];
18742 const labelPointStyle = this.labelPointStyles[i];
18743 const { boxHeight , boxWidth } = options;
18744 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18745 const colorX = getAlignedX(this, 'left', options);
18746 const rtlColorX = rtlHelper.x(colorX);
18747 const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
18748 const colorY = pt.y + yOffSet;
18749 if (options.usePointStyle) {
18750 const drawOptions = {
18751 radius: Math.min(boxWidth, boxHeight) / 2,
18752 pointStyle: labelPointStyle.pointStyle,
18753 rotation: labelPointStyle.rotation,
18754 borderWidth: 1
18755 };
18756 const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
18757 const centerY = colorY + boxHeight / 2;
18758 ctx.strokeStyle = options.multiKeyBackground;
18759 ctx.fillStyle = options.multiKeyBackground;
18760 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18761 ctx.strokeStyle = labelColor.borderColor;
18762 ctx.fillStyle = labelColor.backgroundColor;
18763 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18764 } else {
18765 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;
18766 ctx.strokeStyle = labelColor.borderColor;
18767 ctx.setLineDash(labelColor.borderDash || []);
18768 ctx.lineDashOffset = labelColor.borderDashOffset || 0;
18769 const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);
18770 const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);
18771 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(labelColor.borderRadius);
18772 if (Object.values(borderRadius).some((v)=>v !== 0)) {
18773 ctx.beginPath();
18774 ctx.fillStyle = options.multiKeyBackground;
18775 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18776 x: outerX,
18777 y: colorY,
18778 w: boxWidth,
18779 h: boxHeight,
18780 radius: borderRadius
18781 });
18782 ctx.fill();
18783 ctx.stroke();
18784 ctx.fillStyle = labelColor.backgroundColor;
18785 ctx.beginPath();
18786 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18787 x: innerX,
18788 y: colorY + 1,
18789 w: boxWidth - 2,
18790 h: boxHeight - 2,
18791 radius: borderRadius
18792 });
18793 ctx.fill();
18794 } else {
18795 ctx.fillStyle = options.multiKeyBackground;
18796 ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
18797 ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
18798 ctx.fillStyle = labelColor.backgroundColor;
18799 ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
18800 }
18801 }
18802 ctx.fillStyle = this.labelTextColors[i];
18803 }
18804 drawBody(pt, ctx, options) {
18805 const { body } = this;
18806 const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options;
18807 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18808 let bodyLineHeight = bodyFont.lineHeight;
18809 let xLinePadding = 0;
18810 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18811 const fillLineOfText = function(line) {
18812 ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
18813 pt.y += bodyLineHeight + bodySpacing;
18814 };
18815 const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
18816 let bodyItem, textColor, lines, i, j, ilen, jlen;
18817 ctx.textAlign = bodyAlign;
18818 ctx.textBaseline = 'middle';
18819 ctx.font = bodyFont.string;
18820 pt.x = getAlignedX(this, bodyAlignForCalculation, options);
18821 ctx.fillStyle = options.bodyColor;
18822 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.beforeBody, fillLineOfText);
18823 xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;
18824 for(i = 0, ilen = body.length; i < ilen; ++i){
18825 bodyItem = body[i];
18826 textColor = this.labelTextColors[i];
18827 ctx.fillStyle = textColor;
18828 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, fillLineOfText);
18829 lines = bodyItem.lines;
18830 if (displayColors && lines.length) {
18831 this._drawColorBox(ctx, pt, i, rtlHelper, options);
18832 bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
18833 }
18834 for(j = 0, jlen = lines.length; j < jlen; ++j){
18835 fillLineOfText(lines[j]);
18836 bodyLineHeight = bodyFont.lineHeight;
18837 }
18838 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, fillLineOfText);
18839 }
18840 xLinePadding = 0;
18841 bodyLineHeight = bodyFont.lineHeight;
18842 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.afterBody, fillLineOfText);
18843 pt.y -= bodySpacing;
18844 }
18845 drawFooter(pt, ctx, options) {
18846 const footer = this.footer;
18847 const length = footer.length;
18848 let footerFont, i;
18849 if (length) {
18850 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18851 pt.x = getAlignedX(this, options.footerAlign, options);
18852 pt.y += options.footerMarginTop;
18853 ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
18854 ctx.textBaseline = 'middle';
18855 footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18856 ctx.fillStyle = options.footerColor;
18857 ctx.font = footerFont.string;
18858 for(i = 0; i < length; ++i){
18859 ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
18860 pt.y += footerFont.lineHeight + options.footerSpacing;
18861 }
18862 }
18863 }
18864 drawBackground(pt, ctx, tooltipSize, options) {
18865 const { xAlign , yAlign } = this;
18866 const { x , y } = pt;
18867 const { width , height } = tooltipSize;
18868 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(options.cornerRadius);
18869 ctx.fillStyle = options.backgroundColor;
18870 ctx.strokeStyle = options.borderColor;
18871 ctx.lineWidth = options.borderWidth;
18872 ctx.beginPath();
18873 ctx.moveTo(x + topLeft, y);
18874 if (yAlign === 'top') {
18875 this.drawCaret(pt, ctx, tooltipSize, options);
18876 }
18877 ctx.lineTo(x + width - topRight, y);
18878 ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
18879 if (yAlign === 'center' && xAlign === 'right') {
18880 this.drawCaret(pt, ctx, tooltipSize, options);
18881 }
18882 ctx.lineTo(x + width, y + height - bottomRight);
18883 ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
18884 if (yAlign === 'bottom') {
18885 this.drawCaret(pt, ctx, tooltipSize, options);
18886 }
18887 ctx.lineTo(x + bottomLeft, y + height);
18888 ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
18889 if (yAlign === 'center' && xAlign === 'left') {
18890 this.drawCaret(pt, ctx, tooltipSize, options);
18891 }
18892 ctx.lineTo(x, y + topLeft);
18893 ctx.quadraticCurveTo(x, y, x + topLeft, y);
18894 ctx.closePath();
18895 ctx.fill();
18896 if (options.borderWidth > 0) {
18897 ctx.stroke();
18898 }
18899 }
18900 _updateAnimationTarget(options) {
18901 const chart = this.chart;
18902 const anims = this.$animations;
18903 const animX = anims && anims.x;
18904 const animY = anims && anims.y;
18905 if (animX || animY) {
18906 const position = positioners[options.position].call(this, this._active, this._eventPosition);
18907 if (!position) {
18908 return;
18909 }
18910 const size = this._size = getTooltipSize(this, options);
18911 const positionAndSize = Object.assign({}, position, this._size);
18912 const alignment = determineAlignment(chart, options, positionAndSize);
18913 const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
18914 if (animX._to !== point.x || animY._to !== point.y) {
18915 this.xAlign = alignment.xAlign;
18916 this.yAlign = alignment.yAlign;
18917 this.width = size.width;
18918 this.height = size.height;
18919 this.caretX = position.x;
18920 this.caretY = position.y;
18921 this._resolveAnimations().update(this, point);
18922 }
18923 }
18924 }
18925 _willRender() {
18926 return !!this.opacity;
18927 }
18928 draw(ctx) {
18929 const options = this.options.setContext(this.getContext());
18930 let opacity = this.opacity;
18931 if (!opacity) {
18932 return;
18933 }
18934 this._updateAnimationTarget(options);
18935 const tooltipSize = {
18936 width: this.width,
18937 height: this.height
18938 };
18939 const pt = {
18940 x: this.x,
18941 y: this.y
18942 };
18943 opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
18944 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18945 const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
18946 if (options.enabled && hasTooltipContent) {
18947 ctx.save();
18948 ctx.globalAlpha = opacity;
18949 this.drawBackground(pt, ctx, tooltipSize, options);
18950 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(ctx, options.textDirection);
18951 pt.y += padding.top;
18952 this.drawTitle(pt, ctx, options);
18953 this.drawBody(pt, ctx, options);
18954 this.drawFooter(pt, ctx, options);
18955 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(ctx, options.textDirection);
18956 ctx.restore();
18957 }
18958 }
18959 getActiveElements() {
18960 return this._active || [];
18961 }
18962 setActiveElements(activeElements, eventPosition) {
18963 const lastActive = this._active;
18964 const active = activeElements.map(({ datasetIndex , index })=>{
18965 const meta = this.chart.getDatasetMeta(datasetIndex);
18966 if (!meta) {
18967 throw new Error('Cannot find a dataset at index ' + datasetIndex);
18968 }
18969 return {
18970 datasetIndex,
18971 element: meta.data[index],
18972 index
18973 };
18974 });
18975 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(lastActive, active);
18976 const positionChanged = this._positionChanged(active, eventPosition);
18977 if (changed || positionChanged) {
18978 this._active = active;
18979 this._eventPosition = eventPosition;
18980 this._ignoreReplayEvents = true;
18981 this.update(true);
18982 }
18983 }
18984 handleEvent(e, replay, inChartArea = true) {
18985 if (replay && this._ignoreReplayEvents) {
18986 return false;
18987 }
18988 this._ignoreReplayEvents = false;
18989 const options = this.options;
18990 const lastActive = this._active || [];
18991 const active = this._getActiveElements(e, lastActive, replay, inChartArea);
18992 const positionChanged = this._positionChanged(active, e);
18993 const changed = replay || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive) || positionChanged;
18994 if (changed) {
18995 this._active = active;
18996 if (options.enabled || options.external) {
18997 this._eventPosition = {
18998 x: e.x,
18999 y: e.y
19000 };
19001 this.update(true, replay);
19002 }
19003 }
19004 return changed;
19005 }
19006 _getActiveElements(e, lastActive, replay, inChartArea) {
19007 const options = this.options;
19008 if (e.type === 'mouseout') {
19009 return [];
19010 }
19011 if (!inChartArea) {
19012 return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined);
19013 }
19014 const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
19015 if (options.reverse) {
19016 active.reverse();
19017 }
19018 return active;
19019 }
19020 _positionChanged(active, e) {
19021 const { caretX , caretY , options } = this;
19022 const position = positioners[options.position].call(this, active, e);
19023 return position !== false && (caretX !== position.x || caretY !== position.y);
19024 }
19025 }
19026 var plugin_tooltip = {
19027 id: 'tooltip',
19028 _element: Tooltip,
19029 positioners,
19030 afterInit (chart, _args, options) {
19031 if (options) {
19032 chart.tooltip = new Tooltip({
19033 chart,
19034 options
19035 });
19036 }
19037 },
19038 beforeUpdate (chart, _args, options) {
19039 if (chart.tooltip) {
19040 chart.tooltip.initialize(options);
19041 }
19042 },
19043 reset (chart, _args, options) {
19044 if (chart.tooltip) {
19045 chart.tooltip.initialize(options);
19046 }
19047 },
19048 afterDraw (chart) {
19049 const tooltip = chart.tooltip;
19050 if (tooltip && tooltip._willRender()) {
19051 const args = {
19052 tooltip
19053 };
19054 if (chart.notifyPlugins('beforeTooltipDraw', {
19055 ...args,
19056 cancelable: true
19057 }) === false) {
19058 return;
19059 }
19060 tooltip.draw(chart.ctx);
19061 chart.notifyPlugins('afterTooltipDraw', args);
19062 }
19063 },
19064 afterEvent (chart, args) {
19065 if (chart.tooltip) {
19066 const useFinalPosition = args.replay;
19067 if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
19068 args.changed = true;
19069 }
19070 }
19071 },
19072 defaults: {
19073 enabled: true,
19074 external: null,
19075 position: 'average',
19076 backgroundColor: 'rgba(0,0,0,0.8)',
19077 titleColor: '#fff',
19078 titleFont: {
19079 weight: 'bold'
19080 },
19081 titleSpacing: 2,
19082 titleMarginBottom: 6,
19083 titleAlign: 'left',
19084 bodyColor: '#fff',
19085 bodySpacing: 2,
19086 bodyFont: {},
19087 bodyAlign: 'left',
19088 footerColor: '#fff',
19089 footerSpacing: 2,
19090 footerMarginTop: 6,
19091 footerFont: {
19092 weight: 'bold'
19093 },
19094 footerAlign: 'left',
19095 padding: 6,
19096 caretPadding: 2,
19097 caretSize: 5,
19098 cornerRadius: 6,
19099 boxHeight: (ctx, opts)=>opts.bodyFont.size,
19100 boxWidth: (ctx, opts)=>opts.bodyFont.size,
19101 multiKeyBackground: '#fff',
19102 displayColors: true,
19103 boxPadding: 0,
19104 borderColor: 'rgba(0,0,0,0)',
19105 borderWidth: 0,
19106 animation: {
19107 duration: 400,
19108 easing: 'easeOutQuart'
19109 },
19110 animations: {
19111 numbers: {
19112 type: 'number',
19113 properties: [
19114 'x',
19115 'y',
19116 'width',
19117 'height',
19118 'caretX',
19119 'caretY'
19120 ]
19121 },
19122 opacity: {
19123 easing: 'linear',
19124 duration: 200
19125 }
19126 },
19127 callbacks: defaultCallbacks
19128 },
19129 defaultRoutes: {
19130 bodyFont: 'font',
19131 footerFont: 'font',
19132 titleFont: 'font'
19133 },
19134 descriptors: {
19135 _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external',
19136 _indexable: false,
19137 callbacks: {
19138 _scriptable: false,
19139 _indexable: false
19140 },
19141 animation: {
19142 _fallback: false
19143 },
19144 animations: {
19145 _fallback: 'animation'
19146 }
19147 },
19148 additionalOptionScopes: [
19149 'interaction'
19150 ]
19151 };
19152
19153 var plugins = /*#__PURE__*/Object.freeze({
19154 __proto__: null,
19155 Colors: plugin_colors,
19156 Decimation: plugin_decimation,
19157 Filler: index,
19158 Legend: plugin_legend,
19159 SubTitle: plugin_subtitle,
19160 Title: plugin_title,
19161 Tooltip: plugin_tooltip
19162 });
19163
19164 const addIfString = (labels, raw, index, addedLabels)=>{
19165 if (typeof raw === 'string') {
19166 index = labels.push(raw) - 1;
19167 addedLabels.unshift({
19168 index,
19169 label: raw
19170 });
19171 } else if (isNaN(raw)) {
19172 index = null;
19173 }
19174 return index;
19175 };
19176 function findOrAddLabel(labels, raw, index, addedLabels) {
19177 const first = labels.indexOf(raw);
19178 if (first === -1) {
19179 return addIfString(labels, raw, index, addedLabels);
19180 }
19181 const last = labels.lastIndexOf(raw);
19182 return first !== last ? index : first;
19183 }
19184 const validIndex = (index, max)=>index === null ? null : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(Math.round(index), 0, max);
19185 function _getLabelForValue(value) {
19186 const labels = this.getLabels();
19187 if (value >= 0 && value < labels.length) {
19188 return labels[value];
19189 }
19190 return value;
19191 }
19192 class CategoryScale extends Scale {
19193 static id = 'category';
19194 static defaults = {
19195 ticks: {
19196 callback: _getLabelForValue
19197 }
19198 };
19199 constructor(cfg){
19200 super(cfg);
19201 this._startValue = undefined;
19202 this._valueRange = 0;
19203 this._addedLabels = [];
19204 }
19205 init(scaleOptions) {
19206 const added = this._addedLabels;
19207 if (added.length) {
19208 const labels = this.getLabels();
19209 for (const { index , label } of added){
19210 if (labels[index] === label) {
19211 labels.splice(index, 1);
19212 }
19213 }
19214 this._addedLabels = [];
19215 }
19216 super.init(scaleOptions);
19217 }
19218 parse(raw, index) {
19219 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19220 return null;
19221 }
19222 const labels = this.getLabels();
19223 index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(index, raw), this._addedLabels);
19224 return validIndex(index, labels.length - 1);
19225 }
19226 determineDataLimits() {
19227 const { minDefined , maxDefined } = this.getUserBounds();
19228 let { min , max } = this.getMinMax(true);
19229 if (this.options.bounds === 'ticks') {
19230 if (!minDefined) {
19231 min = 0;
19232 }
19233 if (!maxDefined) {
19234 max = this.getLabels().length - 1;
19235 }
19236 }
19237 this.min = min;
19238 this.max = max;
19239 }
19240 buildTicks() {
19241 const min = this.min;
19242 const max = this.max;
19243 const offset = this.options.offset;
19244 const ticks = [];
19245 let labels = this.getLabels();
19246 labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);
19247 this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
19248 this._startValue = this.min - (offset ? 0.5 : 0);
19249 for(let value = min; value <= max; value++){
19250 ticks.push({
19251 value
19252 });
19253 }
19254 return ticks;
19255 }
19256 getLabelForValue(value) {
19257 return _getLabelForValue.call(this, value);
19258 }
19259 configure() {
19260 super.configure();
19261 if (!this.isHorizontal()) {
19262 this._reversePixels = !this._reversePixels;
19263 }
19264 }
19265 getPixelForValue(value) {
19266 if (typeof value !== 'number') {
19267 value = this.parse(value);
19268 }
19269 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19270 }
19271 getPixelForTick(index) {
19272 const ticks = this.ticks;
19273 if (index < 0 || index > ticks.length - 1) {
19274 return null;
19275 }
19276 return this.getPixelForValue(ticks[index].value);
19277 }
19278 getValueForPixel(pixel) {
19279 return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
19280 }
19281 getBasePixel() {
19282 return this.bottom;
19283 }
19284 }
19285
19286 function generateTicks$1(generationOptions, dataRange) {
19287 const ticks = [];
19288 const MIN_SPACING = 1e-14;
19289 const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions;
19290 const unit = step || 1;
19291 const maxSpaces = maxTicks - 1;
19292 const { min: rmin , max: rmax } = dataRange;
19293 const minDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(min);
19294 const maxDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(max);
19295 const countDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(count);
19296 const minSpacing = (rmax - rmin) / (maxDigits + 1);
19297 let spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)((rmax - rmin) / maxSpaces / unit) * unit;
19298 let factor, niceMin, niceMax, numSpaces;
19299 if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
19300 return [
19301 {
19302 value: rmin
19303 },
19304 {
19305 value: rmax
19306 }
19307 ];
19308 }
19309 numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
19310 if (numSpaces > maxSpaces) {
19311 spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)(numSpaces * spacing / maxSpaces / unit) * unit;
19312 }
19313 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision)) {
19314 factor = Math.pow(10, precision);
19315 spacing = Math.ceil(spacing * factor) / factor;
19316 }
19317 if (bounds === 'ticks') {
19318 niceMin = Math.floor(rmin / spacing) * spacing;
19319 niceMax = Math.ceil(rmax / spacing) * spacing;
19320 } else {
19321 niceMin = rmin;
19322 niceMax = rmax;
19323 }
19324 if (minDefined && maxDefined && step && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aJ)((max - min) / step, spacing / 1000)) {
19325 numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
19326 spacing = (max - min) / numSpaces;
19327 niceMin = min;
19328 niceMax = max;
19329 } else if (countDefined) {
19330 niceMin = minDefined ? min : niceMin;
19331 niceMax = maxDefined ? max : niceMax;
19332 numSpaces = count - 1;
19333 spacing = (niceMax - niceMin) / numSpaces;
19334 } else {
19335 numSpaces = (niceMax - niceMin) / spacing;
19336 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(numSpaces, Math.round(numSpaces), spacing / 1000)) {
19337 numSpaces = Math.round(numSpaces);
19338 } else {
19339 numSpaces = Math.ceil(numSpaces);
19340 }
19341 }
19342 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));
19343 factor = Math.pow(10, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision) ? decimalPlaces : precision);
19344 niceMin = Math.round(niceMin * factor) / factor;
19345 niceMax = Math.round(niceMax * factor) / factor;
19346 let j = 0;
19347 if (minDefined) {
19348 if (includeBounds && niceMin !== min) {
19349 ticks.push({
19350 value: min
19351 });
19352 if (niceMin < min) {
19353 j++;
19354 }
19355 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
19356 j++;
19357 }
19358 } else if (niceMin < min) {
19359 j++;
19360 }
19361 }
19362 for(; j < numSpaces; ++j){
19363 const tickValue = Math.round((niceMin + j * spacing) * factor) / factor;
19364 if (maxDefined && tickValue > max) {
19365 break;
19366 }
19367 ticks.push({
19368 value: tickValue
19369 });
19370 }
19371 if (maxDefined && includeBounds && niceMax !== max) {
19372 if (ticks.length && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
19373 ticks[ticks.length - 1].value = max;
19374 } else {
19375 ticks.push({
19376 value: max
19377 });
19378 }
19379 } else if (!maxDefined || niceMax === max) {
19380 ticks.push({
19381 value: niceMax
19382 });
19383 }
19384 return ticks;
19385 }
19386 function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) {
19387 const rad = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(minRotation);
19388 const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;
19389 const length = 0.75 * minSpacing * ('' + value).length;
19390 return Math.min(minSpacing / ratio, length);
19391 }
19392 class LinearScaleBase extends Scale {
19393 constructor(cfg){
19394 super(cfg);
19395 this.start = undefined;
19396 this.end = undefined;
19397 this._startValue = undefined;
19398 this._endValue = undefined;
19399 this._valueRange = 0;
19400 }
19401 parse(raw, index) {
19402 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19403 return null;
19404 }
19405 if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
19406 return null;
19407 }
19408 return +raw;
19409 }
19410 handleTickRangeOptions() {
19411 const { beginAtZero } = this.options;
19412 const { minDefined , maxDefined } = this.getUserBounds();
19413 let { min , max } = this;
19414 const setMin = (v)=>min = minDefined ? min : v;
19415 const setMax = (v)=>max = maxDefined ? max : v;
19416 if (beginAtZero) {
19417 const minSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(min);
19418 const maxSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(max);
19419 if (minSign < 0 && maxSign < 0) {
19420 setMax(0);
19421 } else if (minSign > 0 && maxSign > 0) {
19422 setMin(0);
19423 }
19424 }
19425 if (min === max) {
19426 let offset = max === 0 ? 1 : Math.abs(max * 0.05);
19427 setMax(max + offset);
19428 if (!beginAtZero) {
19429 setMin(min - offset);
19430 }
19431 }
19432 this.min = min;
19433 this.max = max;
19434 }
19435 getTickLimit() {
19436 const tickOpts = this.options.ticks;
19437 let { maxTicksLimit , stepSize } = tickOpts;
19438 let maxTicks;
19439 if (stepSize) {
19440 maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
19441 if (maxTicks > 1000) {
19442 console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
19443 maxTicks = 1000;
19444 }
19445 } else {
19446 maxTicks = this.computeTickLimit();
19447 maxTicksLimit = maxTicksLimit || 11;
19448 }
19449 if (maxTicksLimit) {
19450 maxTicks = Math.min(maxTicksLimit, maxTicks);
19451 }
19452 return maxTicks;
19453 }
19454 computeTickLimit() {
19455 return Number.POSITIVE_INFINITY;
19456 }
19457 buildTicks() {
19458 const opts = this.options;
19459 const tickOpts = opts.ticks;
19460 let maxTicks = this.getTickLimit();
19461 maxTicks = Math.max(2, maxTicks);
19462 const numericGeneratorOptions = {
19463 maxTicks,
19464 bounds: opts.bounds,
19465 min: opts.min,
19466 max: opts.max,
19467 precision: tickOpts.precision,
19468 step: tickOpts.stepSize,
19469 count: tickOpts.count,
19470 maxDigits: this._maxDigits(),
19471 horizontal: this.isHorizontal(),
19472 minRotation: tickOpts.minRotation || 0,
19473 includeBounds: tickOpts.includeBounds !== false
19474 };
19475 const dataRange = this._range || this;
19476 const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
19477 if (opts.bounds === 'ticks') {
19478 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19479 }
19480 if (opts.reverse) {
19481 ticks.reverse();
19482 this.start = this.max;
19483 this.end = this.min;
19484 } else {
19485 this.start = this.min;
19486 this.end = this.max;
19487 }
19488 return ticks;
19489 }
19490 configure() {
19491 const ticks = this.ticks;
19492 let start = this.min;
19493 let end = this.max;
19494 super.configure();
19495 if (this.options.offset && ticks.length) {
19496 const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
19497 start -= offset;
19498 end += offset;
19499 }
19500 this._startValue = start;
19501 this._endValue = end;
19502 this._valueRange = end - start;
19503 }
19504 getLabelForValue(value) {
19505 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19506 }
19507 }
19508
19509 class LinearScale extends LinearScaleBase {
19510 static id = 'linear';
19511 static defaults = {
19512 ticks: {
19513 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19514 }
19515 };
19516 determineDataLimits() {
19517 const { min , max } = this.getMinMax(true);
19518 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? min : 0;
19519 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? max : 1;
19520 this.handleTickRangeOptions();
19521 }
19522 computeTickLimit() {
19523 const horizontal = this.isHorizontal();
19524 const length = horizontal ? this.width : this.height;
19525 const minRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.ticks.minRotation);
19526 const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;
19527 const tickFont = this._resolveTickFontOptions(0);
19528 return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
19529 }
19530 getPixelForValue(value) {
19531 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19532 }
19533 getValueForPixel(pixel) {
19534 return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
19535 }
19536 }
19537
19538 const log10Floor = (v)=>Math.floor((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(v));
19539 const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m);
19540 function isMajor(tickVal) {
19541 const remain = tickVal / Math.pow(10, log10Floor(tickVal));
19542 return remain === 1;
19543 }
19544 function steps(min, max, rangeExp) {
19545 const rangeStep = Math.pow(10, rangeExp);
19546 const start = Math.floor(min / rangeStep);
19547 const end = Math.ceil(max / rangeStep);
19548 return end - start;
19549 }
19550 function startExp(min, max) {
19551 const range = max - min;
19552 let rangeExp = log10Floor(range);
19553 while(steps(min, max, rangeExp) > 10){
19554 rangeExp++;
19555 }
19556 while(steps(min, max, rangeExp) < 10){
19557 rangeExp--;
19558 }
19559 return Math.min(rangeExp, log10Floor(min));
19560 }
19561 function generateTicks(generationOptions, { min , max }) {
19562 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, min);
19563 const ticks = [];
19564 const minExp = log10Floor(min);
19565 let exp = startExp(min, max);
19566 let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
19567 const stepSize = Math.pow(10, exp);
19568 const base = minExp > exp ? Math.pow(10, minExp) : 0;
19569 const start = Math.round((min - base) * precision) / precision;
19570 const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;
19571 let significand = Math.floor((start - offset) / Math.pow(10, exp));
19572 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);
19573 while(value < max){
19574 ticks.push({
19575 value,
19576 major: isMajor(value),
19577 significand
19578 });
19579 if (significand >= 10) {
19580 significand = significand < 15 ? 15 : 20;
19581 } else {
19582 significand++;
19583 }
19584 if (significand >= 20) {
19585 exp++;
19586 significand = 2;
19587 precision = exp >= 0 ? 1 : precision;
19588 }
19589 value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;
19590 }
19591 const lastTick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.max, value);
19592 ticks.push({
19593 value: lastTick,
19594 major: isMajor(lastTick),
19595 significand
19596 });
19597 return ticks;
19598 }
19599 class LogarithmicScale extends Scale {
19600 static id = 'logarithmic';
19601 static defaults = {
19602 ticks: {
19603 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.logarithmic,
19604 major: {
19605 enabled: true
19606 }
19607 }
19608 };
19609 constructor(cfg){
19610 super(cfg);
19611 this.start = undefined;
19612 this.end = undefined;
19613 this._startValue = undefined;
19614 this._valueRange = 0;
19615 }
19616 parse(raw, index) {
19617 const value = LinearScaleBase.prototype.parse.apply(this, [
19618 raw,
19619 index
19620 ]);
19621 if (value === 0) {
19622 this._zero = true;
19623 return undefined;
19624 }
19625 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value) && value > 0 ? value : null;
19626 }
19627 determineDataLimits() {
19628 const { min , max } = this.getMinMax(true);
19629 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? Math.max(0, min) : null;
19630 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? Math.max(0, max) : null;
19631 if (this.options.beginAtZero) {
19632 this._zero = true;
19633 }
19634 if (this._zero && this.min !== this._suggestedMin && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(this._userMin)) {
19635 this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);
19636 }
19637 this.handleTickRangeOptions();
19638 }
19639 handleTickRangeOptions() {
19640 const { minDefined , maxDefined } = this.getUserBounds();
19641 let min = this.min;
19642 let max = this.max;
19643 const setMin = (v)=>min = minDefined ? min : v;
19644 const setMax = (v)=>max = maxDefined ? max : v;
19645 if (min === max) {
19646 if (min <= 0) {
19647 setMin(1);
19648 setMax(10);
19649 } else {
19650 setMin(changeExponent(min, -1));
19651 setMax(changeExponent(max, +1));
19652 }
19653 }
19654 if (min <= 0) {
19655 setMin(changeExponent(max, -1));
19656 }
19657 if (max <= 0) {
19658 setMax(changeExponent(min, +1));
19659 }
19660 this.min = min;
19661 this.max = max;
19662 }
19663 buildTicks() {
19664 const opts = this.options;
19665 const generationOptions = {
19666 min: this._userMin,
19667 max: this._userMax
19668 };
19669 const ticks = generateTicks(generationOptions, this);
19670 if (opts.bounds === 'ticks') {
19671 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19672 }
19673 if (opts.reverse) {
19674 ticks.reverse();
19675 this.start = this.max;
19676 this.end = this.min;
19677 } else {
19678 this.start = this.min;
19679 this.end = this.max;
19680 }
19681 return ticks;
19682 }
19683 getLabelForValue(value) {
19684 return value === undefined ? '0' : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19685 }
19686 configure() {
19687 const start = this.min;
19688 super.configure();
19689 this._startValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start);
19690 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);
19691 }
19692 getPixelForValue(value) {
19693 if (value === undefined || value === 0) {
19694 value = this.min;
19695 }
19696 if (value === null || isNaN(value)) {
19697 return NaN;
19698 }
19699 return this.getPixelForDecimal(value === this.min ? 0 : ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(value) - this._startValue) / this._valueRange);
19700 }
19701 getValueForPixel(pixel) {
19702 const decimal = this.getDecimalForPixel(pixel);
19703 return Math.pow(10, this._startValue + decimal * this._valueRange);
19704 }
19705 }
19706
19707 function getTickBackdropHeight(opts) {
19708 const tickOpts = opts.ticks;
19709 if (tickOpts.display && opts.display) {
19710 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(tickOpts.backdropPadding);
19711 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;
19712 }
19713 return 0;
19714 }
19715 function measureLabelSize(ctx, font, label) {
19716 label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label : [
19717 label
19718 ];
19719 return {
19720 w: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aO)(ctx, font.string, label),
19721 h: label.length * font.lineHeight
19722 };
19723 }
19724 function determineLimits(angle, pos, size, min, max) {
19725 if (angle === min || angle === max) {
19726 return {
19727 start: pos - size / 2,
19728 end: pos + size / 2
19729 };
19730 } else if (angle < min || angle > max) {
19731 return {
19732 start: pos - size,
19733 end: pos
19734 };
19735 }
19736 return {
19737 start: pos,
19738 end: pos + size
19739 };
19740 }
19741 function fitWithPointLabels(scale) {
19742 const orig = {
19743 l: scale.left + scale._padding.left,
19744 r: scale.right - scale._padding.right,
19745 t: scale.top + scale._padding.top,
19746 b: scale.bottom - scale._padding.bottom
19747 };
19748 const limits = Object.assign({}, orig);
19749 const labelSizes = [];
19750 const padding = [];
19751 const valueCount = scale._pointLabels.length;
19752 const pointLabelOpts = scale.options.pointLabels;
19753 const additionalAngle = pointLabelOpts.centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0;
19754 for(let i = 0; i < valueCount; i++){
19755 const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
19756 padding[i] = opts.padding;
19757 const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
19758 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
19759 const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
19760 labelSizes[i] = textSize;
19761 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(scale.getIndexAngle(i) + additionalAngle);
19762 const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(angleRadians));
19763 const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
19764 const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
19765 updateLimits(limits, orig, angleRadians, hLimits, vLimits);
19766 }
19767 scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);
19768 scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
19769 }
19770 function updateLimits(limits, orig, angle, hLimits, vLimits) {
19771 const sin = Math.abs(Math.sin(angle));
19772 const cos = Math.abs(Math.cos(angle));
19773 let x = 0;
19774 let y = 0;
19775 if (hLimits.start < orig.l) {
19776 x = (orig.l - hLimits.start) / sin;
19777 limits.l = Math.min(limits.l, orig.l - x);
19778 } else if (hLimits.end > orig.r) {
19779 x = (hLimits.end - orig.r) / sin;
19780 limits.r = Math.max(limits.r, orig.r + x);
19781 }
19782 if (vLimits.start < orig.t) {
19783 y = (orig.t - vLimits.start) / cos;
19784 limits.t = Math.min(limits.t, orig.t - y);
19785 } else if (vLimits.end > orig.b) {
19786 y = (vLimits.end - orig.b) / cos;
19787 limits.b = Math.max(limits.b, orig.b + y);
19788 }
19789 }
19790 function createPointLabelItem(scale, index, itemOpts) {
19791 const outerDistance = scale.drawingArea;
19792 const { extra , additionalAngle , padding , size } = itemOpts;
19793 const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);
19794 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)));
19795 const y = yForAngle(pointLabelPosition.y, size.h, angle);
19796 const textAlign = getTextAlignForAngle(angle);
19797 const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
19798 return {
19799 visible: true,
19800 x: pointLabelPosition.x,
19801 y,
19802 textAlign,
19803 left,
19804 top: y,
19805 right: left + size.w,
19806 bottom: y + size.h
19807 };
19808 }
19809 function isNotOverlapped(item, area) {
19810 if (!area) {
19811 return true;
19812 }
19813 const { left , top , right , bottom } = item;
19814 const apexesInArea = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19815 x: left,
19816 y: top
19817 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19818 x: left,
19819 y: bottom
19820 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19821 x: right,
19822 y: top
19823 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19824 x: right,
19825 y: bottom
19826 }, area);
19827 return !apexesInArea;
19828 }
19829 function buildPointLabelItems(scale, labelSizes, padding) {
19830 const items = [];
19831 const valueCount = scale._pointLabels.length;
19832 const opts = scale.options;
19833 const { centerPointLabels , display } = opts.pointLabels;
19834 const itemOpts = {
19835 extra: getTickBackdropHeight(opts) / 2,
19836 additionalAngle: centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0
19837 };
19838 let area;
19839 for(let i = 0; i < valueCount; i++){
19840 itemOpts.padding = padding[i];
19841 itemOpts.size = labelSizes[i];
19842 const item = createPointLabelItem(scale, i, itemOpts);
19843 items.push(item);
19844 if (display === 'auto') {
19845 item.visible = isNotOverlapped(item, area);
19846 if (item.visible) {
19847 area = item;
19848 }
19849 }
19850 }
19851 return items;
19852 }
19853 function getTextAlignForAngle(angle) {
19854 if (angle === 0 || angle === 180) {
19855 return 'center';
19856 } else if (angle < 180) {
19857 return 'left';
19858 }
19859 return 'right';
19860 }
19861 function leftForTextAlign(x, w, align) {
19862 if (align === 'right') {
19863 x -= w;
19864 } else if (align === 'center') {
19865 x -= w / 2;
19866 }
19867 return x;
19868 }
19869 function yForAngle(y, h, angle) {
19870 if (angle === 90 || angle === 270) {
19871 y -= h / 2;
19872 } else if (angle > 270 || angle < 90) {
19873 y -= h;
19874 }
19875 return y;
19876 }
19877 function drawPointLabelBox(ctx, opts, item) {
19878 const { left , top , right , bottom } = item;
19879 const { backdropColor } = opts;
19880 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(backdropColor)) {
19881 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(opts.borderRadius);
19882 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.backdropPadding);
19883 ctx.fillStyle = backdropColor;
19884 const backdropLeft = left - padding.left;
19885 const backdropTop = top - padding.top;
19886 const backdropWidth = right - left + padding.width;
19887 const backdropHeight = bottom - top + padding.height;
19888 if (Object.values(borderRadius).some((v)=>v !== 0)) {
19889 ctx.beginPath();
19890 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
19891 x: backdropLeft,
19892 y: backdropTop,
19893 w: backdropWidth,
19894 h: backdropHeight,
19895 radius: borderRadius
19896 });
19897 ctx.fill();
19898 } else {
19899 ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);
19900 }
19901 }
19902 }
19903 function drawPointLabels(scale, labelCount) {
19904 const { ctx , options: { pointLabels } } = scale;
19905 for(let i = labelCount - 1; i >= 0; i--){
19906 const item = scale._pointLabelItems[i];
19907 if (!item.visible) {
19908 continue;
19909 }
19910 const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));
19911 drawPointLabelBox(ctx, optsAtIndex, item);
19912 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
19913 const { x , y , textAlign } = item;
19914 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, {
19915 color: optsAtIndex.color,
19916 textAlign: textAlign,
19917 textBaseline: 'middle'
19918 });
19919 }
19920 }
19921 function pathRadiusLine(scale, radius, circular, labelCount) {
19922 const { ctx } = scale;
19923 if (circular) {
19924 ctx.arc(scale.xCenter, scale.yCenter, radius, 0, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
19925 } else {
19926 let pointPosition = scale.getPointPosition(0, radius);
19927 ctx.moveTo(pointPosition.x, pointPosition.y);
19928 for(let i = 1; i < labelCount; i++){
19929 pointPosition = scale.getPointPosition(i, radius);
19930 ctx.lineTo(pointPosition.x, pointPosition.y);
19931 }
19932 }
19933 }
19934 function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {
19935 const ctx = scale.ctx;
19936 const circular = gridLineOpts.circular;
19937 const { color , lineWidth } = gridLineOpts;
19938 if (!circular && !labelCount || !color || !lineWidth || radius < 0) {
19939 return;
19940 }
19941 ctx.save();
19942 ctx.strokeStyle = color;
19943 ctx.lineWidth = lineWidth;
19944 ctx.setLineDash(borderOpts.dash || []);
19945 ctx.lineDashOffset = borderOpts.dashOffset;
19946 ctx.beginPath();
19947 pathRadiusLine(scale, radius, circular, labelCount);
19948 ctx.closePath();
19949 ctx.stroke();
19950 ctx.restore();
19951 }
19952 function createPointLabelContext(parent, index, label) {
19953 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
19954 label,
19955 index,
19956 type: 'pointLabel'
19957 });
19958 }
19959 class RadialLinearScale extends LinearScaleBase {
19960 static id = 'radialLinear';
19961 static defaults = {
19962 display: true,
19963 animate: true,
19964 position: 'chartArea',
19965 angleLines: {
19966 display: true,
19967 lineWidth: 1,
19968 borderDash: [],
19969 borderDashOffset: 0.0
19970 },
19971 grid: {
19972 circular: false
19973 },
19974 startAngle: 0,
19975 ticks: {
19976 showLabelBackdrop: true,
19977 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19978 },
19979 pointLabels: {
19980 backdropColor: undefined,
19981 backdropPadding: 2,
19982 display: true,
19983 font: {
19984 size: 10
19985 },
19986 callback (label) {
19987 return label;
19988 },
19989 padding: 5,
19990 centerPointLabels: false
19991 }
19992 };
19993 static defaultRoutes = {
19994 'angleLines.color': 'borderColor',
19995 'pointLabels.color': 'color',
19996 'ticks.color': 'color'
19997 };
19998 static descriptors = {
19999 angleLines: {
20000 _fallback: 'grid'
20001 }
20002 };
20003 constructor(cfg){
20004 super(cfg);
20005 this.xCenter = undefined;
20006 this.yCenter = undefined;
20007 this.drawingArea = undefined;
20008 this._pointLabels = [];
20009 this._pointLabelItems = [];
20010 }
20011 setDimensions() {
20012 const padding = this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(getTickBackdropHeight(this.options) / 2);
20013 const w = this.width = this.maxWidth - padding.width;
20014 const h = this.height = this.maxHeight - padding.height;
20015 this.xCenter = Math.floor(this.left + w / 2 + padding.left);
20016 this.yCenter = Math.floor(this.top + h / 2 + padding.top);
20017 this.drawingArea = Math.floor(Math.min(w, h) / 2);
20018 }
20019 determineDataLimits() {
20020 const { min , max } = this.getMinMax(false);
20021 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : 0;
20022 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : 0;
20023 this.handleTickRangeOptions();
20024 }
20025 computeTickLimit() {
20026 return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
20027 }
20028 generateTickLabels(ticks) {
20029 LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
20030 this._pointLabels = this.getLabels().map((value, index)=>{
20031 const label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.pointLabels.callback, [
20032 value,
20033 index
20034 ], this);
20035 return label || label === 0 ? label : '';
20036 }).filter((v, i)=>this.chart.getDataVisibility(i));
20037 }
20038 fit() {
20039 const opts = this.options;
20040 if (opts.display && opts.pointLabels.display) {
20041 fitWithPointLabels(this);
20042 } else {
20043 this.setCenterPoint(0, 0, 0, 0);
20044 }
20045 }
20046 setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
20047 this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
20048 this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
20049 this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
20050 }
20051 getIndexAngle(index) {
20052 const angleMultiplier = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T / (this._pointLabels.length || 1);
20053 const startAngle = this.options.startAngle || 0;
20054 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(index * angleMultiplier + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(startAngle));
20055 }
20056 getDistanceFromCenterForValue(value) {
20057 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
20058 return NaN;
20059 }
20060 const scalingFactor = this.drawingArea / (this.max - this.min);
20061 if (this.options.reverse) {
20062 return (this.max - value) * scalingFactor;
20063 }
20064 return (value - this.min) * scalingFactor;
20065 }
20066 getValueForDistanceFromCenter(distance) {
20067 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(distance)) {
20068 return NaN;
20069 }
20070 const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
20071 return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
20072 }
20073 getPointLabelContext(index) {
20074 const pointLabels = this._pointLabels || [];
20075 if (index >= 0 && index < pointLabels.length) {
20076 const pointLabel = pointLabels[index];
20077 return createPointLabelContext(this.getContext(), index, pointLabel);
20078 }
20079 }
20080 getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
20081 const angle = this.getIndexAngle(index) - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H + additionalAngle;
20082 return {
20083 x: Math.cos(angle) * distanceFromCenter + this.xCenter,
20084 y: Math.sin(angle) * distanceFromCenter + this.yCenter,
20085 angle
20086 };
20087 }
20088 getPointPositionForValue(index, value) {
20089 return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
20090 }
20091 getBasePosition(index) {
20092 return this.getPointPositionForValue(index || 0, this.getBaseValue());
20093 }
20094 getPointLabelPosition(index) {
20095 const { left , top , right , bottom } = this._pointLabelItems[index];
20096 return {
20097 left,
20098 top,
20099 right,
20100 bottom
20101 };
20102 }
20103 drawBackground() {
20104 const { backgroundColor , grid: { circular } } = this.options;
20105 if (backgroundColor) {
20106 const ctx = this.ctx;
20107 ctx.save();
20108 ctx.beginPath();
20109 pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
20110 ctx.closePath();
20111 ctx.fillStyle = backgroundColor;
20112 ctx.fill();
20113 ctx.restore();
20114 }
20115 }
20116 drawGrid() {
20117 const ctx = this.ctx;
20118 const opts = this.options;
20119 const { angleLines , grid , border } = opts;
20120 const labelCount = this._pointLabels.length;
20121 let i, offset, position;
20122 if (opts.pointLabels.display) {
20123 drawPointLabels(this, labelCount);
20124 }
20125 if (grid.display) {
20126 this.ticks.forEach((tick, index)=>{
20127 if (index !== 0 || index === 0 && this.min < 0) {
20128 offset = this.getDistanceFromCenterForValue(tick.value);
20129 const context = this.getContext(index);
20130 const optsAtIndex = grid.setContext(context);
20131 const optsAtIndexBorder = border.setContext(context);
20132 drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);
20133 }
20134 });
20135 }
20136 if (angleLines.display) {
20137 ctx.save();
20138 for(i = labelCount - 1; i >= 0; i--){
20139 const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
20140 const { color , lineWidth } = optsAtIndex;
20141 if (!lineWidth || !color) {
20142 continue;
20143 }
20144 ctx.lineWidth = lineWidth;
20145 ctx.strokeStyle = color;
20146 ctx.setLineDash(optsAtIndex.borderDash);
20147 ctx.lineDashOffset = optsAtIndex.borderDashOffset;
20148 offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);
20149 position = this.getPointPosition(i, offset);
20150 ctx.beginPath();
20151 ctx.moveTo(this.xCenter, this.yCenter);
20152 ctx.lineTo(position.x, position.y);
20153 ctx.stroke();
20154 }
20155 ctx.restore();
20156 }
20157 }
20158 drawBorder() {}
20159 drawLabels() {
20160 const ctx = this.ctx;
20161 const opts = this.options;
20162 const tickOpts = opts.ticks;
20163 if (!tickOpts.display) {
20164 return;
20165 }
20166 const startAngle = this.getIndexAngle(0);
20167 let offset, width;
20168 ctx.save();
20169 ctx.translate(this.xCenter, this.yCenter);
20170 ctx.rotate(startAngle);
20171 ctx.textAlign = 'center';
20172 ctx.textBaseline = 'middle';
20173 this.ticks.forEach((tick, index)=>{
20174 if (index === 0 && this.min >= 0 && !opts.reverse) {
20175 return;
20176 }
20177 const optsAtIndex = tickOpts.setContext(this.getContext(index));
20178 const tickFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
20179 offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
20180 if (optsAtIndex.showLabelBackdrop) {
20181 ctx.font = tickFont.string;
20182 width = ctx.measureText(tick.label).width;
20183 ctx.fillStyle = optsAtIndex.backdropColor;
20184 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
20185 ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);
20186 }
20187 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, tick.label, 0, -offset, tickFont, {
20188 color: optsAtIndex.color,
20189 strokeColor: optsAtIndex.textStrokeColor,
20190 strokeWidth: optsAtIndex.textStrokeWidth
20191 });
20192 });
20193 ctx.restore();
20194 }
20195 drawTitle() {}
20196 }
20197
20198 const INTERVALS = {
20199 millisecond: {
20200 common: true,
20201 size: 1,
20202 steps: 1000
20203 },
20204 second: {
20205 common: true,
20206 size: 1000,
20207 steps: 60
20208 },
20209 minute: {
20210 common: true,
20211 size: 60000,
20212 steps: 60
20213 },
20214 hour: {
20215 common: true,
20216 size: 3600000,
20217 steps: 24
20218 },
20219 day: {
20220 common: true,
20221 size: 86400000,
20222 steps: 30
20223 },
20224 week: {
20225 common: false,
20226 size: 604800000,
20227 steps: 4
20228 },
20229 month: {
20230 common: true,
20231 size: 2.628e9,
20232 steps: 12
20233 },
20234 quarter: {
20235 common: false,
20236 size: 7.884e9,
20237 steps: 4
20238 },
20239 year: {
20240 common: true,
20241 size: 3.154e10
20242 }
20243 };
20244 const UNITS = /* #__PURE__ */ Object.keys(INTERVALS);
20245 function sorter(a, b) {
20246 return a - b;
20247 }
20248 function parse(scale, input) {
20249 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(input)) {
20250 return null;
20251 }
20252 const adapter = scale._adapter;
20253 const { parser , round , isoWeekday } = scale._parseOpts;
20254 let value = input;
20255 if (typeof parser === 'function') {
20256 value = parser(value);
20257 }
20258 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
20259 value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value);
20260 }
20261 if (value === null) {
20262 return null;
20263 }
20264 if (round) {
20265 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);
20266 }
20267 return +value;
20268 }
20269 function determineUnitForAutoTicks(minUnit, min, max, capacity) {
20270 const ilen = UNITS.length;
20271 for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){
20272 const interval = INTERVALS[UNITS[i]];
20273 const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
20274 if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
20275 return UNITS[i];
20276 }
20277 }
20278 return UNITS[ilen - 1];
20279 }
20280 function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
20281 for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){
20282 const unit = UNITS[i];
20283 if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
20284 return unit;
20285 }
20286 }
20287 return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
20288 }
20289 function determineMajorUnit(unit) {
20290 for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){
20291 if (INTERVALS[UNITS[i]].common) {
20292 return UNITS[i];
20293 }
20294 }
20295 }
20296 function addTick(ticks, time, timestamps) {
20297 if (!timestamps) {
20298 ticks[time] = true;
20299 } else if (timestamps.length) {
20300 const { lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aQ)(timestamps, time);
20301 const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
20302 ticks[timestamp] = true;
20303 }
20304 }
20305 function setMajorTicks(scale, ticks, map, majorUnit) {
20306 const adapter = scale._adapter;
20307 const first = +adapter.startOf(ticks[0].value, majorUnit);
20308 const last = ticks[ticks.length - 1].value;
20309 let major, index;
20310 for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){
20311 index = map[major];
20312 if (index >= 0) {
20313 ticks[index].major = true;
20314 }
20315 }
20316 return ticks;
20317 }
20318 function ticksFromTimestamps(scale, values, majorUnit) {
20319 const ticks = [];
20320 const map = {};
20321 const ilen = values.length;
20322 let i, value;
20323 for(i = 0; i < ilen; ++i){
20324 value = values[i];
20325 map[value] = i;
20326 ticks.push({
20327 value,
20328 major: false
20329 });
20330 }
20331 return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
20332 }
20333 class TimeScale extends Scale {
20334 static id = 'time';
20335 static defaults = {
20336 bounds: 'data',
20337 adapters: {},
20338 time: {
20339 parser: false,
20340 unit: false,
20341 round: false,
20342 isoWeekday: false,
20343 minUnit: 'millisecond',
20344 displayFormats: {}
20345 },
20346 ticks: {
20347 source: 'auto',
20348 callback: false,
20349 major: {
20350 enabled: false
20351 }
20352 }
20353 };
20354 constructor(props){
20355 super(props);
20356 this._cache = {
20357 data: [],
20358 labels: [],
20359 all: []
20360 };
20361 this._unit = 'day';
20362 this._majorUnit = undefined;
20363 this._offsets = {};
20364 this._normalized = false;
20365 this._parseOpts = undefined;
20366 }
20367 init(scaleOpts, opts = {}) {
20368 const time = scaleOpts.time || (scaleOpts.time = {});
20369 const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
20370 adapter.init(opts);
20371 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(time.displayFormats, adapter.formats());
20372 this._parseOpts = {
20373 parser: time.parser,
20374 round: time.round,
20375 isoWeekday: time.isoWeekday
20376 };
20377 super.init(scaleOpts);
20378 this._normalized = opts.normalized;
20379 }
20380 parse(raw, index) {
20381 if (raw === undefined) {
20382 return null;
20383 }
20384 return parse(this, raw);
20385 }
20386 beforeLayout() {
20387 super.beforeLayout();
20388 this._cache = {
20389 data: [],
20390 labels: [],
20391 all: []
20392 };
20393 }
20394 determineDataLimits() {
20395 const options = this.options;
20396 const adapter = this._adapter;
20397 const unit = options.time.unit || 'day';
20398 let { min , max , minDefined , maxDefined } = this.getUserBounds();
20399 function _applyBounds(bounds) {
20400 if (!minDefined && !isNaN(bounds.min)) {
20401 min = Math.min(min, bounds.min);
20402 }
20403 if (!maxDefined && !isNaN(bounds.max)) {
20404 max = Math.max(max, bounds.max);
20405 }
20406 }
20407 if (!minDefined || !maxDefined) {
20408 _applyBounds(this._getLabelBounds());
20409 if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
20410 _applyBounds(this.getMinMax(false));
20411 }
20412 }
20413 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
20414 max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
20415 this.min = Math.min(min, max - 1);
20416 this.max = Math.max(min + 1, max);
20417 }
20418 _getLabelBounds() {
20419 const arr = this.getLabelTimestamps();
20420 let min = Number.POSITIVE_INFINITY;
20421 let max = Number.NEGATIVE_INFINITY;
20422 if (arr.length) {
20423 min = arr[0];
20424 max = arr[arr.length - 1];
20425 }
20426 return {
20427 min,
20428 max
20429 };
20430 }
20431 buildTicks() {
20432 const options = this.options;
20433 const timeOpts = options.time;
20434 const tickOpts = options.ticks;
20435 const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();
20436 if (options.bounds === 'ticks' && timestamps.length) {
20437 this.min = this._userMin || timestamps[0];
20438 this.max = this._userMax || timestamps[timestamps.length - 1];
20439 }
20440 const min = this.min;
20441 const max = this.max;
20442 const ticks = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aP)(timestamps, min, max);
20443 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));
20444 this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit);
20445 this.initOffsets(timestamps);
20446 if (options.reverse) {
20447 ticks.reverse();
20448 }
20449 return ticksFromTimestamps(this, ticks, this._majorUnit);
20450 }
20451 afterAutoSkip() {
20452 if (this.options.offsetAfterAutoskip) {
20453 this.initOffsets(this.ticks.map((tick)=>+tick.value));
20454 }
20455 }
20456 initOffsets(timestamps = []) {
20457 let start = 0;
20458 let end = 0;
20459 let first, last;
20460 if (this.options.offset && timestamps.length) {
20461 first = this.getDecimalForValue(timestamps[0]);
20462 if (timestamps.length === 1) {
20463 start = 1 - first;
20464 } else {
20465 start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
20466 }
20467 last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
20468 if (timestamps.length === 1) {
20469 end = last;
20470 } else {
20471 end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
20472 }
20473 }
20474 const limit = timestamps.length < 3 ? 0.5 : 0.25;
20475 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(start, 0, limit);
20476 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(end, 0, limit);
20477 this._offsets = {
20478 start,
20479 end,
20480 factor: 1 / (start + 1 + end)
20481 };
20482 }
20483 _generate() {
20484 const adapter = this._adapter;
20485 const min = this.min;
20486 const max = this.max;
20487 const options = this.options;
20488 const timeOpts = options.time;
20489 const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
20490 const stepSize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.stepSize, 1);
20491 const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
20492 const hasWeekday = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(weekday) || weekday === true;
20493 const ticks = {};
20494 let first = min;
20495 let time, count;
20496 if (hasWeekday) {
20497 first = +adapter.startOf(first, 'isoWeek', weekday);
20498 }
20499 first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
20500 if (adapter.diff(max, min, minor) > 100000 * stepSize) {
20501 throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
20502 }
20503 const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();
20504 for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){
20505 addTick(ticks, time, timestamps);
20506 }
20507 if (time === max || options.bounds === 'ticks' || count === 1) {
20508 addTick(ticks, time, timestamps);
20509 }
20510 return Object.keys(ticks).sort(sorter).map((x)=>+x);
20511 }
20512 getLabelForValue(value) {
20513 const adapter = this._adapter;
20514 const timeOpts = this.options.time;
20515 if (timeOpts.tooltipFormat) {
20516 return adapter.format(value, timeOpts.tooltipFormat);
20517 }
20518 return adapter.format(value, timeOpts.displayFormats.datetime);
20519 }
20520 format(value, format) {
20521 const options = this.options;
20522 const formats = options.time.displayFormats;
20523 const unit = this._unit;
20524 const fmt = format || formats[unit];
20525 return this._adapter.format(value, fmt);
20526 }
20527 _tickFormatFunction(time, index, ticks, format) {
20528 const options = this.options;
20529 const formatter = options.ticks.callback;
20530 if (formatter) {
20531 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(formatter, [
20532 time,
20533 index,
20534 ticks
20535 ], this);
20536 }
20537 const formats = options.time.displayFormats;
20538 const unit = this._unit;
20539 const majorUnit = this._majorUnit;
20540 const minorFormat = unit && formats[unit];
20541 const majorFormat = majorUnit && formats[majorUnit];
20542 const tick = ticks[index];
20543 const major = majorUnit && majorFormat && tick && tick.major;
20544 return this._adapter.format(time, format || (major ? majorFormat : minorFormat));
20545 }
20546 generateTickLabels(ticks) {
20547 let i, ilen, tick;
20548 for(i = 0, ilen = ticks.length; i < ilen; ++i){
20549 tick = ticks[i];
20550 tick.label = this._tickFormatFunction(tick.value, i, ticks);
20551 }
20552 }
20553 getDecimalForValue(value) {
20554 return value === null ? NaN : (value - this.min) / (this.max - this.min);
20555 }
20556 getPixelForValue(value) {
20557 const offsets = this._offsets;
20558 const pos = this.getDecimalForValue(value);
20559 return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
20560 }
20561 getValueForPixel(pixel) {
20562 const offsets = this._offsets;
20563 const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20564 return this.min + pos * (this.max - this.min);
20565 }
20566 _getLabelSize(label) {
20567 const ticksOpts = this.options.ticks;
20568 const tickLabelWidth = this.ctx.measureText(label).width;
20569 const angle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
20570 const cosRotation = Math.cos(angle);
20571 const sinRotation = Math.sin(angle);
20572 const tickFontSize = this._resolveTickFontOptions(0).size;
20573 return {
20574 w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,
20575 h: tickLabelWidth * sinRotation + tickFontSize * cosRotation
20576 };
20577 }
20578 _getLabelCapacity(exampleTime) {
20579 const timeOpts = this.options.time;
20580 const displayFormats = timeOpts.displayFormats;
20581 const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
20582 const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [
20583 exampleTime
20584 ], this._majorUnit), format);
20585 const size = this._getLabelSize(exampleLabel);
20586 const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
20587 return capacity > 0 ? capacity : 1;
20588 }
20589 getDataTimestamps() {
20590 let timestamps = this._cache.data || [];
20591 let i, ilen;
20592 if (timestamps.length) {
20593 return timestamps;
20594 }
20595 const metas = this.getMatchingVisibleMetas();
20596 if (this._normalized && metas.length) {
20597 return this._cache.data = metas[0].controller.getAllParsedValues(this);
20598 }
20599 for(i = 0, ilen = metas.length; i < ilen; ++i){
20600 timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));
20601 }
20602 return this._cache.data = this.normalize(timestamps);
20603 }
20604 getLabelTimestamps() {
20605 const timestamps = this._cache.labels || [];
20606 let i, ilen;
20607 if (timestamps.length) {
20608 return timestamps;
20609 }
20610 const labels = this.getLabels();
20611 for(i = 0, ilen = labels.length; i < ilen; ++i){
20612 timestamps.push(parse(this, labels[i]));
20613 }
20614 return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);
20615 }
20616 normalize(values) {
20617 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort(sorter));
20618 }
20619 }
20620
20621 function interpolate(table, val, reverse) {
20622 let lo = 0;
20623 let hi = table.length - 1;
20624 let prevSource, nextSource, prevTarget, nextTarget;
20625 if (reverse) {
20626 if (val >= table[lo].pos && val <= table[hi].pos) {
20627 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'pos', val));
20628 }
20629 ({ pos: prevSource , time: prevTarget } = table[lo]);
20630 ({ pos: nextSource , time: nextTarget } = table[hi]);
20631 } else {
20632 if (val >= table[lo].time && val <= table[hi].time) {
20633 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'time', val));
20634 }
20635 ({ time: prevSource , pos: prevTarget } = table[lo]);
20636 ({ time: nextSource , pos: nextTarget } = table[hi]);
20637 }
20638 const span = nextSource - prevSource;
20639 return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
20640 }
20641 class TimeSeriesScale extends TimeScale {
20642 static id = 'timeseries';
20643 static defaults = TimeScale.defaults;
20644 constructor(props){
20645 super(props);
20646 this._table = [];
20647 this._minPos = undefined;
20648 this._tableRange = undefined;
20649 }
20650 initOffsets() {
20651 const timestamps = this._getTimestampsForTable();
20652 const table = this._table = this.buildLookupTable(timestamps);
20653 this._minPos = interpolate(table, this.min);
20654 this._tableRange = interpolate(table, this.max) - this._minPos;
20655 super.initOffsets(timestamps);
20656 }
20657 buildLookupTable(timestamps) {
20658 const { min , max } = this;
20659 const items = [];
20660 const table = [];
20661 let i, ilen, prev, curr, next;
20662 for(i = 0, ilen = timestamps.length; i < ilen; ++i){
20663 curr = timestamps[i];
20664 if (curr >= min && curr <= max) {
20665 items.push(curr);
20666 }
20667 }
20668 if (items.length < 2) {
20669 return [
20670 {
20671 time: min,
20672 pos: 0
20673 },
20674 {
20675 time: max,
20676 pos: 1
20677 }
20678 ];
20679 }
20680 for(i = 0, ilen = items.length; i < ilen; ++i){
20681 next = items[i + 1];
20682 prev = items[i - 1];
20683 curr = items[i];
20684 if (Math.round((next + prev) / 2) !== curr) {
20685 table.push({
20686 time: curr,
20687 pos: i / (ilen - 1)
20688 });
20689 }
20690 }
20691 return table;
20692 }
20693 _generate() {
20694 const min = this.min;
20695 const max = this.max;
20696 let timestamps = super.getDataTimestamps();
20697 if (!timestamps.includes(min) || !timestamps.length) {
20698 timestamps.splice(0, 0, min);
20699 }
20700 if (!timestamps.includes(max) || timestamps.length === 1) {
20701 timestamps.push(max);
20702 }
20703 return timestamps.sort((a, b)=>a - b);
20704 }
20705 _getTimestampsForTable() {
20706 let timestamps = this._cache.all || [];
20707 if (timestamps.length) {
20708 return timestamps;
20709 }
20710 const data = this.getDataTimestamps();
20711 const label = this.getLabelTimestamps();
20712 if (data.length && label.length) {
20713 timestamps = this.normalize(data.concat(label));
20714 } else {
20715 timestamps = data.length ? data : label;
20716 }
20717 timestamps = this._cache.all = timestamps;
20718 return timestamps;
20719 }
20720 getDecimalForValue(value) {
20721 return (interpolate(this._table, value) - this._minPos) / this._tableRange;
20722 }
20723 getValueForPixel(pixel) {
20724 const offsets = this._offsets;
20725 const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20726 return interpolate(this._table, decimal * this._tableRange + this._minPos, true);
20727 }
20728 }
20729
20730 var scales = /*#__PURE__*/Object.freeze({
20731 __proto__: null,
20732 CategoryScale: CategoryScale,
20733 LinearScale: LinearScale,
20734 LogarithmicScale: LogarithmicScale,
20735 RadialLinearScale: RadialLinearScale,
20736 TimeScale: TimeScale,
20737 TimeSeriesScale: TimeSeriesScale
20738 });
20739
20740 const registerables = [
20741 controllers,
20742 elements,
20743 plugins,
20744 scales
20745 ];
20746
20747
20748 //# sourceMappingURL=chart.js.map
20749
20750
20751 /***/ },
20752
20753 /***/ "./node_modules/chart.js/dist/chunks/helpers.dataset.js"
20754 /*!**************************************************************!*\
20755 !*** ./node_modules/chart.js/dist/chunks/helpers.dataset.js ***!
20756 \**************************************************************/
20757 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
20758
20759 "use strict";
20760 __webpack_require__.r(__webpack_exports__);
20761 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
20762 /* harmony export */ $: () => (/* binding */ unclipArea),
20763 /* harmony export */ A: () => (/* binding */ _rlookupByKey),
20764 /* harmony export */ B: () => (/* binding */ _lookupByKey),
20765 /* harmony export */ C: () => (/* binding */ _isPointInArea),
20766 /* harmony export */ D: () => (/* binding */ getAngleFromPoint),
20767 /* harmony export */ E: () => (/* binding */ toPadding),
20768 /* harmony export */ F: () => (/* binding */ each),
20769 /* harmony export */ G: () => (/* binding */ getMaximumSize),
20770 /* harmony export */ H: () => (/* binding */ HALF_PI),
20771 /* harmony export */ I: () => (/* binding */ _getParentNode),
20772 /* harmony export */ J: () => (/* binding */ readUsedSize),
20773 /* harmony export */ K: () => (/* binding */ supportsEventListenerOptions),
20774 /* harmony export */ L: () => (/* binding */ throttled),
20775 /* harmony export */ M: () => (/* binding */ _isDomSupported),
20776 /* harmony export */ N: () => (/* binding */ _factorize),
20777 /* harmony export */ O: () => (/* binding */ finiteOrDefault),
20778 /* harmony export */ P: () => (/* binding */ PI),
20779 /* harmony export */ Q: () => (/* binding */ callback),
20780 /* harmony export */ R: () => (/* binding */ _addGrace),
20781 /* harmony export */ S: () => (/* binding */ _limitValue),
20782 /* harmony export */ T: () => (/* binding */ TAU),
20783 /* harmony export */ U: () => (/* binding */ toDegrees),
20784 /* harmony export */ V: () => (/* binding */ _measureText),
20785 /* harmony export */ W: () => (/* binding */ _int16Range),
20786 /* harmony export */ X: () => (/* binding */ _alignPixel),
20787 /* harmony export */ Y: () => (/* binding */ clipArea),
20788 /* harmony export */ Z: () => (/* binding */ renderText),
20789 /* harmony export */ _: () => (/* binding */ _arrayUnique),
20790 /* harmony export */ a: () => (/* binding */ resolve),
20791 /* harmony export */ a$: () => (/* binding */ getStyle),
20792 /* harmony export */ a0: () => (/* binding */ toFont),
20793 /* harmony export */ a1: () => (/* binding */ _toLeftRightCenter),
20794 /* harmony export */ a2: () => (/* binding */ _alignStartEnd),
20795 /* harmony export */ a3: () => (/* binding */ overrides),
20796 /* harmony export */ a4: () => (/* binding */ merge),
20797 /* harmony export */ a5: () => (/* binding */ _capitalize),
20798 /* harmony export */ a6: () => (/* binding */ descriptors),
20799 /* harmony export */ a7: () => (/* binding */ isFunction),
20800 /* harmony export */ a8: () => (/* binding */ _attachContext),
20801 /* harmony export */ a9: () => (/* binding */ _createResolver),
20802 /* harmony export */ aA: () => (/* binding */ getRtlAdapter),
20803 /* harmony export */ aB: () => (/* binding */ overrideTextDirection),
20804 /* harmony export */ aC: () => (/* binding */ _textX),
20805 /* harmony export */ aD: () => (/* binding */ restoreTextDirection),
20806 /* harmony export */ aE: () => (/* binding */ drawPointLegend),
20807 /* harmony export */ aF: () => (/* binding */ distanceBetweenPoints),
20808 /* harmony export */ aG: () => (/* binding */ noop),
20809 /* harmony export */ aH: () => (/* binding */ _setMinAndMaxByKey),
20810 /* harmony export */ aI: () => (/* binding */ niceNum),
20811 /* harmony export */ aJ: () => (/* binding */ almostWhole),
20812 /* harmony export */ aK: () => (/* binding */ almostEquals),
20813 /* harmony export */ aL: () => (/* binding */ _decimalPlaces),
20814 /* harmony export */ aM: () => (/* binding */ Ticks),
20815 /* harmony export */ aN: () => (/* binding */ log10),
20816 /* harmony export */ aO: () => (/* binding */ _longestText),
20817 /* harmony export */ aP: () => (/* binding */ _filterBetween),
20818 /* harmony export */ aQ: () => (/* binding */ _lookup),
20819 /* harmony export */ aR: () => (/* binding */ isPatternOrGradient),
20820 /* harmony export */ aS: () => (/* binding */ getHoverColor),
20821 /* harmony export */ aT: () => (/* binding */ clone),
20822 /* harmony export */ aU: () => (/* binding */ _merger),
20823 /* harmony export */ aV: () => (/* binding */ _mergerIf),
20824 /* harmony export */ aW: () => (/* binding */ _deprecated),
20825 /* harmony export */ aX: () => (/* binding */ _splitKey),
20826 /* harmony export */ aY: () => (/* binding */ toFontString),
20827 /* harmony export */ aZ: () => (/* binding */ splineCurve),
20828 /* harmony export */ a_: () => (/* binding */ splineCurveMonotone),
20829 /* harmony export */ aa: () => (/* binding */ _descriptors),
20830 /* harmony export */ ab: () => (/* binding */ mergeIf),
20831 /* harmony export */ ac: () => (/* binding */ uid),
20832 /* harmony export */ ad: () => (/* binding */ debounce),
20833 /* harmony export */ ae: () => (/* binding */ retinaScale),
20834 /* harmony export */ af: () => (/* binding */ clearCanvas),
20835 /* harmony export */ ag: () => (/* binding */ setsEqual),
20836 /* harmony export */ ah: () => (/* binding */ getDatasetClipArea),
20837 /* harmony export */ ai: () => (/* binding */ _elementsEqual),
20838 /* harmony export */ aj: () => (/* binding */ _isClickEvent),
20839 /* harmony export */ ak: () => (/* binding */ _isBetween),
20840 /* harmony export */ al: () => (/* binding */ _normalizeAngle),
20841 /* harmony export */ am: () => (/* binding */ _readValueToProps),
20842 /* harmony export */ an: () => (/* binding */ _updateBezierControlPoints),
20843 /* harmony export */ ao: () => (/* binding */ _computeSegments),
20844 /* harmony export */ ap: () => (/* binding */ _boundSegments),
20845 /* harmony export */ aq: () => (/* binding */ _steppedInterpolation),
20846 /* harmony export */ ar: () => (/* binding */ _bezierInterpolation),
20847 /* harmony export */ as: () => (/* binding */ _pointInLine),
20848 /* harmony export */ at: () => (/* binding */ _steppedLineTo),
20849 /* harmony export */ au: () => (/* binding */ _bezierCurveTo),
20850 /* harmony export */ av: () => (/* binding */ drawPoint),
20851 /* harmony export */ aw: () => (/* binding */ addRoundedRectPath),
20852 /* harmony export */ ax: () => (/* binding */ toTRBL),
20853 /* harmony export */ ay: () => (/* binding */ toTRBLCorners),
20854 /* harmony export */ az: () => (/* binding */ _boundSegment),
20855 /* harmony export */ b: () => (/* binding */ isArray),
20856 /* harmony export */ b0: () => (/* binding */ fontString),
20857 /* harmony export */ b1: () => (/* binding */ toLineHeight),
20858 /* harmony export */ b2: () => (/* binding */ PITAU),
20859 /* harmony export */ b3: () => (/* binding */ INFINITY),
20860 /* harmony export */ b4: () => (/* binding */ RAD_PER_DEG),
20861 /* harmony export */ b5: () => (/* binding */ QUARTER_PI),
20862 /* harmony export */ b6: () => (/* binding */ TWO_THIRDS_PI),
20863 /* harmony export */ b7: () => (/* binding */ _angleDiff),
20864 /* harmony export */ c: () => (/* binding */ color),
20865 /* harmony export */ d: () => (/* binding */ defaults),
20866 /* harmony export */ e: () => (/* binding */ effects),
20867 /* harmony export */ f: () => (/* binding */ resolveObjectKey),
20868 /* harmony export */ g: () => (/* binding */ isNumberFinite),
20869 /* harmony export */ h: () => (/* binding */ defined),
20870 /* harmony export */ i: () => (/* binding */ isObject),
20871 /* harmony export */ j: () => (/* binding */ createContext),
20872 /* harmony export */ k: () => (/* binding */ isNullOrUndef),
20873 /* harmony export */ l: () => (/* binding */ listenArrayEvents),
20874 /* harmony export */ m: () => (/* binding */ toPercentage),
20875 /* harmony export */ n: () => (/* binding */ toDimension),
20876 /* harmony export */ o: () => (/* binding */ formatNumber),
20877 /* harmony export */ p: () => (/* binding */ _angleBetween),
20878 /* harmony export */ q: () => (/* binding */ _getStartAndCountOfVisiblePoints),
20879 /* harmony export */ r: () => (/* binding */ requestAnimFrame),
20880 /* harmony export */ s: () => (/* binding */ sign),
20881 /* harmony export */ t: () => (/* binding */ toRadians),
20882 /* harmony export */ u: () => (/* binding */ unlistenArrayEvents),
20883 /* harmony export */ v: () => (/* binding */ valueOrDefault),
20884 /* harmony export */ w: () => (/* binding */ _scaleRangesChanged),
20885 /* harmony export */ x: () => (/* binding */ isNumber),
20886 /* harmony export */ y: () => (/* binding */ _parseObjectDataRadialScale),
20887 /* harmony export */ z: () => (/* binding */ getRelativePosition)
20888 /* harmony export */ });
20889 /* harmony import */ var _kurkle_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kurkle/color */ "./node_modules/@kurkle/color/dist/color.esm.js");
20890 /*!
20891 * Chart.js v4.5.1
20892 * https://www.chartjs.org
20893 * (c) 2025 Chart.js Contributors
20894 * Released under the MIT License
20895 */
20896
20897
20898 /**
20899 * @namespace Chart.helpers
20900 */ /**
20901 * An empty function that can be used, for example, for optional callback.
20902 */ function noop() {
20903 /* noop */ }
20904 /**
20905 * Returns a unique id, sequentially generated from a global variable.
20906 */ const uid = (()=>{
20907 let id = 0;
20908 return ()=>id++;
20909 })();
20910 /**
20911 * Returns true if `value` is neither null nor undefined, else returns false.
20912 * @param value - The value to test.
20913 * @since 2.7.0
20914 */ function isNullOrUndef(value) {
20915 return value === null || value === undefined;
20916 }
20917 /**
20918 * Returns true if `value` is an array (including typed arrays), else returns false.
20919 * @param value - The value to test.
20920 * @function
20921 */ function isArray(value) {
20922 if (Array.isArray && Array.isArray(value)) {
20923 return true;
20924 }
20925 const type = Object.prototype.toString.call(value);
20926 if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') {
20927 return true;
20928 }
20929 return false;
20930 }
20931 /**
20932 * Returns true if `value` is an object (excluding null), else returns false.
20933 * @param value - The value to test.
20934 * @since 2.7.0
20935 */ function isObject(value) {
20936 return value !== null && Object.prototype.toString.call(value) === '[object Object]';
20937 }
20938 /**
20939 * Returns true if `value` is a finite number, else returns false
20940 * @param value - The value to test.
20941 */ function isNumberFinite(value) {
20942 return (typeof value === 'number' || value instanceof Number) && isFinite(+value);
20943 }
20944 /**
20945 * Returns `value` if finite, else returns `defaultValue`.
20946 * @param value - The value to return if defined.
20947 * @param defaultValue - The value to return if `value` is not finite.
20948 */ function finiteOrDefault(value, defaultValue) {
20949 return isNumberFinite(value) ? value : defaultValue;
20950 }
20951 /**
20952 * Returns `value` if defined, else returns `defaultValue`.
20953 * @param value - The value to return if defined.
20954 * @param defaultValue - The value to return if `value` is undefined.
20955 */ function valueOrDefault(value, defaultValue) {
20956 return typeof value === 'undefined' ? defaultValue : value;
20957 }
20958 const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;
20959 const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;
20960 /**
20961 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
20962 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
20963 * @param fn - The function to call.
20964 * @param args - The arguments with which `fn` should be called.
20965 * @param [thisArg] - The value of `this` provided for the call to `fn`.
20966 */ function callback(fn, args, thisArg) {
20967 if (fn && typeof fn.call === 'function') {
20968 return fn.apply(thisArg, args);
20969 }
20970 }
20971 function each(loopable, fn, thisArg, reverse) {
20972 let i, len, keys;
20973 if (isArray(loopable)) {
20974 len = loopable.length;
20975 if (reverse) {
20976 for(i = len - 1; i >= 0; i--){
20977 fn.call(thisArg, loopable[i], i);
20978 }
20979 } else {
20980 for(i = 0; i < len; i++){
20981 fn.call(thisArg, loopable[i], i);
20982 }
20983 }
20984 } else if (isObject(loopable)) {
20985 keys = Object.keys(loopable);
20986 len = keys.length;
20987 for(i = 0; i < len; i++){
20988 fn.call(thisArg, loopable[keys[i]], keys[i]);
20989 }
20990 }
20991 }
20992 /**
20993 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
20994 * @param a0 - The array to compare
20995 * @param a1 - The array to compare
20996 * @private
20997 */ function _elementsEqual(a0, a1) {
20998 let i, ilen, v0, v1;
20999 if (!a0 || !a1 || a0.length !== a1.length) {
21000 return false;
21001 }
21002 for(i = 0, ilen = a0.length; i < ilen; ++i){
21003 v0 = a0[i];
21004 v1 = a1[i];
21005 if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
21006 return false;
21007 }
21008 }
21009 return true;
21010 }
21011 /**
21012 * Returns a deep copy of `source` without keeping references on objects and arrays.
21013 * @param source - The value to clone.
21014 */ function clone(source) {
21015 if (isArray(source)) {
21016 return source.map(clone);
21017 }
21018 if (isObject(source)) {
21019 const target = Object.create(null);
21020 const keys = Object.keys(source);
21021 const klen = keys.length;
21022 let k = 0;
21023 for(; k < klen; ++k){
21024 target[keys[k]] = clone(source[keys[k]]);
21025 }
21026 return target;
21027 }
21028 return source;
21029 }
21030 function isValidKey(key) {
21031 return [
21032 '__proto__',
21033 'prototype',
21034 'constructor'
21035 ].indexOf(key) === -1;
21036 }
21037 /**
21038 * The default merger when Chart.helpers.merge is called without merger option.
21039 * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
21040 * @private
21041 */ function _merger(key, target, source, options) {
21042 if (!isValidKey(key)) {
21043 return;
21044 }
21045 const tval = target[key];
21046 const sval = source[key];
21047 if (isObject(tval) && isObject(sval)) {
21048 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21049 merge(tval, sval, options);
21050 } else {
21051 target[key] = clone(sval);
21052 }
21053 }
21054 function merge(target, source, options) {
21055 const sources = isArray(source) ? source : [
21056 source
21057 ];
21058 const ilen = sources.length;
21059 if (!isObject(target)) {
21060 return target;
21061 }
21062 options = options || {};
21063 const merger = options.merger || _merger;
21064 let current;
21065 for(let i = 0; i < ilen; ++i){
21066 current = sources[i];
21067 if (!isObject(current)) {
21068 continue;
21069 }
21070 const keys = Object.keys(current);
21071 for(let k = 0, klen = keys.length; k < klen; ++k){
21072 merger(keys[k], target, current, options);
21073 }
21074 }
21075 return target;
21076 }
21077 function mergeIf(target, source) {
21078 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21079 return merge(target, source, {
21080 merger: _mergerIf
21081 });
21082 }
21083 /**
21084 * Merges source[key] in target[key] only if target[key] is undefined.
21085 * @private
21086 */ function _mergerIf(key, target, source) {
21087 if (!isValidKey(key)) {
21088 return;
21089 }
21090 const tval = target[key];
21091 const sval = source[key];
21092 if (isObject(tval) && isObject(sval)) {
21093 mergeIf(tval, sval);
21094 } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
21095 target[key] = clone(sval);
21096 }
21097 }
21098 /**
21099 * @private
21100 */ function _deprecated(scope, value, previous, current) {
21101 if (value !== undefined) {
21102 console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead');
21103 }
21104 }
21105 // resolveObjectKey resolver cache
21106 const keyResolvers = {
21107 // Chart.helpers.core resolveObjectKey should resolve empty key to root object
21108 '': (v)=>v,
21109 // default resolvers
21110 x: (o)=>o.x,
21111 y: (o)=>o.y
21112 };
21113 /**
21114 * @private
21115 */ function _splitKey(key) {
21116 const parts = key.split('.');
21117 const keys = [];
21118 let tmp = '';
21119 for (const part of parts){
21120 tmp += part;
21121 if (tmp.endsWith('\\')) {
21122 tmp = tmp.slice(0, -1) + '.';
21123 } else {
21124 keys.push(tmp);
21125 tmp = '';
21126 }
21127 }
21128 return keys;
21129 }
21130 function _getKeyResolver(key) {
21131 const keys = _splitKey(key);
21132 return (obj)=>{
21133 for (const k of keys){
21134 if (k === '') {
21135 break;
21136 }
21137 obj = obj && obj[k];
21138 }
21139 return obj;
21140 };
21141 }
21142 function resolveObjectKey(obj, key) {
21143 const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
21144 return resolver(obj);
21145 }
21146 /**
21147 * @private
21148 */ function _capitalize(str) {
21149 return str.charAt(0).toUpperCase() + str.slice(1);
21150 }
21151 const defined = (value)=>typeof value !== 'undefined';
21152 const isFunction = (value)=>typeof value === 'function';
21153 // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
21154 const setsEqual = (a, b)=>{
21155 if (a.size !== b.size) {
21156 return false;
21157 }
21158 for (const item of a){
21159 if (!b.has(item)) {
21160 return false;
21161 }
21162 }
21163 return true;
21164 };
21165 /**
21166 * @param e - The event
21167 * @private
21168 */ function _isClickEvent(e) {
21169 return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
21170 }
21171
21172 /**
21173 * @alias Chart.helpers.math
21174 * @namespace
21175 */ const PI = Math.PI;
21176 const TAU = 2 * PI;
21177 const PITAU = TAU + PI;
21178 const INFINITY = Number.POSITIVE_INFINITY;
21179 const RAD_PER_DEG = PI / 180;
21180 const HALF_PI = PI / 2;
21181 const QUARTER_PI = PI / 4;
21182 const TWO_THIRDS_PI = PI * 2 / 3;
21183 const log10 = Math.log10;
21184 const sign = Math.sign;
21185 function almostEquals(x, y, epsilon) {
21186 return Math.abs(x - y) < epsilon;
21187 }
21188 /**
21189 * Implementation of the nice number algorithm used in determining where axis labels will go
21190 */ function niceNum(range) {
21191 const roundedRange = Math.round(range);
21192 range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
21193 const niceRange = Math.pow(10, Math.floor(log10(range)));
21194 const fraction = range / niceRange;
21195 const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
21196 return niceFraction * niceRange;
21197 }
21198 /**
21199 * Returns an array of factors sorted from 1 to sqrt(value)
21200 * @private
21201 */ function _factorize(value) {
21202 const result = [];
21203 const sqrt = Math.sqrt(value);
21204 let i;
21205 for(i = 1; i < sqrt; i++){
21206 if (value % i === 0) {
21207 result.push(i);
21208 result.push(value / i);
21209 }
21210 }
21211 if (sqrt === (sqrt | 0)) {
21212 result.push(sqrt);
21213 }
21214 result.sort((a, b)=>a - b).pop();
21215 return result;
21216 }
21217 /**
21218 * Verifies that attempting to coerce n to string or number won't throw a TypeError.
21219 */ function isNonPrimitive(n) {
21220 return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n);
21221 }
21222 function isNumber(n) {
21223 return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n);
21224 }
21225 function almostWhole(x, epsilon) {
21226 const rounded = Math.round(x);
21227 return rounded - epsilon <= x && rounded + epsilon >= x;
21228 }
21229 /**
21230 * @private
21231 */ function _setMinAndMaxByKey(array, target, property) {
21232 let i, ilen, value;
21233 for(i = 0, ilen = array.length; i < ilen; i++){
21234 value = array[i][property];
21235 if (!isNaN(value)) {
21236 target.min = Math.min(target.min, value);
21237 target.max = Math.max(target.max, value);
21238 }
21239 }
21240 }
21241 function toRadians(degrees) {
21242 return degrees * (PI / 180);
21243 }
21244 function toDegrees(radians) {
21245 return radians * (180 / PI);
21246 }
21247 /**
21248 * Returns the number of decimal places
21249 * i.e. the number of digits after the decimal point, of the value of this Number.
21250 * @param x - A number.
21251 * @returns The number of decimal places.
21252 * @private
21253 */ function _decimalPlaces(x) {
21254 if (!isNumberFinite(x)) {
21255 return;
21256 }
21257 let e = 1;
21258 let p = 0;
21259 while(Math.round(x * e) / e !== x){
21260 e *= 10;
21261 p++;
21262 }
21263 return p;
21264 }
21265 // Gets the angle from vertical upright to the point about a centre.
21266 function getAngleFromPoint(centrePoint, anglePoint) {
21267 const distanceFromXCenter = anglePoint.x - centrePoint.x;
21268 const distanceFromYCenter = anglePoint.y - centrePoint.y;
21269 const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
21270 let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
21271 if (angle < -0.5 * PI) {
21272 angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
21273 }
21274 return {
21275 angle,
21276 distance: radialDistanceFromCenter
21277 };
21278 }
21279 function distanceBetweenPoints(pt1, pt2) {
21280 return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
21281 }
21282 /**
21283 * Shortest distance between angles, in either direction.
21284 * @private
21285 */ function _angleDiff(a, b) {
21286 return (a - b + PITAU) % TAU - PI;
21287 }
21288 /**
21289 * Normalize angle to be between 0 and 2*PI
21290 * @private
21291 */ function _normalizeAngle(a) {
21292 return (a % TAU + TAU) % TAU;
21293 }
21294 /**
21295 * @private
21296 */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
21297 const a = _normalizeAngle(angle);
21298 const s = _normalizeAngle(start);
21299 const e = _normalizeAngle(end);
21300 const angleToStart = _normalizeAngle(s - a);
21301 const angleToEnd = _normalizeAngle(e - a);
21302 const startToAngle = _normalizeAngle(a - s);
21303 const endToAngle = _normalizeAngle(a - e);
21304 return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;
21305 }
21306 /**
21307 * Limit `value` between `min` and `max`
21308 * @param value
21309 * @param min
21310 * @param max
21311 * @private
21312 */ function _limitValue(value, min, max) {
21313 return Math.max(min, Math.min(max, value));
21314 }
21315 /**
21316 * @param {number} value
21317 * @private
21318 */ function _int16Range(value) {
21319 return _limitValue(value, -32768, 32767);
21320 }
21321 /**
21322 * @param value
21323 * @param start
21324 * @param end
21325 * @param [epsilon]
21326 * @private
21327 */ function _isBetween(value, start, end, epsilon = 1e-6) {
21328 return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
21329 }
21330
21331 function _lookup(table, value, cmp) {
21332 cmp = cmp || ((index)=>table[index] < value);
21333 let hi = table.length - 1;
21334 let lo = 0;
21335 let mid;
21336 while(hi - lo > 1){
21337 mid = lo + hi >> 1;
21338 if (cmp(mid)) {
21339 lo = mid;
21340 } else {
21341 hi = mid;
21342 }
21343 }
21344 return {
21345 lo,
21346 hi
21347 };
21348 }
21349 /**
21350 * Binary search
21351 * @param table - the table search. must be sorted!
21352 * @param key - property name for the value in each entry
21353 * @param value - value to find
21354 * @param last - lookup last index
21355 * @private
21356 */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{
21357 const ti = table[index][key];
21358 return ti < value || ti === value && table[index + 1][key] === value;
21359 } : (index)=>table[index][key] < value);
21360 /**
21361 * Reverse binary search
21362 * @param table - the table search. must be sorted!
21363 * @param key - property name for the value in each entry
21364 * @param value - value to find
21365 * @private
21366 */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);
21367 /**
21368 * Return subset of `values` between `min` and `max` inclusive.
21369 * Values are assumed to be in sorted order.
21370 * @param values - sorted array of values
21371 * @param min - min value
21372 * @param max - max value
21373 */ function _filterBetween(values, min, max) {
21374 let start = 0;
21375 let end = values.length;
21376 while(start < end && values[start] < min){
21377 start++;
21378 }
21379 while(end > start && values[end - 1] > max){
21380 end--;
21381 }
21382 return start > 0 || end < values.length ? values.slice(start, end) : values;
21383 }
21384 const arrayEvents = [
21385 'push',
21386 'pop',
21387 'shift',
21388 'splice',
21389 'unshift'
21390 ];
21391 function listenArrayEvents(array, listener) {
21392 if (array._chartjs) {
21393 array._chartjs.listeners.push(listener);
21394 return;
21395 }
21396 Object.defineProperty(array, '_chartjs', {
21397 configurable: true,
21398 enumerable: false,
21399 value: {
21400 listeners: [
21401 listener
21402 ]
21403 }
21404 });
21405 arrayEvents.forEach((key)=>{
21406 const method = '_onData' + _capitalize(key);
21407 const base = array[key];
21408 Object.defineProperty(array, key, {
21409 configurable: true,
21410 enumerable: false,
21411 value (...args) {
21412 const res = base.apply(this, args);
21413 array._chartjs.listeners.forEach((object)=>{
21414 if (typeof object[method] === 'function') {
21415 object[method](...args);
21416 }
21417 });
21418 return res;
21419 }
21420 });
21421 });
21422 }
21423 function unlistenArrayEvents(array, listener) {
21424 const stub = array._chartjs;
21425 if (!stub) {
21426 return;
21427 }
21428 const listeners = stub.listeners;
21429 const index = listeners.indexOf(listener);
21430 if (index !== -1) {
21431 listeners.splice(index, 1);
21432 }
21433 if (listeners.length > 0) {
21434 return;
21435 }
21436 arrayEvents.forEach((key)=>{
21437 delete array[key];
21438 });
21439 delete array._chartjs;
21440 }
21441 /**
21442 * @param items
21443 */ function _arrayUnique(items) {
21444 const set = new Set(items);
21445 if (set.size === items.length) {
21446 return items;
21447 }
21448 return Array.from(set);
21449 }
21450
21451 function fontString(pixelSize, fontStyle, fontFamily) {
21452 return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
21453 }
21454 /**
21455 * Request animation polyfill
21456 */ const requestAnimFrame = function() {
21457 if (typeof window === 'undefined') {
21458 return function(callback) {
21459 return callback();
21460 };
21461 }
21462 return window.requestAnimationFrame;
21463 }();
21464 /**
21465 * Throttles calling `fn` once per animation frame
21466 * Latest arguments are used on the actual call
21467 */ function throttled(fn, thisArg) {
21468 let argsToUse = [];
21469 let ticking = false;
21470 return function(...args) {
21471 // Save the args for use later
21472 argsToUse = args;
21473 if (!ticking) {
21474 ticking = true;
21475 requestAnimFrame.call(window, ()=>{
21476 ticking = false;
21477 fn.apply(thisArg, argsToUse);
21478 });
21479 }
21480 };
21481 }
21482 /**
21483 * Debounces calling `fn` for `delay` ms
21484 */ function debounce(fn, delay) {
21485 let timeout;
21486 return function(...args) {
21487 if (delay) {
21488 clearTimeout(timeout);
21489 timeout = setTimeout(fn, delay, args);
21490 } else {
21491 fn.apply(this, args);
21492 }
21493 return delay;
21494 };
21495 }
21496 /**
21497 * Converts 'start' to 'left', 'end' to 'right' and others to 'center'
21498 * @private
21499 */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
21500 /**
21501 * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`
21502 * @private
21503 */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
21504 /**
21505 * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`
21506 * @private
21507 */ const _textX = (align, left, right, rtl)=>{
21508 const check = rtl ? 'left' : 'right';
21509 return align === check ? right : align === 'center' ? (left + right) / 2 : left;
21510 };
21511 /**
21512 * Return start and count of visible points.
21513 * @private
21514 */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
21515 const pointCount = points.length;
21516 let start = 0;
21517 let count = pointCount;
21518 if (meta._sorted) {
21519 const { iScale , vScale , _parsed } = meta;
21520 const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null;
21521 const axis = iScale.axis;
21522 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
21523 if (minDefined) {
21524 start = Math.min(// @ts-expect-error Need to type _parsed
21525 _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey
21526 animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo);
21527 if (spanGaps) {
21528 const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21529 start -= Math.max(0, distanceToDefinedLo);
21530 }
21531 start = _limitValue(start, 0, pointCount - 1);
21532 }
21533 if (maxDefined) {
21534 let end = Math.max(// @ts-expect-error Need to type _parsed
21535 _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey
21536 animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1);
21537 if (spanGaps) {
21538 const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21539 end += Math.max(0, distanceToDefinedHi);
21540 }
21541 count = _limitValue(end, start, pointCount) - start;
21542 } else {
21543 count = pointCount - start;
21544 }
21545 }
21546 return {
21547 start,
21548 count
21549 };
21550 }
21551 /**
21552 * Checks if the scale ranges have changed.
21553 * @param {object} meta - dataset meta.
21554 * @returns {boolean}
21555 * @private
21556 */ function _scaleRangesChanged(meta) {
21557 const { xScale , yScale , _scaleRanges } = meta;
21558 const newRanges = {
21559 xmin: xScale.min,
21560 xmax: xScale.max,
21561 ymin: yScale.min,
21562 ymax: yScale.max
21563 };
21564 if (!_scaleRanges) {
21565 meta._scaleRanges = newRanges;
21566 return true;
21567 }
21568 const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max;
21569 Object.assign(_scaleRanges, newRanges);
21570 return changed;
21571 }
21572
21573 const atEdge = (t)=>t === 0 || t === 1;
21574 const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
21575 const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
21576 /**
21577 * Easing functions adapted from Robert Penner's easing equations.
21578 * @namespace Chart.helpers.easing.effects
21579 * @see http://www.robertpenner.com/easing/
21580 */ const effects = {
21581 linear: (t)=>t,
21582 easeInQuad: (t)=>t * t,
21583 easeOutQuad: (t)=>-t * (t - 2),
21584 easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),
21585 easeInCubic: (t)=>t * t * t,
21586 easeOutCubic: (t)=>(t -= 1) * t * t + 1,
21587 easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),
21588 easeInQuart: (t)=>t * t * t * t,
21589 easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),
21590 easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),
21591 easeInQuint: (t)=>t * t * t * t * t,
21592 easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,
21593 easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),
21594 easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,
21595 easeOutSine: (t)=>Math.sin(t * HALF_PI),
21596 easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),
21597 easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
21598 easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,
21599 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),
21600 easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),
21601 easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),
21602 easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
21603 easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
21604 easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
21605 easeInOutElastic (t) {
21606 const s = 0.1125;
21607 const p = 0.45;
21608 return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
21609 },
21610 easeInBack (t) {
21611 const s = 1.70158;
21612 return t * t * ((s + 1) * t - s);
21613 },
21614 easeOutBack (t) {
21615 const s = 1.70158;
21616 return (t -= 1) * t * ((s + 1) * t + s) + 1;
21617 },
21618 easeInOutBack (t) {
21619 let s = 1.70158;
21620 if ((t /= 0.5) < 1) {
21621 return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
21622 }
21623 return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
21624 },
21625 easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),
21626 easeOutBounce (t) {
21627 const m = 7.5625;
21628 const d = 2.75;
21629 if (t < 1 / d) {
21630 return m * t * t;
21631 }
21632 if (t < 2 / d) {
21633 return m * (t -= 1.5 / d) * t + 0.75;
21634 }
21635 if (t < 2.5 / d) {
21636 return m * (t -= 2.25 / d) * t + 0.9375;
21637 }
21638 return m * (t -= 2.625 / d) * t + 0.984375;
21639 },
21640 easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5
21641 };
21642
21643 function isPatternOrGradient(value) {
21644 if (value && typeof value === 'object') {
21645 const type = value.toString();
21646 return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
21647 }
21648 return false;
21649 }
21650 function color(value) {
21651 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value);
21652 }
21653 function getHoverColor(value) {
21654 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value).saturate(0.5).darken(0.1).hexString();
21655 }
21656
21657 const numbers = [
21658 'x',
21659 'y',
21660 'borderWidth',
21661 'radius',
21662 'tension'
21663 ];
21664 const colors = [
21665 'color',
21666 'borderColor',
21667 'backgroundColor'
21668 ];
21669 function applyAnimationsDefaults(defaults) {
21670 defaults.set('animation', {
21671 delay: undefined,
21672 duration: 1000,
21673 easing: 'easeOutQuart',
21674 fn: undefined,
21675 from: undefined,
21676 loop: undefined,
21677 to: undefined,
21678 type: undefined
21679 });
21680 defaults.describe('animation', {
21681 _fallback: false,
21682 _indexable: false,
21683 _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'
21684 });
21685 defaults.set('animations', {
21686 colors: {
21687 type: 'color',
21688 properties: colors
21689 },
21690 numbers: {
21691 type: 'number',
21692 properties: numbers
21693 }
21694 });
21695 defaults.describe('animations', {
21696 _fallback: 'animation'
21697 });
21698 defaults.set('transitions', {
21699 active: {
21700 animation: {
21701 duration: 400
21702 }
21703 },
21704 resize: {
21705 animation: {
21706 duration: 0
21707 }
21708 },
21709 show: {
21710 animations: {
21711 colors: {
21712 from: 'transparent'
21713 },
21714 visible: {
21715 type: 'boolean',
21716 duration: 0
21717 }
21718 }
21719 },
21720 hide: {
21721 animations: {
21722 colors: {
21723 to: 'transparent'
21724 },
21725 visible: {
21726 type: 'boolean',
21727 easing: 'linear',
21728 fn: (v)=>v | 0
21729 }
21730 }
21731 }
21732 });
21733 }
21734
21735 function applyLayoutsDefaults(defaults) {
21736 defaults.set('layout', {
21737 autoPadding: true,
21738 padding: {
21739 top: 0,
21740 right: 0,
21741 bottom: 0,
21742 left: 0
21743 }
21744 });
21745 }
21746
21747 const intlCache = new Map();
21748 function getNumberFormat(locale, options) {
21749 options = options || {};
21750 const cacheKey = locale + JSON.stringify(options);
21751 let formatter = intlCache.get(cacheKey);
21752 if (!formatter) {
21753 formatter = new Intl.NumberFormat(locale, options);
21754 intlCache.set(cacheKey, formatter);
21755 }
21756 return formatter;
21757 }
21758 function formatNumber(num, locale, options) {
21759 return getNumberFormat(locale, options).format(num);
21760 }
21761
21762 const formatters = {
21763 values (value) {
21764 return isArray(value) ? value : '' + value;
21765 },
21766 numeric (tickValue, index, ticks) {
21767 if (tickValue === 0) {
21768 return '0';
21769 }
21770 const locale = this.chart.options.locale;
21771 let notation;
21772 let delta = tickValue;
21773 if (ticks.length > 1) {
21774 const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
21775 if (maxTick < 1e-4 || maxTick > 1e+15) {
21776 notation = 'scientific';
21777 }
21778 delta = calculateDelta(tickValue, ticks);
21779 }
21780 const logDelta = log10(Math.abs(delta));
21781 const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
21782 const options = {
21783 notation,
21784 minimumFractionDigits: numDecimal,
21785 maximumFractionDigits: numDecimal
21786 };
21787 Object.assign(options, this.options.ticks.format);
21788 return formatNumber(tickValue, locale, options);
21789 },
21790 logarithmic (tickValue, index, ticks) {
21791 if (tickValue === 0) {
21792 return '0';
21793 }
21794 const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
21795 if ([
21796 1,
21797 2,
21798 3,
21799 5,
21800 10,
21801 15
21802 ].includes(remain) || index > 0.8 * ticks.length) {
21803 return formatters.numeric.call(this, tickValue, index, ticks);
21804 }
21805 return '';
21806 }
21807 };
21808 function calculateDelta(tickValue, ticks) {
21809 let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
21810 if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
21811 delta = tickValue - Math.floor(tickValue);
21812 }
21813 return delta;
21814 }
21815 var Ticks = {
21816 formatters
21817 };
21818
21819 function applyScaleDefaults(defaults) {
21820 defaults.set('scale', {
21821 display: true,
21822 offset: false,
21823 reverse: false,
21824 beginAtZero: false,
21825 bounds: 'ticks',
21826 clip: true,
21827 grace: 0,
21828 grid: {
21829 display: true,
21830 lineWidth: 1,
21831 drawOnChartArea: true,
21832 drawTicks: true,
21833 tickLength: 8,
21834 tickWidth: (_ctx, options)=>options.lineWidth,
21835 tickColor: (_ctx, options)=>options.color,
21836 offset: false
21837 },
21838 border: {
21839 display: true,
21840 dash: [],
21841 dashOffset: 0.0,
21842 width: 1
21843 },
21844 title: {
21845 display: false,
21846 text: '',
21847 padding: {
21848 top: 4,
21849 bottom: 4
21850 }
21851 },
21852 ticks: {
21853 minRotation: 0,
21854 maxRotation: 50,
21855 mirror: false,
21856 textStrokeWidth: 0,
21857 textStrokeColor: '',
21858 padding: 3,
21859 display: true,
21860 autoSkip: true,
21861 autoSkipPadding: 3,
21862 labelOffset: 0,
21863 callback: Ticks.formatters.values,
21864 minor: {},
21865 major: {},
21866 align: 'center',
21867 crossAlign: 'near',
21868 showLabelBackdrop: false,
21869 backdropColor: 'rgba(255, 255, 255, 0.75)',
21870 backdropPadding: 2
21871 }
21872 });
21873 defaults.route('scale.ticks', 'color', '', 'color');
21874 defaults.route('scale.grid', 'color', '', 'borderColor');
21875 defaults.route('scale.border', 'color', '', 'borderColor');
21876 defaults.route('scale.title', 'color', '', 'color');
21877 defaults.describe('scale', {
21878 _fallback: false,
21879 _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
21880 _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'
21881 });
21882 defaults.describe('scales', {
21883 _fallback: 'scale'
21884 });
21885 defaults.describe('scale.ticks', {
21886 _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',
21887 _indexable: (name)=>name !== 'backdropPadding'
21888 });
21889 }
21890
21891 const overrides = Object.create(null);
21892 const descriptors = Object.create(null);
21893 function getScope$1(node, key) {
21894 if (!key) {
21895 return node;
21896 }
21897 const keys = key.split('.');
21898 for(let i = 0, n = keys.length; i < n; ++i){
21899 const k = keys[i];
21900 node = node[k] || (node[k] = Object.create(null));
21901 }
21902 return node;
21903 }
21904 function set(root, scope, values) {
21905 if (typeof scope === 'string') {
21906 return merge(getScope$1(root, scope), values);
21907 }
21908 return merge(getScope$1(root, ''), scope);
21909 }
21910 class Defaults {
21911 constructor(_descriptors, _appliers){
21912 this.animation = undefined;
21913 this.backgroundColor = 'rgba(0,0,0,0.1)';
21914 this.borderColor = 'rgba(0,0,0,0.1)';
21915 this.color = '#666';
21916 this.datasets = {};
21917 this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio();
21918 this.elements = {};
21919 this.events = [
21920 'mousemove',
21921 'mouseout',
21922 'click',
21923 'touchstart',
21924 'touchmove'
21925 ];
21926 this.font = {
21927 family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
21928 size: 12,
21929 style: 'normal',
21930 lineHeight: 1.2,
21931 weight: null
21932 };
21933 this.hover = {};
21934 this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor);
21935 this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor);
21936 this.hoverColor = (ctx, options)=>getHoverColor(options.color);
21937 this.indexAxis = 'x';
21938 this.interaction = {
21939 mode: 'nearest',
21940 intersect: true,
21941 includeInvisible: false
21942 };
21943 this.maintainAspectRatio = true;
21944 this.onHover = null;
21945 this.onClick = null;
21946 this.parsing = true;
21947 this.plugins = {};
21948 this.responsive = true;
21949 this.scale = undefined;
21950 this.scales = {};
21951 this.showLine = true;
21952 this.drawActiveElementsOnTop = true;
21953 this.describe(_descriptors);
21954 this.apply(_appliers);
21955 }
21956 set(scope, values) {
21957 return set(this, scope, values);
21958 }
21959 get(scope) {
21960 return getScope$1(this, scope);
21961 }
21962 describe(scope, values) {
21963 return set(descriptors, scope, values);
21964 }
21965 override(scope, values) {
21966 return set(overrides, scope, values);
21967 }
21968 route(scope, name, targetScope, targetName) {
21969 const scopeObject = getScope$1(this, scope);
21970 const targetScopeObject = getScope$1(this, targetScope);
21971 const privateName = '_' + name;
21972 Object.defineProperties(scopeObject, {
21973 [privateName]: {
21974 value: scopeObject[name],
21975 writable: true
21976 },
21977 [name]: {
21978 enumerable: true,
21979 get () {
21980 const local = this[privateName];
21981 const target = targetScopeObject[targetName];
21982 if (isObject(local)) {
21983 return Object.assign({}, target, local);
21984 }
21985 return valueOrDefault(local, target);
21986 },
21987 set (value) {
21988 this[privateName] = value;
21989 }
21990 }
21991 });
21992 }
21993 apply(appliers) {
21994 appliers.forEach((apply)=>apply(this));
21995 }
21996 }
21997 var defaults = /* #__PURE__ */ new Defaults({
21998 _scriptable: (name)=>!name.startsWith('on'),
21999 _indexable: (name)=>name !== 'events',
22000 hover: {
22001 _fallback: 'interaction'
22002 },
22003 interaction: {
22004 _scriptable: false,
22005 _indexable: false
22006 }
22007 }, [
22008 applyAnimationsDefaults,
22009 applyLayoutsDefaults,
22010 applyScaleDefaults
22011 ]);
22012
22013 /**
22014 * Converts the given font object into a CSS font string.
22015 * @param font - A font object.
22016 * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
22017 * @private
22018 */ function toFontString(font) {
22019 if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
22020 return null;
22021 }
22022 return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family;
22023 }
22024 /**
22025 * @private
22026 */ function _measureText(ctx, data, gc, longest, string) {
22027 let textWidth = data[string];
22028 if (!textWidth) {
22029 textWidth = data[string] = ctx.measureText(string).width;
22030 gc.push(string);
22031 }
22032 if (textWidth > longest) {
22033 longest = textWidth;
22034 }
22035 return longest;
22036 }
22037 /**
22038 * @private
22039 */ // eslint-disable-next-line complexity
22040 function _longestText(ctx, font, arrayOfThings, cache) {
22041 cache = cache || {};
22042 let data = cache.data = cache.data || {};
22043 let gc = cache.garbageCollect = cache.garbageCollect || [];
22044 if (cache.font !== font) {
22045 data = cache.data = {};
22046 gc = cache.garbageCollect = [];
22047 cache.font = font;
22048 }
22049 ctx.save();
22050 ctx.font = font;
22051 let longest = 0;
22052 const ilen = arrayOfThings.length;
22053 let i, j, jlen, thing, nestedThing;
22054 for(i = 0; i < ilen; i++){
22055 thing = arrayOfThings[i];
22056 // Undefined strings and arrays should not be measured
22057 if (thing !== undefined && thing !== null && !isArray(thing)) {
22058 longest = _measureText(ctx, data, gc, longest, thing);
22059 } else if (isArray(thing)) {
22060 // if it is an array lets measure each element
22061 // to do maybe simplify this function a bit so we can do this more recursively?
22062 for(j = 0, jlen = thing.length; j < jlen; j++){
22063 nestedThing = thing[j];
22064 // Undefined strings and arrays should not be measured
22065 if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
22066 longest = _measureText(ctx, data, gc, longest, nestedThing);
22067 }
22068 }
22069 }
22070 }
22071 ctx.restore();
22072 const gcLen = gc.length / 2;
22073 if (gcLen > arrayOfThings.length) {
22074 for(i = 0; i < gcLen; i++){
22075 delete data[gc[i]];
22076 }
22077 gc.splice(0, gcLen);
22078 }
22079 return longest;
22080 }
22081 /**
22082 * Returns the aligned pixel value to avoid anti-aliasing blur
22083 * @param chart - The chart instance.
22084 * @param pixel - A pixel value.
22085 * @param width - The width of the element.
22086 * @returns The aligned pixel value.
22087 * @private
22088 */ function _alignPixel(chart, pixel, width) {
22089 const devicePixelRatio = chart.currentDevicePixelRatio;
22090 const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
22091 return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
22092 }
22093 /**
22094 * Clears the entire canvas.
22095 */ function clearCanvas(canvas, ctx) {
22096 if (!ctx && !canvas) {
22097 return;
22098 }
22099 ctx = ctx || canvas.getContext('2d');
22100 ctx.save();
22101 // canvas.width and canvas.height do not consider the canvas transform,
22102 // while clearRect does
22103 ctx.resetTransform();
22104 ctx.clearRect(0, 0, canvas.width, canvas.height);
22105 ctx.restore();
22106 }
22107 function drawPoint(ctx, options, x, y) {
22108 // eslint-disable-next-line @typescript-eslint/no-use-before-define
22109 drawPointLegend(ctx, options, x, y, null);
22110 }
22111 // eslint-disable-next-line complexity
22112 function drawPointLegend(ctx, options, x, y, w) {
22113 let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;
22114 const style = options.pointStyle;
22115 const rotation = options.rotation;
22116 const radius = options.radius;
22117 let rad = (rotation || 0) * RAD_PER_DEG;
22118 if (style && typeof style === 'object') {
22119 type = style.toString();
22120 if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
22121 ctx.save();
22122 ctx.translate(x, y);
22123 ctx.rotate(rad);
22124 ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
22125 ctx.restore();
22126 return;
22127 }
22128 }
22129 if (isNaN(radius) || radius <= 0) {
22130 return;
22131 }
22132 ctx.beginPath();
22133 switch(style){
22134 // Default includes circle
22135 default:
22136 if (w) {
22137 ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);
22138 } else {
22139 ctx.arc(x, y, radius, 0, TAU);
22140 }
22141 ctx.closePath();
22142 break;
22143 case 'triangle':
22144 width = w ? w / 2 : radius;
22145 ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22146 rad += TWO_THIRDS_PI;
22147 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22148 rad += TWO_THIRDS_PI;
22149 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22150 ctx.closePath();
22151 break;
22152 case 'rectRounded':
22153 // NOTE: the rounded rect implementation changed to use `arc` instead of
22154 // `quadraticCurveTo` since it generates better results when rect is
22155 // almost a circle. 0.516 (instead of 0.5) produces results with visually
22156 // closer proportion to the previous impl and it is inscribed in the
22157 // circle with `radius`. For more details, see the following PRs:
22158 // https://github.com/chartjs/Chart.js/issues/5597
22159 // https://github.com/chartjs/Chart.js/issues/5858
22160 cornerRadius = radius * 0.516;
22161 size = radius - cornerRadius;
22162 xOffset = Math.cos(rad + QUARTER_PI) * size;
22163 xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22164 yOffset = Math.sin(rad + QUARTER_PI) * size;
22165 yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22166 ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
22167 ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);
22168 ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);
22169 ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
22170 ctx.closePath();
22171 break;
22172 case 'rect':
22173 if (!rotation) {
22174 size = Math.SQRT1_2 * radius;
22175 width = w ? w / 2 : size;
22176 ctx.rect(x - width, y - size, 2 * width, 2 * size);
22177 break;
22178 }
22179 rad += QUARTER_PI;
22180 /* falls through */ case 'rectRot':
22181 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22182 xOffset = Math.cos(rad) * radius;
22183 yOffset = Math.sin(rad) * radius;
22184 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22185 ctx.moveTo(x - xOffsetW, y - yOffset);
22186 ctx.lineTo(x + yOffsetW, y - xOffset);
22187 ctx.lineTo(x + xOffsetW, y + yOffset);
22188 ctx.lineTo(x - yOffsetW, y + xOffset);
22189 ctx.closePath();
22190 break;
22191 case 'crossRot':
22192 rad += QUARTER_PI;
22193 /* falls through */ case 'cross':
22194 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22195 xOffset = Math.cos(rad) * radius;
22196 yOffset = Math.sin(rad) * radius;
22197 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22198 ctx.moveTo(x - xOffsetW, y - yOffset);
22199 ctx.lineTo(x + xOffsetW, y + yOffset);
22200 ctx.moveTo(x + yOffsetW, y - xOffset);
22201 ctx.lineTo(x - yOffsetW, y + xOffset);
22202 break;
22203 case 'star':
22204 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22205 xOffset = Math.cos(rad) * radius;
22206 yOffset = Math.sin(rad) * radius;
22207 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22208 ctx.moveTo(x - xOffsetW, y - yOffset);
22209 ctx.lineTo(x + xOffsetW, y + yOffset);
22210 ctx.moveTo(x + yOffsetW, y - xOffset);
22211 ctx.lineTo(x - yOffsetW, y + xOffset);
22212 rad += QUARTER_PI;
22213 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22214 xOffset = Math.cos(rad) * radius;
22215 yOffset = Math.sin(rad) * radius;
22216 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22217 ctx.moveTo(x - xOffsetW, y - yOffset);
22218 ctx.lineTo(x + xOffsetW, y + yOffset);
22219 ctx.moveTo(x + yOffsetW, y - xOffset);
22220 ctx.lineTo(x - yOffsetW, y + xOffset);
22221 break;
22222 case 'line':
22223 xOffset = w ? w / 2 : Math.cos(rad) * radius;
22224 yOffset = Math.sin(rad) * radius;
22225 ctx.moveTo(x - xOffset, y - yOffset);
22226 ctx.lineTo(x + xOffset, y + yOffset);
22227 break;
22228 case 'dash':
22229 ctx.moveTo(x, y);
22230 ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);
22231 break;
22232 case false:
22233 ctx.closePath();
22234 break;
22235 }
22236 ctx.fill();
22237 if (options.borderWidth > 0) {
22238 ctx.stroke();
22239 }
22240 }
22241 /**
22242 * Returns true if the point is inside the rectangle
22243 * @param point - The point to test
22244 * @param area - The rectangle
22245 * @param margin - allowed margin
22246 * @private
22247 */ function _isPointInArea(point, area, margin) {
22248 margin = margin || 0.5; // margin - default is to match rounded decimals
22249 return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;
22250 }
22251 function clipArea(ctx, area) {
22252 ctx.save();
22253 ctx.beginPath();
22254 ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
22255 ctx.clip();
22256 }
22257 function unclipArea(ctx) {
22258 ctx.restore();
22259 }
22260 /**
22261 * @private
22262 */ function _steppedLineTo(ctx, previous, target, flip, mode) {
22263 if (!previous) {
22264 return ctx.lineTo(target.x, target.y);
22265 }
22266 if (mode === 'middle') {
22267 const midpoint = (previous.x + target.x) / 2.0;
22268 ctx.lineTo(midpoint, previous.y);
22269 ctx.lineTo(midpoint, target.y);
22270 } else if (mode === 'after' !== !!flip) {
22271 ctx.lineTo(previous.x, target.y);
22272 } else {
22273 ctx.lineTo(target.x, previous.y);
22274 }
22275 ctx.lineTo(target.x, target.y);
22276 }
22277 /**
22278 * @private
22279 */ function _bezierCurveTo(ctx, previous, target, flip) {
22280 if (!previous) {
22281 return ctx.lineTo(target.x, target.y);
22282 }
22283 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);
22284 }
22285 function setRenderOpts(ctx, opts) {
22286 if (opts.translation) {
22287 ctx.translate(opts.translation[0], opts.translation[1]);
22288 }
22289 if (!isNullOrUndef(opts.rotation)) {
22290 ctx.rotate(opts.rotation);
22291 }
22292 if (opts.color) {
22293 ctx.fillStyle = opts.color;
22294 }
22295 if (opts.textAlign) {
22296 ctx.textAlign = opts.textAlign;
22297 }
22298 if (opts.textBaseline) {
22299 ctx.textBaseline = opts.textBaseline;
22300 }
22301 }
22302 function decorateText(ctx, x, y, line, opts) {
22303 if (opts.strikethrough || opts.underline) {
22304 /**
22305 * Now that IE11 support has been dropped, we can use more
22306 * of the TextMetrics object. The actual bounding boxes
22307 * are unflagged in Chrome, Firefox, Edge, and Safari so they
22308 * can be safely used.
22309 * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
22310 */ const metrics = ctx.measureText(line);
22311 const left = x - metrics.actualBoundingBoxLeft;
22312 const right = x + metrics.actualBoundingBoxRight;
22313 const top = y - metrics.actualBoundingBoxAscent;
22314 const bottom = y + metrics.actualBoundingBoxDescent;
22315 const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
22316 ctx.strokeStyle = ctx.fillStyle;
22317 ctx.beginPath();
22318 ctx.lineWidth = opts.decorationWidth || 2;
22319 ctx.moveTo(left, yDecoration);
22320 ctx.lineTo(right, yDecoration);
22321 ctx.stroke();
22322 }
22323 }
22324 function drawBackdrop(ctx, opts) {
22325 const oldColor = ctx.fillStyle;
22326 ctx.fillStyle = opts.color;
22327 ctx.fillRect(opts.left, opts.top, opts.width, opts.height);
22328 ctx.fillStyle = oldColor;
22329 }
22330 /**
22331 * Render text onto the canvas
22332 */ function renderText(ctx, text, x, y, font, opts = {}) {
22333 const lines = isArray(text) ? text : [
22334 text
22335 ];
22336 const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
22337 let i, line;
22338 ctx.save();
22339 ctx.font = font.string;
22340 setRenderOpts(ctx, opts);
22341 for(i = 0; i < lines.length; ++i){
22342 line = lines[i];
22343 if (opts.backdrop) {
22344 drawBackdrop(ctx, opts.backdrop);
22345 }
22346 if (stroke) {
22347 if (opts.strokeColor) {
22348 ctx.strokeStyle = opts.strokeColor;
22349 }
22350 if (!isNullOrUndef(opts.strokeWidth)) {
22351 ctx.lineWidth = opts.strokeWidth;
22352 }
22353 ctx.strokeText(line, x, y, opts.maxWidth);
22354 }
22355 ctx.fillText(line, x, y, opts.maxWidth);
22356 decorateText(ctx, x, y, line, opts);
22357 y += Number(font.lineHeight);
22358 }
22359 ctx.restore();
22360 }
22361 /**
22362 * Add a path of a rectangle with rounded corners to the current sub-path
22363 * @param ctx - Context
22364 * @param rect - Bounding rect
22365 */ function addRoundedRectPath(ctx, rect) {
22366 const { x , y , w , h , radius } = rect;
22367 // top left arc
22368 ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
22369 // line from top left to bottom left
22370 ctx.lineTo(x, y + h - radius.bottomLeft);
22371 // bottom left arc
22372 ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
22373 // line from bottom left to bottom right
22374 ctx.lineTo(x + w - radius.bottomRight, y + h);
22375 // bottom right arc
22376 ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
22377 // line from bottom right to top right
22378 ctx.lineTo(x + w, y + radius.topRight);
22379 // top right arc
22380 ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
22381 // line from top right to top left
22382 ctx.lineTo(x + radius.topLeft, y);
22383 }
22384
22385 const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
22386 const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
22387 /**
22388 * @alias Chart.helpers.options
22389 * @namespace
22390 */ /**
22391 * Converts the given line height `value` in pixels for a specific font `size`.
22392 * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
22393 * @param size - The font size (in pixels) used to resolve relative `value`.
22394 * @returns The effective line height in pixels (size * 1.2 if value is invalid).
22395 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
22396 * @since 2.7.0
22397 */ function toLineHeight(value, size) {
22398 const matches = ('' + value).match(LINE_HEIGHT);
22399 if (!matches || matches[1] === 'normal') {
22400 return size * 1.2;
22401 }
22402 value = +matches[2];
22403 switch(matches[3]){
22404 case 'px':
22405 return value;
22406 case '%':
22407 value /= 100;
22408 break;
22409 }
22410 return size * value;
22411 }
22412 const numberOrZero = (v)=>+v || 0;
22413 function _readValueToProps(value, props) {
22414 const ret = {};
22415 const objProps = isObject(props);
22416 const keys = objProps ? Object.keys(props) : props;
22417 const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value;
22418 for (const prop of keys){
22419 ret[prop] = numberOrZero(read(prop));
22420 }
22421 return ret;
22422 }
22423 /**
22424 * Converts the given value into a TRBL object.
22425 * @param value - If a number, set the value to all TRBL component,
22426 * else, if an object, use defined properties and sets undefined ones to 0.
22427 * x / y are shorthands for same value for left/right and top/bottom.
22428 * @returns The padding values (top, right, bottom, left)
22429 * @since 3.0.0
22430 */ function toTRBL(value) {
22431 return _readValueToProps(value, {
22432 top: 'y',
22433 right: 'x',
22434 bottom: 'y',
22435 left: 'x'
22436 });
22437 }
22438 /**
22439 * Converts the given value into a TRBL corners object (similar with css border-radius).
22440 * @param value - If a number, set the value to all TRBL corner components,
22441 * else, if an object, use defined properties and sets undefined ones to 0.
22442 * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)
22443 * @since 3.0.0
22444 */ function toTRBLCorners(value) {
22445 return _readValueToProps(value, [
22446 'topLeft',
22447 'topRight',
22448 'bottomLeft',
22449 'bottomRight'
22450 ]);
22451 }
22452 /**
22453 * Converts the given value into a padding object with pre-computed width/height.
22454 * @param value - If a number, set the value to all TRBL component,
22455 * else, if an object, use defined properties and sets undefined ones to 0.
22456 * x / y are shorthands for same value for left/right and top/bottom.
22457 * @returns The padding values (top, right, bottom, left, width, height)
22458 * @since 2.7.0
22459 */ function toPadding(value) {
22460 const obj = toTRBL(value);
22461 obj.width = obj.left + obj.right;
22462 obj.height = obj.top + obj.bottom;
22463 return obj;
22464 }
22465 /**
22466 * Parses font options and returns the font object.
22467 * @param options - A object that contains font options to be parsed.
22468 * @param fallback - A object that contains fallback font options.
22469 * @return The font object.
22470 * @private
22471 */ function toFont(options, fallback) {
22472 options = options || {};
22473 fallback = fallback || defaults.font;
22474 let size = valueOrDefault(options.size, fallback.size);
22475 if (typeof size === 'string') {
22476 size = parseInt(size, 10);
22477 }
22478 let style = valueOrDefault(options.style, fallback.style);
22479 if (style && !('' + style).match(FONT_STYLE)) {
22480 console.warn('Invalid font style specified: "' + style + '"');
22481 style = undefined;
22482 }
22483 const font = {
22484 family: valueOrDefault(options.family, fallback.family),
22485 lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
22486 size,
22487 style,
22488 weight: valueOrDefault(options.weight, fallback.weight),
22489 string: ''
22490 };
22491 font.string = toFontString(font);
22492 return font;
22493 }
22494 /**
22495 * Evaluates the given `inputs` sequentially and returns the first defined value.
22496 * @param inputs - An array of values, falling back to the last value.
22497 * @param context - If defined and the current value is a function, the value
22498 * is called with `context` as first argument and the result becomes the new input.
22499 * @param index - If defined and the current value is an array, the value
22500 * at `index` become the new input.
22501 * @param info - object to return information about resolution in
22502 * @param info.cacheable - Will be set to `false` if option is not cacheable.
22503 * @since 2.7.0
22504 */ function resolve(inputs, context, index, info) {
22505 let cacheable = true;
22506 let i, ilen, value;
22507 for(i = 0, ilen = inputs.length; i < ilen; ++i){
22508 value = inputs[i];
22509 if (value === undefined) {
22510 continue;
22511 }
22512 if (context !== undefined && typeof value === 'function') {
22513 value = value(context);
22514 cacheable = false;
22515 }
22516 if (index !== undefined && isArray(value)) {
22517 value = value[index % value.length];
22518 cacheable = false;
22519 }
22520 if (value !== undefined) {
22521 if (info && !cacheable) {
22522 info.cacheable = false;
22523 }
22524 return value;
22525 }
22526 }
22527 }
22528 /**
22529 * @param minmax
22530 * @param grace
22531 * @param beginAtZero
22532 * @private
22533 */ function _addGrace(minmax, grace, beginAtZero) {
22534 const { min , max } = minmax;
22535 const change = toDimension(grace, (max - min) / 2);
22536 const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;
22537 return {
22538 min: keepZero(min, -Math.abs(change)),
22539 max: keepZero(max, change)
22540 };
22541 }
22542 function createContext(parentContext, context) {
22543 return Object.assign(Object.create(parentContext), context);
22544 }
22545
22546 /**
22547 * Creates a Proxy for resolving raw values for options.
22548 * @param scopes - The option scopes to look for values, in resolution order
22549 * @param prefixes - The prefixes for values, in resolution order.
22550 * @param rootScopes - The root option scopes
22551 * @param fallback - Parent scopes fallback
22552 * @param getTarget - callback for getting the target for changed values
22553 * @returns Proxy
22554 * @private
22555 */ function _createResolver(scopes, prefixes = [
22556 ''
22557 ], rootScopes, fallback, getTarget = ()=>scopes[0]) {
22558 const finalRootScopes = rootScopes || scopes;
22559 if (typeof fallback === 'undefined') {
22560 fallback = _resolve('_fallback', scopes);
22561 }
22562 const cache = {
22563 [Symbol.toStringTag]: 'Object',
22564 _cacheable: true,
22565 _scopes: scopes,
22566 _rootScopes: finalRootScopes,
22567 _fallback: fallback,
22568 _getTarget: getTarget,
22569 override: (scope)=>_createResolver([
22570 scope,
22571 ...scopes
22572 ], prefixes, finalRootScopes, fallback)
22573 };
22574 return new Proxy(cache, {
22575 /**
22576 * A trap for the delete operator.
22577 */ deleteProperty (target, prop) {
22578 delete target[prop]; // remove from cache
22579 delete target._keys; // remove cached keys
22580 delete scopes[0][prop]; // remove from top level scope
22581 return true;
22582 },
22583 /**
22584 * A trap for getting property values.
22585 */ get (target, prop) {
22586 return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));
22587 },
22588 /**
22589 * A trap for Object.getOwnPropertyDescriptor.
22590 * Also used by Object.hasOwnProperty.
22591 */ getOwnPropertyDescriptor (target, prop) {
22592 return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
22593 },
22594 /**
22595 * A trap for Object.getPrototypeOf.
22596 */ getPrototypeOf () {
22597 return Reflect.getPrototypeOf(scopes[0]);
22598 },
22599 /**
22600 * A trap for the in operator.
22601 */ has (target, prop) {
22602 return getKeysFromAllScopes(target).includes(prop);
22603 },
22604 /**
22605 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22606 */ ownKeys (target) {
22607 return getKeysFromAllScopes(target);
22608 },
22609 /**
22610 * A trap for setting property values.
22611 */ set (target, prop, value) {
22612 const storage = target._storage || (target._storage = getTarget());
22613 target[prop] = storage[prop] = value; // set to top level scope + cache
22614 delete target._keys; // remove cached keys
22615 return true;
22616 }
22617 });
22618 }
22619 /**
22620 * Returns an Proxy for resolving option values with context.
22621 * @param proxy - The Proxy returned by `_createResolver`
22622 * @param context - Context object for scriptable/indexable options
22623 * @param subProxy - The proxy provided for scriptable options
22624 * @param descriptorDefaults - Defaults for descriptors
22625 * @private
22626 */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {
22627 const cache = {
22628 _cacheable: false,
22629 _proxy: proxy,
22630 _context: context,
22631 _subProxy: subProxy,
22632 _stack: new Set(),
22633 _descriptors: _descriptors(proxy, descriptorDefaults),
22634 setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),
22635 override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
22636 };
22637 return new Proxy(cache, {
22638 /**
22639 * A trap for the delete operator.
22640 */ deleteProperty (target, prop) {
22641 delete target[prop]; // remove from cache
22642 delete proxy[prop]; // remove from proxy
22643 return true;
22644 },
22645 /**
22646 * A trap for getting property values.
22647 */ get (target, prop, receiver) {
22648 return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));
22649 },
22650 /**
22651 * A trap for Object.getOwnPropertyDescriptor.
22652 * Also used by Object.hasOwnProperty.
22653 */ getOwnPropertyDescriptor (target, prop) {
22654 return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
22655 enumerable: true,
22656 configurable: true
22657 } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);
22658 },
22659 /**
22660 * A trap for Object.getPrototypeOf.
22661 */ getPrototypeOf () {
22662 return Reflect.getPrototypeOf(proxy);
22663 },
22664 /**
22665 * A trap for the in operator.
22666 */ has (target, prop) {
22667 return Reflect.has(proxy, prop);
22668 },
22669 /**
22670 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22671 */ ownKeys () {
22672 return Reflect.ownKeys(proxy);
22673 },
22674 /**
22675 * A trap for setting property values.
22676 */ set (target, prop, value) {
22677 proxy[prop] = value; // set to proxy
22678 delete target[prop]; // remove from cache
22679 return true;
22680 }
22681 });
22682 }
22683 /**
22684 * @private
22685 */ function _descriptors(proxy, defaults = {
22686 scriptable: true,
22687 indexable: true
22688 }) {
22689 const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;
22690 return {
22691 allKeys: _allKeys,
22692 scriptable: _scriptable,
22693 indexable: _indexable,
22694 isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,
22695 isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable
22696 };
22697 }
22698 const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;
22699 const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);
22700 function _cached(target, prop, resolve) {
22701 if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {
22702 return target[prop];
22703 }
22704 const value = resolve();
22705 // cache the resolved value
22706 target[prop] = value;
22707 return value;
22708 }
22709 function _resolveWithContext(target, prop, receiver) {
22710 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22711 let value = _proxy[prop]; // resolve from proxy
22712 // resolve with context
22713 if (isFunction(value) && descriptors.isScriptable(prop)) {
22714 value = _resolveScriptable(prop, value, target, receiver);
22715 }
22716 if (isArray(value) && value.length) {
22717 value = _resolveArray(prop, value, target, descriptors.isIndexable);
22718 }
22719 if (needsSubResolver(prop, value)) {
22720 // if the resolved value is an object, create a sub resolver for it
22721 value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
22722 }
22723 return value;
22724 }
22725 function _resolveScriptable(prop, getValue, target, receiver) {
22726 const { _proxy , _context , _subProxy , _stack } = target;
22727 if (_stack.has(prop)) {
22728 throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
22729 }
22730 _stack.add(prop);
22731 let value = getValue(_context, _subProxy || receiver);
22732 _stack.delete(prop);
22733 if (needsSubResolver(prop, value)) {
22734 // When scriptable option returns an object, create a resolver on that.
22735 value = createSubResolver(_proxy._scopes, _proxy, prop, value);
22736 }
22737 return value;
22738 }
22739 function _resolveArray(prop, value, target, isIndexable) {
22740 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22741 if (typeof _context.index !== 'undefined' && isIndexable(prop)) {
22742 return value[_context.index % value.length];
22743 } else if (isObject(value[0])) {
22744 // Array of objects, return array or resolvers
22745 const arr = value;
22746 const scopes = _proxy._scopes.filter((s)=>s !== arr);
22747 value = [];
22748 for (const item of arr){
22749 const resolver = createSubResolver(scopes, _proxy, prop, item);
22750 value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
22751 }
22752 }
22753 return value;
22754 }
22755 function resolveFallback(fallback, prop, value) {
22756 return isFunction(fallback) ? fallback(prop, value) : fallback;
22757 }
22758 const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
22759 function addScopes(set, parentScopes, key, parentFallback, value) {
22760 for (const parent of parentScopes){
22761 const scope = getScope(key, parent);
22762 if (scope) {
22763 set.add(scope);
22764 const fallback = resolveFallback(scope._fallback, key, value);
22765 if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {
22766 // When we reach the descriptor that defines a new _fallback, return that.
22767 // The fallback will resume to that new scope.
22768 return fallback;
22769 }
22770 } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {
22771 // Fallback to `false` results to `false`, when falling back to different key.
22772 // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`
22773 return null;
22774 }
22775 }
22776 return false;
22777 }
22778 function createSubResolver(parentScopes, resolver, prop, value) {
22779 const rootScopes = resolver._rootScopes;
22780 const fallback = resolveFallback(resolver._fallback, prop, value);
22781 const allScopes = [
22782 ...parentScopes,
22783 ...rootScopes
22784 ];
22785 const set = new Set();
22786 set.add(value);
22787 let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
22788 if (key === null) {
22789 return false;
22790 }
22791 if (typeof fallback !== 'undefined' && fallback !== prop) {
22792 key = addScopesFromKey(set, allScopes, fallback, key, value);
22793 if (key === null) {
22794 return false;
22795 }
22796 }
22797 return _createResolver(Array.from(set), [
22798 ''
22799 ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));
22800 }
22801 function addScopesFromKey(set, allScopes, key, fallback, item) {
22802 while(key){
22803 key = addScopes(set, allScopes, key, fallback, item);
22804 }
22805 return key;
22806 }
22807 function subGetTarget(resolver, prop, value) {
22808 const parent = resolver._getTarget();
22809 if (!(prop in parent)) {
22810 parent[prop] = {};
22811 }
22812 const target = parent[prop];
22813 if (isArray(target) && isObject(value)) {
22814 // For array of objects, the object is used to store updated values
22815 return value;
22816 }
22817 return target || {};
22818 }
22819 function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
22820 let value;
22821 for (const prefix of prefixes){
22822 value = _resolve(readKey(prefix, prop), scopes);
22823 if (typeof value !== 'undefined') {
22824 return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
22825 }
22826 }
22827 }
22828 function _resolve(key, scopes) {
22829 for (const scope of scopes){
22830 if (!scope) {
22831 continue;
22832 }
22833 const value = scope[key];
22834 if (typeof value !== 'undefined') {
22835 return value;
22836 }
22837 }
22838 }
22839 function getKeysFromAllScopes(target) {
22840 let keys = target._keys;
22841 if (!keys) {
22842 keys = target._keys = resolveKeysFromAllScopes(target._scopes);
22843 }
22844 return keys;
22845 }
22846 function resolveKeysFromAllScopes(scopes) {
22847 const set = new Set();
22848 for (const scope of scopes){
22849 for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){
22850 set.add(key);
22851 }
22852 }
22853 return Array.from(set);
22854 }
22855 function _parseObjectDataRadialScale(meta, data, start, count) {
22856 const { iScale } = meta;
22857 const { key ='r' } = this._parsing;
22858 const parsed = new Array(count);
22859 let i, ilen, index, item;
22860 for(i = 0, ilen = count; i < ilen; ++i){
22861 index = i + start;
22862 item = data[index];
22863 parsed[i] = {
22864 r: iScale.parse(resolveObjectKey(item, key), index)
22865 };
22866 }
22867 return parsed;
22868 }
22869
22870 const EPSILON = Number.EPSILON || 1e-14;
22871 const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];
22872 const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';
22873 function splineCurve(firstPoint, middlePoint, afterPoint, t) {
22874 // Props to Rob Spencer at scaled innovation for his post on splining between points
22875 // http://scaledinnovation.com/analytics/splines/aboutSplines.html
22876 // This function must also respect "skipped" points
22877 const previous = firstPoint.skip ? middlePoint : firstPoint;
22878 const current = middlePoint;
22879 const next = afterPoint.skip ? middlePoint : afterPoint;
22880 const d01 = distanceBetweenPoints(current, previous);
22881 const d12 = distanceBetweenPoints(next, current);
22882 let s01 = d01 / (d01 + d12);
22883 let s12 = d12 / (d01 + d12);
22884 // If all points are the same, s01 & s02 will be inf
22885 s01 = isNaN(s01) ? 0 : s01;
22886 s12 = isNaN(s12) ? 0 : s12;
22887 const fa = t * s01; // scaling factor for triangle Ta
22888 const fb = t * s12;
22889 return {
22890 previous: {
22891 x: current.x - fa * (next.x - previous.x),
22892 y: current.y - fa * (next.y - previous.y)
22893 },
22894 next: {
22895 x: current.x + fb * (next.x - previous.x),
22896 y: current.y + fb * (next.y - previous.y)
22897 }
22898 };
22899 }
22900 /**
22901 * Adjust tangents to ensure monotonic properties
22902 */ function monotoneAdjust(points, deltaK, mK) {
22903 const pointsLen = points.length;
22904 let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
22905 let pointAfter = getPoint(points, 0);
22906 for(let i = 0; i < pointsLen - 1; ++i){
22907 pointCurrent = pointAfter;
22908 pointAfter = getPoint(points, i + 1);
22909 if (!pointCurrent || !pointAfter) {
22910 continue;
22911 }
22912 if (almostEquals(deltaK[i], 0, EPSILON)) {
22913 mK[i] = mK[i + 1] = 0;
22914 continue;
22915 }
22916 alphaK = mK[i] / deltaK[i];
22917 betaK = mK[i + 1] / deltaK[i];
22918 squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
22919 if (squaredMagnitude <= 9) {
22920 continue;
22921 }
22922 tauK = 3 / Math.sqrt(squaredMagnitude);
22923 mK[i] = alphaK * tauK * deltaK[i];
22924 mK[i + 1] = betaK * tauK * deltaK[i];
22925 }
22926 }
22927 function monotoneCompute(points, mK, indexAxis = 'x') {
22928 const valueAxis = getValueAxis(indexAxis);
22929 const pointsLen = points.length;
22930 let delta, pointBefore, pointCurrent;
22931 let pointAfter = getPoint(points, 0);
22932 for(let i = 0; i < pointsLen; ++i){
22933 pointBefore = pointCurrent;
22934 pointCurrent = pointAfter;
22935 pointAfter = getPoint(points, i + 1);
22936 if (!pointCurrent) {
22937 continue;
22938 }
22939 const iPixel = pointCurrent[indexAxis];
22940 const vPixel = pointCurrent[valueAxis];
22941 if (pointBefore) {
22942 delta = (iPixel - pointBefore[indexAxis]) / 3;
22943 pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
22944 pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
22945 }
22946 if (pointAfter) {
22947 delta = (pointAfter[indexAxis] - iPixel) / 3;
22948 pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
22949 pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
22950 }
22951 }
22952 }
22953 /**
22954 * This function calculates Bézier control points in a similar way than |splineCurve|,
22955 * but preserves monotonicity of the provided data and ensures no local extremums are added
22956 * between the dataset discrete points due to the interpolation.
22957 * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
22958 */ function splineCurveMonotone(points, indexAxis = 'x') {
22959 const valueAxis = getValueAxis(indexAxis);
22960 const pointsLen = points.length;
22961 const deltaK = Array(pointsLen).fill(0);
22962 const mK = Array(pointsLen);
22963 // Calculate slopes (deltaK) and initialize tangents (mK)
22964 let i, pointBefore, pointCurrent;
22965 let pointAfter = getPoint(points, 0);
22966 for(i = 0; i < pointsLen; ++i){
22967 pointBefore = pointCurrent;
22968 pointCurrent = pointAfter;
22969 pointAfter = getPoint(points, i + 1);
22970 if (!pointCurrent) {
22971 continue;
22972 }
22973 if (pointAfter) {
22974 const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
22975 // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
22976 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
22977 }
22978 mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;
22979 }
22980 monotoneAdjust(points, deltaK, mK);
22981 monotoneCompute(points, mK, indexAxis);
22982 }
22983 function capControlPoint(pt, min, max) {
22984 return Math.max(Math.min(pt, max), min);
22985 }
22986 function capBezierPoints(points, area) {
22987 let i, ilen, point, inArea, inAreaPrev;
22988 let inAreaNext = _isPointInArea(points[0], area);
22989 for(i = 0, ilen = points.length; i < ilen; ++i){
22990 inAreaPrev = inArea;
22991 inArea = inAreaNext;
22992 inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
22993 if (!inArea) {
22994 continue;
22995 }
22996 point = points[i];
22997 if (inAreaPrev) {
22998 point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
22999 point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
23000 }
23001 if (inAreaNext) {
23002 point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
23003 point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
23004 }
23005 }
23006 }
23007 /**
23008 * @private
23009 */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
23010 let i, ilen, point, controlPoints;
23011 // Only consider points that are drawn in case the spanGaps option is used
23012 if (options.spanGaps) {
23013 points = points.filter((pt)=>!pt.skip);
23014 }
23015 if (options.cubicInterpolationMode === 'monotone') {
23016 splineCurveMonotone(points, indexAxis);
23017 } else {
23018 let prev = loop ? points[points.length - 1] : points[0];
23019 for(i = 0, ilen = points.length; i < ilen; ++i){
23020 point = points[i];
23021 controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);
23022 point.cp1x = controlPoints.previous.x;
23023 point.cp1y = controlPoints.previous.y;
23024 point.cp2x = controlPoints.next.x;
23025 point.cp2y = controlPoints.next.y;
23026 prev = point;
23027 }
23028 }
23029 if (options.capBezierPoints) {
23030 capBezierPoints(points, area);
23031 }
23032 }
23033
23034 /**
23035 * @private
23036 */ function _isDomSupported() {
23037 return typeof window !== 'undefined' && typeof document !== 'undefined';
23038 }
23039 /**
23040 * @private
23041 */ function _getParentNode(domNode) {
23042 let parent = domNode.parentNode;
23043 if (parent && parent.toString() === '[object ShadowRoot]') {
23044 parent = parent.host;
23045 }
23046 return parent;
23047 }
23048 /**
23049 * convert max-width/max-height values that may be percentages into a number
23050 * @private
23051 */ function parseMaxStyle(styleValue, node, parentProperty) {
23052 let valueInPixels;
23053 if (typeof styleValue === 'string') {
23054 valueInPixels = parseInt(styleValue, 10);
23055 if (styleValue.indexOf('%') !== -1) {
23056 // percentage * size in dimension
23057 valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
23058 }
23059 } else {
23060 valueInPixels = styleValue;
23061 }
23062 return valueInPixels;
23063 }
23064 const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);
23065 function getStyle(el, property) {
23066 return getComputedStyle(el).getPropertyValue(property);
23067 }
23068 const positions = [
23069 'top',
23070 'right',
23071 'bottom',
23072 'left'
23073 ];
23074 function getPositionedStyle(styles, style, suffix) {
23075 const result = {};
23076 suffix = suffix ? '-' + suffix : '';
23077 for(let i = 0; i < 4; i++){
23078 const pos = positions[i];
23079 result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
23080 }
23081 result.width = result.left + result.right;
23082 result.height = result.top + result.bottom;
23083 return result;
23084 }
23085 const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);
23086 /**
23087 * @param e
23088 * @param canvas
23089 * @returns Canvas position
23090 */ function getCanvasPosition(e, canvas) {
23091 const touches = e.touches;
23092 const source = touches && touches.length ? touches[0] : e;
23093 const { offsetX , offsetY } = source;
23094 let box = false;
23095 let x, y;
23096 if (useOffsetPos(offsetX, offsetY, e.target)) {
23097 x = offsetX;
23098 y = offsetY;
23099 } else {
23100 const rect = canvas.getBoundingClientRect();
23101 x = source.clientX - rect.left;
23102 y = source.clientY - rect.top;
23103 box = true;
23104 }
23105 return {
23106 x,
23107 y,
23108 box
23109 };
23110 }
23111 /**
23112 * Gets an event's x, y coordinates, relative to the chart area
23113 * @param event
23114 * @param chart
23115 * @returns x and y coordinates of the event
23116 */ function getRelativePosition(event, chart) {
23117 if ('native' in event) {
23118 return event;
23119 }
23120 const { canvas , currentDevicePixelRatio } = chart;
23121 const style = getComputedStyle(canvas);
23122 const borderBox = style.boxSizing === 'border-box';
23123 const paddings = getPositionedStyle(style, 'padding');
23124 const borders = getPositionedStyle(style, 'border', 'width');
23125 const { x , y , box } = getCanvasPosition(event, canvas);
23126 const xOffset = paddings.left + (box && borders.left);
23127 const yOffset = paddings.top + (box && borders.top);
23128 let { width , height } = chart;
23129 if (borderBox) {
23130 width -= paddings.width + borders.width;
23131 height -= paddings.height + borders.height;
23132 }
23133 return {
23134 x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
23135 y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
23136 };
23137 }
23138 function getContainerSize(canvas, width, height) {
23139 let maxWidth, maxHeight;
23140 if (width === undefined || height === undefined) {
23141 const container = canvas && _getParentNode(canvas);
23142 if (!container) {
23143 width = canvas.clientWidth;
23144 height = canvas.clientHeight;
23145 } else {
23146 const rect = container.getBoundingClientRect(); // this is the border box of the container
23147 const containerStyle = getComputedStyle(container);
23148 const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
23149 const containerPadding = getPositionedStyle(containerStyle, 'padding');
23150 width = rect.width - containerPadding.width - containerBorder.width;
23151 height = rect.height - containerPadding.height - containerBorder.height;
23152 maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
23153 maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
23154 }
23155 }
23156 return {
23157 width,
23158 height,
23159 maxWidth: maxWidth || INFINITY,
23160 maxHeight: maxHeight || INFINITY
23161 };
23162 }
23163 const round1 = (v)=>Math.round(v * 10) / 10;
23164 // eslint-disable-next-line complexity
23165 function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
23166 const style = getComputedStyle(canvas);
23167 const margins = getPositionedStyle(style, 'margin');
23168 const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
23169 const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
23170 const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
23171 let { width , height } = containerSize;
23172 if (style.boxSizing === 'content-box') {
23173 const borders = getPositionedStyle(style, 'border', 'width');
23174 const paddings = getPositionedStyle(style, 'padding');
23175 width -= paddings.width + borders.width;
23176 height -= paddings.height + borders.height;
23177 }
23178 width = Math.max(0, width - margins.width);
23179 height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
23180 width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
23181 height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
23182 if (width && !height) {
23183 // https://github.com/chartjs/Chart.js/issues/4659
23184 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)
23185 height = round1(width / 2);
23186 }
23187 const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;
23188 if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
23189 height = containerSize.height;
23190 width = round1(Math.floor(height * aspectRatio));
23191 }
23192 return {
23193 width,
23194 height
23195 };
23196 }
23197 /**
23198 * @param chart
23199 * @param forceRatio
23200 * @param forceStyle
23201 * @returns True if the canvas context size or transformation has changed.
23202 */ function retinaScale(chart, forceRatio, forceStyle) {
23203 const pixelRatio = forceRatio || 1;
23204 const deviceHeight = round1(chart.height * pixelRatio);
23205 const deviceWidth = round1(chart.width * pixelRatio);
23206 chart.height = round1(chart.height);
23207 chart.width = round1(chart.width);
23208 const canvas = chart.canvas;
23209 // If no style has been set on the canvas, the render size is used as display size,
23210 // making the chart visually bigger, so let's enforce it to the "correct" values.
23211 // See https://github.com/chartjs/Chart.js/issues/3575
23212 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
23213 canvas.style.height = `${chart.height}px`;
23214 canvas.style.width = `${chart.width}px`;
23215 }
23216 if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
23217 chart.currentDevicePixelRatio = pixelRatio;
23218 canvas.height = deviceHeight;
23219 canvas.width = deviceWidth;
23220 chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
23221 return true;
23222 }
23223 return false;
23224 }
23225 /**
23226 * Detects support for options object argument in addEventListener.
23227 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
23228 * @private
23229 */ const supportsEventListenerOptions = function() {
23230 let passiveSupported = false;
23231 try {
23232 const options = {
23233 get passive () {
23234 passiveSupported = true;
23235 return false;
23236 }
23237 };
23238 if (_isDomSupported()) {
23239 window.addEventListener('test', null, options);
23240 window.removeEventListener('test', null, options);
23241 }
23242 } catch (e) {
23243 // continue regardless of error
23244 }
23245 return passiveSupported;
23246 }();
23247 /**
23248 * The "used" size is the final value of a dimension property after all calculations have
23249 * been performed. This method uses the computed style of `element` but returns undefined
23250 * if the computed style is not expressed in pixels. That can happen in some cases where
23251 * `element` has a size relative to its parent and this last one is not yet displayed,
23252 * for example because of `display: none` on a parent node.
23253 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
23254 * @returns Size in pixels or undefined if unknown.
23255 */ function readUsedSize(element, property) {
23256 const value = getStyle(element, property);
23257 const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
23258 return matches ? +matches[1] : undefined;
23259 }
23260
23261 /**
23262 * @private
23263 */ function _pointInLine(p1, p2, t, mode) {
23264 return {
23265 x: p1.x + t * (p2.x - p1.x),
23266 y: p1.y + t * (p2.y - p1.y)
23267 };
23268 }
23269 /**
23270 * @private
23271 */ function _steppedInterpolation(p1, p2, t, mode) {
23272 return {
23273 x: p1.x + t * (p2.x - p1.x),
23274 y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y
23275 };
23276 }
23277 /**
23278 * @private
23279 */ function _bezierInterpolation(p1, p2, t, mode) {
23280 const cp1 = {
23281 x: p1.cp2x,
23282 y: p1.cp2y
23283 };
23284 const cp2 = {
23285 x: p2.cp1x,
23286 y: p2.cp1y
23287 };
23288 const a = _pointInLine(p1, cp1, t);
23289 const b = _pointInLine(cp1, cp2, t);
23290 const c = _pointInLine(cp2, p2, t);
23291 const d = _pointInLine(a, b, t);
23292 const e = _pointInLine(b, c, t);
23293 return _pointInLine(d, e, t);
23294 }
23295
23296 const getRightToLeftAdapter = function(rectX, width) {
23297 return {
23298 x (x) {
23299 return rectX + rectX + width - x;
23300 },
23301 setWidth (w) {
23302 width = w;
23303 },
23304 textAlign (align) {
23305 if (align === 'center') {
23306 return align;
23307 }
23308 return align === 'right' ? 'left' : 'right';
23309 },
23310 xPlus (x, value) {
23311 return x - value;
23312 },
23313 leftForLtr (x, itemWidth) {
23314 return x - itemWidth;
23315 }
23316 };
23317 };
23318 const getLeftToRightAdapter = function() {
23319 return {
23320 x (x) {
23321 return x;
23322 },
23323 setWidth (w) {},
23324 textAlign (align) {
23325 return align;
23326 },
23327 xPlus (x, value) {
23328 return x + value;
23329 },
23330 leftForLtr (x, _itemWidth) {
23331 return x;
23332 }
23333 };
23334 };
23335 function getRtlAdapter(rtl, rectX, width) {
23336 return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
23337 }
23338 function overrideTextDirection(ctx, direction) {
23339 let style, original;
23340 if (direction === 'ltr' || direction === 'rtl') {
23341 style = ctx.canvas.style;
23342 original = [
23343 style.getPropertyValue('direction'),
23344 style.getPropertyPriority('direction')
23345 ];
23346 style.setProperty('direction', direction, 'important');
23347 ctx.prevTextDirection = original;
23348 }
23349 }
23350 function restoreTextDirection(ctx, original) {
23351 if (original !== undefined) {
23352 delete ctx.prevTextDirection;
23353 ctx.canvas.style.setProperty('direction', original[0], original[1]);
23354 }
23355 }
23356
23357 function propertyFn(property) {
23358 if (property === 'angle') {
23359 return {
23360 between: _angleBetween,
23361 compare: _angleDiff,
23362 normalize: _normalizeAngle
23363 };
23364 }
23365 return {
23366 between: _isBetween,
23367 compare: (a, b)=>a - b,
23368 normalize: (x)=>x
23369 };
23370 }
23371 function normalizeSegment({ start , end , count , loop , style }) {
23372 return {
23373 start: start % count,
23374 end: end % count,
23375 loop: loop && (end - start + 1) % count === 0,
23376 style
23377 };
23378 }
23379 function getSegment(segment, points, bounds) {
23380 const { property , start: startBound , end: endBound } = bounds;
23381 const { between , normalize } = propertyFn(property);
23382 const count = points.length;
23383 let { start , end , loop } = segment;
23384 let i, ilen;
23385 if (loop) {
23386 start += count;
23387 end += count;
23388 for(i = 0, ilen = count; i < ilen; ++i){
23389 if (!between(normalize(points[start % count][property]), startBound, endBound)) {
23390 break;
23391 }
23392 start--;
23393 end--;
23394 }
23395 start %= count;
23396 end %= count;
23397 }
23398 if (end < start) {
23399 end += count;
23400 }
23401 return {
23402 start,
23403 end,
23404 loop,
23405 style: segment.style
23406 };
23407 }
23408 function _boundSegment(segment, points, bounds) {
23409 if (!bounds) {
23410 return [
23411 segment
23412 ];
23413 }
23414 const { property , start: startBound , end: endBound } = bounds;
23415 const count = points.length;
23416 const { compare , between , normalize } = propertyFn(property);
23417 const { start , end , loop , style } = getSegment(segment, points, bounds);
23418 const result = [];
23419 let inside = false;
23420 let subStart = null;
23421 let value, point, prevValue;
23422 const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
23423 const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);
23424 const shouldStart = ()=>inside || startIsBefore();
23425 const shouldStop = ()=>!inside || endIsBefore();
23426 for(let i = start, prev = start; i <= end; ++i){
23427 point = points[i % count];
23428 if (point.skip) {
23429 continue;
23430 }
23431 value = normalize(point[property]);
23432 if (value === prevValue) {
23433 continue;
23434 }
23435 inside = between(value, startBound, endBound);
23436 if (subStart === null && shouldStart()) {
23437 subStart = compare(value, startBound) === 0 ? i : prev;
23438 }
23439 if (subStart !== null && shouldStop()) {
23440 result.push(normalizeSegment({
23441 start: subStart,
23442 end: i,
23443 loop,
23444 count,
23445 style
23446 }));
23447 subStart = null;
23448 }
23449 prev = i;
23450 prevValue = value;
23451 }
23452 if (subStart !== null) {
23453 result.push(normalizeSegment({
23454 start: subStart,
23455 end,
23456 loop,
23457 count,
23458 style
23459 }));
23460 }
23461 return result;
23462 }
23463 function _boundSegments(line, bounds) {
23464 const result = [];
23465 const segments = line.segments;
23466 for(let i = 0; i < segments.length; i++){
23467 const sub = _boundSegment(segments[i], line.points, bounds);
23468 if (sub.length) {
23469 result.push(...sub);
23470 }
23471 }
23472 return result;
23473 }
23474 function findStartAndEnd(points, count, loop, spanGaps) {
23475 let start = 0;
23476 let end = count - 1;
23477 if (loop && !spanGaps) {
23478 while(start < count && !points[start].skip){
23479 start++;
23480 }
23481 }
23482 while(start < count && points[start].skip){
23483 start++;
23484 }
23485 start %= count;
23486 if (loop) {
23487 end += start;
23488 }
23489 while(end > start && points[end % count].skip){
23490 end--;
23491 }
23492 end %= count;
23493 return {
23494 start,
23495 end
23496 };
23497 }
23498 function solidSegments(points, start, max, loop) {
23499 const count = points.length;
23500 const result = [];
23501 let last = start;
23502 let prev = points[start];
23503 let end;
23504 for(end = start + 1; end <= max; ++end){
23505 const cur = points[end % count];
23506 if (cur.skip || cur.stop) {
23507 if (!prev.skip) {
23508 loop = false;
23509 result.push({
23510 start: start % count,
23511 end: (end - 1) % count,
23512 loop
23513 });
23514 start = last = cur.stop ? end : null;
23515 }
23516 } else {
23517 last = end;
23518 if (prev.skip) {
23519 start = end;
23520 }
23521 }
23522 prev = cur;
23523 }
23524 if (last !== null) {
23525 result.push({
23526 start: start % count,
23527 end: last % count,
23528 loop
23529 });
23530 }
23531 return result;
23532 }
23533 function _computeSegments(line, segmentOptions) {
23534 const points = line.points;
23535 const spanGaps = line.options.spanGaps;
23536 const count = points.length;
23537 if (!count) {
23538 return [];
23539 }
23540 const loop = !!line._loop;
23541 const { start , end } = findStartAndEnd(points, count, loop, spanGaps);
23542 if (spanGaps === true) {
23543 return splitByStyles(line, [
23544 {
23545 start,
23546 end,
23547 loop
23548 }
23549 ], points, segmentOptions);
23550 }
23551 const max = end < start ? end + count : end;
23552 const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
23553 return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
23554 }
23555 function splitByStyles(line, segments, points, segmentOptions) {
23556 if (!segmentOptions || !segmentOptions.setContext || !points) {
23557 return segments;
23558 }
23559 return doSplitByStyles(line, segments, points, segmentOptions);
23560 }
23561 function doSplitByStyles(line, segments, points, segmentOptions) {
23562 const chartContext = line._chart.getContext();
23563 const baseStyle = readStyle(line.options);
23564 const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;
23565 const count = points.length;
23566 const result = [];
23567 let prevStyle = baseStyle;
23568 let start = segments[0].start;
23569 let i = start;
23570 function addStyle(s, e, l, st) {
23571 const dir = spanGaps ? -1 : 1;
23572 if (s === e) {
23573 return;
23574 }
23575 s += count;
23576 while(points[s % count].skip){
23577 s -= dir;
23578 }
23579 while(points[e % count].skip){
23580 e += dir;
23581 }
23582 if (s % count !== e % count) {
23583 result.push({
23584 start: s % count,
23585 end: e % count,
23586 loop: l,
23587 style: st
23588 });
23589 prevStyle = st;
23590 start = e % count;
23591 }
23592 }
23593 for (const segment of segments){
23594 start = spanGaps ? start : segment.start;
23595 let prev = points[start % count];
23596 let style;
23597 for(i = start + 1; i <= segment.end; i++){
23598 const pt = points[i % count];
23599 style = readStyle(segmentOptions.setContext(createContext(chartContext, {
23600 type: 'segment',
23601 p0: prev,
23602 p1: pt,
23603 p0DataIndex: (i - 1) % count,
23604 p1DataIndex: i % count,
23605 datasetIndex
23606 })));
23607 if (styleChanged(style, prevStyle)) {
23608 addStyle(start, i - 1, segment.loop, prevStyle);
23609 }
23610 prev = pt;
23611 prevStyle = style;
23612 }
23613 if (start < i - 1) {
23614 addStyle(start, i - 1, segment.loop, prevStyle);
23615 }
23616 }
23617 return result;
23618 }
23619 function readStyle(options) {
23620 return {
23621 backgroundColor: options.backgroundColor,
23622 borderCapStyle: options.borderCapStyle,
23623 borderDash: options.borderDash,
23624 borderDashOffset: options.borderDashOffset,
23625 borderJoinStyle: options.borderJoinStyle,
23626 borderWidth: options.borderWidth,
23627 borderColor: options.borderColor
23628 };
23629 }
23630 function styleChanged(style, prevStyle) {
23631 if (!prevStyle) {
23632 return false;
23633 }
23634 const cache = [];
23635 const replacer = function(key, value) {
23636 if (!isPatternOrGradient(value)) {
23637 return value;
23638 }
23639 if (!cache.includes(value)) {
23640 cache.push(value);
23641 }
23642 return cache.indexOf(value);
23643 };
23644 return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);
23645 }
23646
23647 function getSizeForArea(scale, chartArea, field) {
23648 return scale.options.clip ? scale[field] : chartArea[field];
23649 }
23650 function getDatasetArea(meta, chartArea) {
23651 const { xScale , yScale } = meta;
23652 if (xScale && yScale) {
23653 return {
23654 left: getSizeForArea(xScale, chartArea, 'left'),
23655 right: getSizeForArea(xScale, chartArea, 'right'),
23656 top: getSizeForArea(yScale, chartArea, 'top'),
23657 bottom: getSizeForArea(yScale, chartArea, 'bottom')
23658 };
23659 }
23660 return chartArea;
23661 }
23662 function getDatasetClipArea(chart, meta) {
23663 const clip = meta._clip;
23664 if (clip.disabled) {
23665 return false;
23666 }
23667 const area = getDatasetArea(meta, chart.chartArea);
23668 return {
23669 left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left),
23670 right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right),
23671 top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top),
23672 bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom)
23673 };
23674 }
23675
23676
23677 //# sourceMappingURL=helpers.dataset.js.map
23678
23679
23680 /***/ }
23681
23682 /******/ });
23683 /************************************************************************/
23684 /******/ // The module cache
23685 /******/ var __webpack_module_cache__ = {};
23686 /******/
23687 /******/ // The require function
23688 /******/ function __webpack_require__(moduleId) {
23689 /******/ // Check if module is in cache
23690 /******/ var cachedModule = __webpack_module_cache__[moduleId];
23691 /******/ if (cachedModule !== undefined) {
23692 /******/ return cachedModule.exports;
23693 /******/ }
23694 /******/ // Create a new module (and put it into the cache)
23695 /******/ var module = __webpack_module_cache__[moduleId] = {
23696 /******/ // no module.id needed
23697 /******/ // no module.loaded needed
23698 /******/ exports: {}
23699 /******/ };
23700 /******/
23701 /******/ // Execute the module function
23702 /******/ if (!(moduleId in __webpack_modules__)) {
23703 /******/ delete __webpack_module_cache__[moduleId];
23704 /******/ var e = new Error("Cannot find module '" + moduleId + "'");
23705 /******/ e.code = 'MODULE_NOT_FOUND';
23706 /******/ throw e;
23707 /******/ }
23708 /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
23709 /******/
23710 /******/ // Return the exports of the module
23711 /******/ return module.exports;
23712 /******/ }
23713 /******/
23714 /************************************************************************/
23715 /******/ /* webpack/runtime/compat get default export */
23716 /******/ (() => {
23717 /******/ // getDefaultExport function for compatibility with non-harmony modules
23718 /******/ __webpack_require__.n = (module) => {
23719 /******/ var getter = module && module.__esModule ?
23720 /******/ () => (module['default']) :
23721 /******/ () => (module);
23722 /******/ __webpack_require__.d(getter, { a: getter });
23723 /******/ return getter;
23724 /******/ };
23725 /******/ })();
23726 /******/
23727 /******/ /* webpack/runtime/define property getters */
23728 /******/ (() => {
23729 /******/ // define getter functions for harmony exports
23730 /******/ __webpack_require__.d = (exports, definition) => {
23731 /******/ for(var key in definition) {
23732 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
23733 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
23734 /******/ }
23735 /******/ }
23736 /******/ };
23737 /******/ })();
23738 /******/
23739 /******/ /* webpack/runtime/hasOwnProperty shorthand */
23740 /******/ (() => {
23741 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
23742 /******/ })();
23743 /******/
23744 /******/ /* webpack/runtime/make namespace object */
23745 /******/ (() => {
23746 /******/ // define __esModule on exports
23747 /******/ __webpack_require__.r = (exports) => {
23748 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
23749 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
23750 /******/ }
23751 /******/ Object.defineProperty(exports, '__esModule', { value: true });
23752 /******/ };
23753 /******/ })();
23754 /******/
23755 /************************************************************************/
23756 var __webpack_exports__ = {};
23757 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
23758 (() => {
23759 "use strict";
23760 /*!************************************************!*\
23761 !*** ./assets/src/js/admin/admin-statistic.js ***!
23762 \************************************************/
23763 __webpack_require__.r(__webpack_exports__);
23764 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
23765 /* 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");
23766 /* 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");
23767 /* 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");
23768 /* 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");
23769 /* 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");
23770 /* 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");
23771 /* 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");
23772 /**
23773 * Statistics dashboard entry — bootstraps the per-tab modules.
23774 *
23775 * All four tabs run on the statistics/* module stack (state, api, chart,
23776 * data-table, report-modal); the legacy per-tab loaders are gone.
23777 *
23778 * @since 4.2.5.5
23779 * @version 2.0.0
23780 */
23781
23782
23783
23784
23785
23786
23787
23788
23789
23790 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.LpStatsFilterBar.selectors.elContainer, () => {
23791 _statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsFilterBar.init();
23792 });
23793 // SweetAlert2 popup: delegated events only, no rendered container to wait for.
23794 _statistics_report_modal_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsReportModal.init();
23795 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.LpStatsTabOverview.selectors.elContainer, () => {
23796 _statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.lpStatsTabOverview.init();
23797 });
23798 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.LpStatsTabOrders.selectors.elContainer, () => {
23799 _statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.lpStatsTabOrders.init();
23800 });
23801 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.LpStatsTabCourses.selectors.elContainer, () => {
23802 _statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.lpStatsTabCourses.init();
23803 });
23804 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.LpStatsTabUsers.selectors.elContainer, () => {
23805 _statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsTabUsers.init();
23806 });
23807 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.LpStatsTabInstructors.selectors.elContainer, () => {
23808 _statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.lpStatsTabInstructors.init();
23809 });
23810 })();
23811
23812 /******/ })()
23813 ;
23814 //# sourceMappingURL=admin-statistic.js.map