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

23,791 lines 863.0 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.25
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 * @returns {boolean}
3745 */
3746 const isFirefox = () => navigator.userAgent.includes('Firefox');
3747
3748 /**
3749 * Gets the popup container which contains the backdrop and the popup itself.
3750 *
3751 * @returns {HTMLElement | null}
3752 */
3753 const getContainer = () => document.body.querySelector(`.${swalClasses.container}`);
3754
3755 /**
3756 * @param {string} selectorString
3757 * @returns {HTMLElement | null}
3758 */
3759 const elementBySelector = selectorString => {
3760 const container = getContainer();
3761 return container ? container.querySelector(selectorString) : null;
3762 };
3763
3764 /**
3765 * @param {string} className
3766 * @returns {HTMLElement | null}
3767 */
3768 const elementByClass = className => {
3769 return elementBySelector(`.${className}`);
3770 };
3771
3772 /**
3773 * @returns {HTMLElement | null}
3774 */
3775 const getPopup = () => elementByClass(swalClasses.popup);
3776
3777 /**
3778 * @returns {HTMLElement | null}
3779 */
3780 const getIcon = () => elementByClass(swalClasses.icon);
3781
3782 /**
3783 * @returns {HTMLElement | null}
3784 */
3785 const getIconContent = () => elementByClass(swalClasses['icon-content']);
3786
3787 /**
3788 * @returns {HTMLElement | null}
3789 */
3790 const getTitle = () => elementByClass(swalClasses.title);
3791
3792 /**
3793 * @returns {HTMLElement | null}
3794 */
3795 const getHtmlContainer = () => elementByClass(swalClasses['html-container']);
3796
3797 /**
3798 * @returns {HTMLElement | null}
3799 */
3800 const getImage = () => elementByClass(swalClasses.image);
3801
3802 /**
3803 * @returns {HTMLElement | null}
3804 */
3805 const getProgressSteps = () => elementByClass(swalClasses['progress-steps']);
3806
3807 /**
3808 * @returns {HTMLElement | null}
3809 */
3810 const getValidationMessage = () => elementByClass(swalClasses['validation-message']);
3811
3812 /**
3813 * @returns {HTMLButtonElement | null}
3814 */
3815 const getConfirmButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.confirm}`));
3816
3817 /**
3818 * @returns {HTMLButtonElement | null}
3819 */
3820 const getCancelButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.cancel}`));
3821
3822 /**
3823 * @returns {HTMLButtonElement | null}
3824 */
3825 const getDenyButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.deny}`));
3826
3827 /**
3828 * @returns {HTMLElement | null}
3829 */
3830 const getInputLabel = () => elementByClass(swalClasses['input-label']);
3831
3832 /**
3833 * @returns {HTMLElement | null}
3834 */
3835 const getLoader = () => elementBySelector(`.${swalClasses.loader}`);
3836
3837 /**
3838 * @returns {HTMLElement | null}
3839 */
3840 const getActions = () => elementByClass(swalClasses.actions);
3841
3842 /**
3843 * @returns {HTMLElement | null}
3844 */
3845 const getFooter = () => elementByClass(swalClasses.footer);
3846
3847 /**
3848 * @returns {HTMLElement | null}
3849 */
3850 const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']);
3851
3852 /**
3853 * @returns {HTMLElement | null}
3854 */
3855 const getCloseButton = () => elementByClass(swalClasses.close);
3856
3857 // https://github.com/jkup/focusable/blob/master/index.js
3858 const focusable = `
3859 a[href],
3860 area[href],
3861 input:not([disabled]),
3862 select:not([disabled]),
3863 textarea:not([disabled]),
3864 button:not([disabled]),
3865 iframe,
3866 object,
3867 embed,
3868 [tabindex="0"],
3869 [contenteditable],
3870 audio[controls],
3871 video[controls],
3872 summary
3873 `;
3874 /**
3875 * @returns {HTMLElement[]}
3876 */
3877 const getFocusableElements = () => {
3878 const popup = getPopup();
3879 if (!popup) {
3880 return [];
3881 }
3882 /** @type {NodeListOf<HTMLElement>} */
3883 const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])');
3884 const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex)
3885 // sort according to tabindex
3886 .sort((a, b) => {
3887 const tabindexA = parseInt(a.getAttribute('tabindex') || '0');
3888 const tabindexB = parseInt(b.getAttribute('tabindex') || '0');
3889 if (tabindexA > tabindexB) {
3890 return 1;
3891 } else if (tabindexA < tabindexB) {
3892 return -1;
3893 }
3894 return 0;
3895 });
3896
3897 /** @type {NodeListOf<HTMLElement>} */
3898 const otherFocusableElements = popup.querySelectorAll(focusable);
3899 const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1');
3900 return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el));
3901 };
3902
3903 /**
3904 * @returns {boolean}
3905 */
3906 const isModal = () => {
3907 return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']);
3908 };
3909
3910 /**
3911 * @returns {boolean}
3912 */
3913 const isToast = () => {
3914 const popup = getPopup();
3915 if (!popup) {
3916 return false;
3917 }
3918 return hasClass(popup, swalClasses.toast);
3919 };
3920
3921 /**
3922 * @returns {boolean}
3923 */
3924 const isLoading = () => {
3925 const popup = getPopup();
3926 if (!popup) {
3927 return false;
3928 }
3929 return popup.hasAttribute('data-loading');
3930 };
3931
3932 /**
3933 * Securely set innerHTML of an element
3934 * https://github.com/sweetalert2/sweetalert2/issues/1926
3935 *
3936 * @param {HTMLElement} elem
3937 * @param {string} html
3938 */
3939 const setInnerHtml = (elem, html) => {
3940 elem.textContent = '';
3941 if (html) {
3942 const parser = new DOMParser();
3943 const parsed = parser.parseFromString(html, `text/html`);
3944 const head = parsed.querySelector('head');
3945 if (head) {
3946 Array.from(head.childNodes).forEach(child => {
3947 elem.appendChild(child);
3948 });
3949 }
3950 const body = parsed.querySelector('body');
3951 if (body) {
3952 Array.from(body.childNodes).forEach(child => {
3953 if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) {
3954 elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507
3955 } else {
3956 elem.appendChild(child);
3957 }
3958 });
3959 }
3960 }
3961 };
3962
3963 /**
3964 * @param {HTMLElement} elem
3965 * @param {string} className
3966 * @returns {boolean}
3967 */
3968 const hasClass = (elem, className) => {
3969 if (!className) {
3970 return false;
3971 }
3972 return className.split(/\s+/).every(cls => elem.classList.contains(cls));
3973 };
3974
3975 /**
3976 * @param {HTMLElement} elem
3977 * @param {SweetAlertOptions} params
3978 */
3979 const removeCustomClasses = (elem, params) => {
3980 Array.from(elem.classList).forEach(className => {
3981 if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) {
3982 elem.classList.remove(className);
3983 }
3984 });
3985 };
3986
3987 /**
3988 * @param {HTMLElement} elem
3989 * @param {SweetAlertOptions} params
3990 * @param {string} className
3991 */
3992 const applyCustomClass = (elem, params, className) => {
3993 removeCustomClasses(elem, params);
3994 if (!params.customClass) {
3995 return;
3996 }
3997 const customClass = params.customClass[(/** @type {keyof SweetAlertCustomClass} */className)];
3998 if (!customClass) {
3999 return;
4000 }
4001 if (typeof customClass !== 'string' && !customClass.forEach) {
4002 warn(`Invalid type of customClass.${className}! Expected string or iterable object, got "${typeof customClass}"`);
4003 return;
4004 }
4005 addClass(elem, customClass);
4006 };
4007
4008 /**
4009 * @param {HTMLElement} popup
4010 * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass
4011 * @returns {HTMLInputElement | null}
4012 */
4013 const getInput$1 = (popup, inputClass) => {
4014 if (!inputClass) {
4015 return null;
4016 }
4017 switch (inputClass) {
4018 case 'select':
4019 case 'textarea':
4020 case 'file':
4021 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses[inputClass]}`);
4022 case 'checkbox':
4023 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.checkbox} input`);
4024 case 'radio':
4025 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:checked`) || popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:first-child`);
4026 case 'range':
4027 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.range} input`);
4028 default:
4029 return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.input}`);
4030 }
4031 };
4032
4033 /**
4034 * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input
4035 */
4036 const focusInput = input => {
4037 input.focus();
4038
4039 // place cursor at end of text in text input
4040 if (input.type !== 'file') {
4041 // http://stackoverflow.com/a/2345915
4042 const val = input.value;
4043 input.value = '';
4044 input.value = val;
4045 }
4046 };
4047
4048 /**
4049 * @param {HTMLElement | HTMLElement[] | null} target
4050 * @param {string | string[] | readonly string[] | undefined} classList
4051 * @param {boolean} condition
4052 */
4053 const toggleClass = (target, classList, condition) => {
4054 if (!target || !classList) {
4055 return;
4056 }
4057 const classes = typeof classList === 'string' ? classList.split(/\s+/).filter(Boolean) : classList;
4058 const targets = Array.isArray(target) ? target : [target];
4059 targets.forEach(elem => {
4060 classes.forEach(className => {
4061 if (condition) {
4062 elem.classList.add(className);
4063 } else {
4064 elem.classList.remove(className);
4065 }
4066 });
4067 });
4068 };
4069
4070 /**
4071 * @param {HTMLElement | HTMLElement[] | null} target
4072 * @param {string | string[] | readonly string[] | undefined} classList
4073 */
4074 const addClass = (target, classList) => {
4075 toggleClass(target, classList, true);
4076 };
4077
4078 /**
4079 * @param {HTMLElement | HTMLElement[] | null} target
4080 * @param {string | string[] | readonly string[] | undefined} classList
4081 */
4082 const removeClass = (target, classList) => {
4083 toggleClass(target, classList, false);
4084 };
4085
4086 /**
4087 * Get direct child of an element by class name
4088 *
4089 * @param {HTMLElement} elem
4090 * @param {string} className
4091 * @returns {HTMLElement | undefined}
4092 */
4093 const getDirectChildByClass = (elem, className) => (/** @type {HTMLElement | undefined} */
4094 Array.from(elem.children).find(child => child instanceof HTMLElement && hasClass(child, className)));
4095
4096 /**
4097 * @param {HTMLElement} elem
4098 * @param {string} property
4099 * @param {string | number | null | undefined} value
4100 */
4101 const applyNumericalStyle = (elem, property, value) => {
4102 if (value === `${parseInt(`${value}`)}`) {
4103 value = parseInt(value);
4104 }
4105 if (value || value === 0) {
4106 elem.style.setProperty(property, typeof value === 'number' ? `${value}px` : (/** @type {string} */value));
4107 } else {
4108 elem.style.removeProperty(property);
4109 }
4110 };
4111
4112 /**
4113 * @param {HTMLElement | null} elem
4114 * @param {string} display
4115 */
4116 const show = (elem, display = 'flex') => {
4117 if (!elem) {
4118 return;
4119 }
4120 elem.style.display = display;
4121 };
4122
4123 /**
4124 * @param {HTMLElement | null} elem
4125 */
4126 const hide = elem => {
4127 if (!elem) {
4128 return;
4129 }
4130 elem.style.display = 'none';
4131 };
4132
4133 /**
4134 * @param {HTMLElement | null} elem
4135 * @param {string} display
4136 */
4137 const showWhenInnerHtmlPresent = (elem, display = 'block') => {
4138 if (!elem) {
4139 return;
4140 }
4141 new MutationObserver(() => {
4142 toggle(elem, elem.innerHTML, display);
4143 }).observe(elem, {
4144 childList: true,
4145 subtree: true
4146 });
4147 };
4148
4149 /**
4150 * @param {HTMLElement} parent
4151 * @param {string} selector
4152 * @param {string} property
4153 * @param {string} value
4154 */
4155 const setStyle = (parent, selector, property, value) => {
4156 /** @type {HTMLElement | null} */
4157 const el = parent.querySelector(selector);
4158 if (el) {
4159 el.style.setProperty(property, value);
4160 }
4161 };
4162
4163 /**
4164 * @param {HTMLElement} elem
4165 * @param {boolean | string | null | undefined} condition
4166 * @param {string} display
4167 */
4168 const toggle = (elem, condition, display = 'flex') => {
4169 if (condition) {
4170 show(elem, display);
4171 } else {
4172 hide(elem);
4173 }
4174 };
4175
4176 /**
4177 * borrowed from jquery $(elem).is(':visible') implementation
4178 *
4179 * @param {HTMLElement | null} elem
4180 * @returns {boolean}
4181 */
4182 const isVisible$1 = elem => Boolean(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length));
4183
4184 /**
4185 * @returns {boolean}
4186 */
4187 const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton());
4188
4189 /**
4190 * @param {HTMLElement} elem
4191 * @returns {boolean}
4192 */
4193 const isScrollable = elem => Boolean(elem.scrollHeight > elem.clientHeight);
4194
4195 /**
4196 * @param {HTMLElement} element
4197 * @param {HTMLElement} stopElement
4198 * @returns {boolean}
4199 */
4200 const selfOrParentIsScrollable = (element, stopElement) => {
4201 let parent = /** @type {HTMLElement | null} */element;
4202 while (parent && parent !== stopElement) {
4203 if (isScrollable(parent)) {
4204 return true;
4205 }
4206 parent = parent.parentElement;
4207 }
4208 return false;
4209 };
4210
4211 /**
4212 * borrowed from https://stackoverflow.com/a/46352119
4213 *
4214 * @param {HTMLElement} elem
4215 * @returns {boolean}
4216 */
4217 const hasCssAnimation = elem => {
4218 const style = window.getComputedStyle(elem);
4219 const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0');
4220 const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0');
4221 return animDuration > 0 || transDuration > 0;
4222 };
4223
4224 /**
4225 * @param {number} timer
4226 * @param {boolean} reset
4227 */
4228 const animateTimerProgressBar = (timer, reset = false) => {
4229 const timerProgressBar = getTimerProgressBar();
4230 if (!timerProgressBar) {
4231 return;
4232 }
4233 if (isVisible$1(timerProgressBar)) {
4234 if (reset) {
4235 timerProgressBar.style.transition = 'none';
4236 timerProgressBar.style.width = '100%';
4237 }
4238 setTimeout(() => {
4239 timerProgressBar.style.transition = `width ${timer / 1000}s linear`;
4240 timerProgressBar.style.width = '0%';
4241 }, 10);
4242 }
4243 };
4244 const stopTimerProgressBar = () => {
4245 const timerProgressBar = getTimerProgressBar();
4246 if (!timerProgressBar) {
4247 return;
4248 }
4249 const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4250 timerProgressBar.style.removeProperty('transition');
4251 timerProgressBar.style.width = '100%';
4252 const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width);
4253 const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100;
4254 timerProgressBar.style.width = `${timerProgressBarPercent}%`;
4255 };
4256
4257 /**
4258 * Detect Node env
4259 *
4260 * @returns {boolean}
4261 */
4262 const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
4263
4264 const sweetHTML = `
4265 <div aria-labelledby="${swalClasses.title}" aria-describedby="${swalClasses['html-container']}" class="${swalClasses.popup}" tabindex="-1">
4266 <button type="button" class="${swalClasses.close}"></button>
4267 <ul class="${swalClasses['progress-steps']}"></ul>
4268 <div class="${swalClasses.icon}"></div>
4269 <img class="${swalClasses.image}" />
4270 <h2 class="${swalClasses.title}" id="${swalClasses.title}"></h2>
4271 <div class="${swalClasses['html-container']}" id="${swalClasses['html-container']}"></div>
4272 <input class="${swalClasses.input}" id="${swalClasses.input}" />
4273 <input type="file" class="${swalClasses.file}" />
4274 <div class="${swalClasses.range}">
4275 <input type="range" />
4276 <output></output>
4277 </div>
4278 <select class="${swalClasses.select}" id="${swalClasses.select}"></select>
4279 <div class="${swalClasses.radio}"></div>
4280 <label class="${swalClasses.checkbox}">
4281 <input type="checkbox" id="${swalClasses.checkbox}" />
4282 <span class="${swalClasses.label}"></span>
4283 </label>
4284 <textarea class="${swalClasses.textarea}" id="${swalClasses.textarea}"></textarea>
4285 <div class="${swalClasses['validation-message']}" id="${swalClasses['validation-message']}"></div>
4286 <div class="${swalClasses.actions}">
4287 <div class="${swalClasses.loader}"></div>
4288 <button type="button" class="${swalClasses.confirm}"></button>
4289 <button type="button" class="${swalClasses.deny}"></button>
4290 <button type="button" class="${swalClasses.cancel}"></button>
4291 </div>
4292 <div class="${swalClasses.footer}"></div>
4293 <div class="${swalClasses['timer-progress-bar-container']}">
4294 <div class="${swalClasses['timer-progress-bar']}"></div>
4295 </div>
4296 </div>
4297 `.replace(/(^|\n)\s*/g, '');
4298
4299 /**
4300 * @returns {boolean}
4301 */
4302 const resetOldContainer = () => {
4303 const oldContainer = getContainer();
4304 if (!oldContainer) {
4305 return false;
4306 }
4307 oldContainer.remove();
4308 removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'],
4309 // @ts-ignore: 'has-column' is not defined in swalClasses but may be set dynamically
4310 swalClasses['has-column']]);
4311 return true;
4312 };
4313 const resetValidationMessage$1 = () => {
4314 if (globalState.currentInstance) {
4315 globalState.currentInstance.resetValidationMessage();
4316 }
4317 };
4318 const addInputChangeListeners = () => {
4319 const popup = getPopup();
4320 if (!popup) {
4321 return;
4322 }
4323 const input = getDirectChildByClass(popup, swalClasses.input);
4324 const file = getDirectChildByClass(popup, swalClasses.file);
4325 /** @type {HTMLInputElement | null} */
4326 const range = popup.querySelector(`.${swalClasses.range} input`);
4327 /** @type {HTMLOutputElement | null} */
4328 const rangeOutput = popup.querySelector(`.${swalClasses.range} output`);
4329 const select = getDirectChildByClass(popup, swalClasses.select);
4330 /** @type {HTMLInputElement | null} */
4331 const checkbox = popup.querySelector(`.${swalClasses.checkbox} input`);
4332 const textarea = getDirectChildByClass(popup, swalClasses.textarea);
4333 if (input) {
4334 input.oninput = resetValidationMessage$1;
4335 }
4336 if (file) {
4337 file.onchange = resetValidationMessage$1;
4338 }
4339 if (select) {
4340 select.onchange = resetValidationMessage$1;
4341 }
4342 if (checkbox) {
4343 checkbox.onchange = resetValidationMessage$1;
4344 }
4345 if (textarea) {
4346 textarea.oninput = resetValidationMessage$1;
4347 }
4348 if (range && rangeOutput) {
4349 range.oninput = () => {
4350 resetValidationMessage$1();
4351 rangeOutput.value = range.value;
4352 };
4353 range.onchange = () => {
4354 resetValidationMessage$1();
4355 rangeOutput.value = range.value;
4356 };
4357 }
4358 };
4359
4360 /**
4361 * @param {string | HTMLElement} target
4362 * @returns {HTMLElement}
4363 */
4364 const getTarget = target => {
4365 if (typeof target === 'string') {
4366 const element = document.querySelector(target);
4367 if (!element) {
4368 throw new Error(`Target element "${target}" not found`);
4369 }
4370 return /** @type {HTMLElement} */element;
4371 }
4372 return target;
4373 };
4374
4375 /**
4376 * @param {SweetAlertOptions} params
4377 */
4378 const setupAccessibility = params => {
4379 const popup = getPopup();
4380 if (!popup) {
4381 return;
4382 }
4383 popup.setAttribute('role', params.toast ? 'alert' : 'dialog');
4384 popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive');
4385 if (!params.toast) {
4386 popup.setAttribute('aria-modal', 'true');
4387 }
4388 };
4389
4390 /**
4391 * @param {HTMLElement} targetElement
4392 */
4393 const setupRTL = targetElement => {
4394 if (window.getComputedStyle(targetElement).direction === 'rtl') {
4395 addClass(getContainer(), swalClasses.rtl);
4396 globalState.isRTL = true;
4397 }
4398 };
4399
4400 /**
4401 * Add modal + backdrop to DOM
4402 *
4403 * @param {SweetAlertOptions} params
4404 */
4405 const init = params => {
4406 // Clean up the old popup container if it exists
4407 const oldContainerExisted = resetOldContainer();
4408 if (isNodeEnv()) {
4409 error('SweetAlert2 requires document to initialize');
4410 return;
4411 }
4412 const container = document.createElement('div');
4413 container.className = swalClasses.container;
4414 if (oldContainerExisted) {
4415 addClass(container, swalClasses['no-transition']);
4416 }
4417 setInnerHtml(container, sweetHTML);
4418 container.dataset['swal2Theme'] = params.theme;
4419 const targetElement = getTarget(params.target || 'body');
4420 targetElement.appendChild(container);
4421 if (params.topLayer) {
4422 container.setAttribute('popover', '');
4423 container.showPopover();
4424 }
4425 setupAccessibility(params);
4426 setupRTL(targetElement);
4427 addInputChangeListeners();
4428 };
4429
4430 /**
4431 * @param {HTMLElement | object | string} param
4432 * @param {HTMLElement} target
4433 */
4434 const parseHtmlToContainer = (param, target) => {
4435 // DOM element
4436 if (param instanceof HTMLElement) {
4437 target.appendChild(param);
4438 }
4439
4440 // Object
4441 else if (typeof param === 'object') {
4442 handleObject(param, target);
4443 }
4444
4445 // Plain string
4446 else if (param) {
4447 setInnerHtml(target, param);
4448 }
4449 };
4450
4451 /**
4452 * @param {object} param
4453 * @param {HTMLElement} target
4454 */
4455 const handleObject = (param, target) => {
4456 // JQuery element(s)
4457 if ('jquery' in param) {
4458 handleJqueryElem(target, param);
4459 }
4460
4461 // For other objects use their string representation
4462 else {
4463 setInnerHtml(target, param.toString());
4464 }
4465 };
4466
4467 /**
4468 * @param {HTMLElement} target
4469 * @param {any} elem
4470 */
4471 const handleJqueryElem = (target, elem) => {
4472 target.textContent = '';
4473 if (0 in elem) {
4474 for (let i = 0; i in elem; i++) {
4475 target.appendChild(elem[i].cloneNode(true));
4476 }
4477 } else {
4478 target.appendChild(elem.cloneNode(true));
4479 }
4480 };
4481
4482 /**
4483 * @param {SweetAlert} instance
4484 * @param {SweetAlertOptions} params
4485 */
4486 const renderActions = (instance, params) => {
4487 const actions = getActions();
4488 const loader = getLoader();
4489 if (!actions || !loader) {
4490 return;
4491 }
4492
4493 // Actions (buttons) wrapper
4494 if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) {
4495 hide(actions);
4496 } else {
4497 show(actions);
4498 }
4499
4500 // Custom class
4501 applyCustomClass(actions, params, 'actions');
4502
4503 // Render all the buttons
4504 renderButtons(actions, loader, params);
4505
4506 // Loader
4507 setInnerHtml(loader, params.loaderHtml || '');
4508 applyCustomClass(loader, params, 'loader');
4509 };
4510
4511 /**
4512 * @param {HTMLElement} actions
4513 * @param {HTMLElement} loader
4514 * @param {SweetAlertOptions} params
4515 */
4516 function renderButtons(actions, loader, params) {
4517 const confirmButton = getConfirmButton();
4518 const denyButton = getDenyButton();
4519 const cancelButton = getCancelButton();
4520 if (!confirmButton || !denyButton || !cancelButton) {
4521 return;
4522 }
4523
4524 // Render buttons
4525 renderButton(confirmButton, 'confirm', params);
4526 renderButton(denyButton, 'deny', params);
4527 renderButton(cancelButton, 'cancel', params);
4528 handleButtonsStyling(confirmButton, denyButton, cancelButton, params);
4529 if (params.reverseButtons) {
4530 if (params.toast) {
4531 actions.insertBefore(cancelButton, confirmButton);
4532 actions.insertBefore(denyButton, confirmButton);
4533 } else {
4534 actions.insertBefore(cancelButton, loader);
4535 actions.insertBefore(denyButton, loader);
4536 actions.insertBefore(confirmButton, loader);
4537 }
4538 }
4539 }
4540
4541 /**
4542 * @param {HTMLElement} confirmButton
4543 * @param {HTMLElement} denyButton
4544 * @param {HTMLElement} cancelButton
4545 * @param {SweetAlertOptions} params
4546 */
4547 function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) {
4548 if (!params.buttonsStyling) {
4549 removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4550 return;
4551 }
4552 addClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
4553
4554 // Apply custom background colors and outline colors to action buttons
4555 /** @type {[HTMLElement, string, string | undefined][]} */
4556 const buttons = [[confirmButton, 'confirm', params.confirmButtonColor], [denyButton, 'deny', params.denyButtonColor], [cancelButton, 'cancel', params.cancelButtonColor]];
4557 buttons.forEach(([button, type, color]) => {
4558 if (color) {
4559 button.style.setProperty(`--swal2-${type}-button-background-color`, color);
4560 }
4561 applyOutlineColor(button);
4562 });
4563 }
4564
4565 /**
4566 * @param {HTMLElement} button
4567 */
4568 function applyOutlineColor(button) {
4569 const buttonStyle = window.getComputedStyle(button);
4570 if (buttonStyle.getPropertyValue('--swal2-action-button-focus-box-shadow')) {
4571 // If the button already has a custom outline color, no need to change it
4572 return;
4573 }
4574 const outlineColor = buttonStyle.backgroundColor.replace(/rgba?\((\d+), (\d+), (\d+).*/, 'rgba($1, $2, $3, 0.5)');
4575 button.style.setProperty('--swal2-action-button-focus-box-shadow', buttonStyle.getPropertyValue('--swal2-outline').replace(/ rgba\(.*/, ` ${outlineColor}`));
4576 }
4577
4578 /**
4579 * @param {HTMLElement} button
4580 * @param {'confirm' | 'deny' | 'cancel'} buttonType
4581 * @param {SweetAlertOptions} params
4582 */
4583 function renderButton(button, buttonType, params) {
4584 const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType);
4585 toggle(button, params[`show${buttonName}Button`], 'inline-block');
4586 setInnerHtml(button, params[`${buttonType}ButtonText`] || ''); // Set caption text
4587 button.setAttribute('aria-label', params[`${buttonType}ButtonAriaLabel`] || ''); // ARIA label
4588
4589 // Add buttons custom classes
4590 button.className = swalClasses[buttonType];
4591 applyCustomClass(button, params, `${buttonType}Button`);
4592 }
4593
4594 /**
4595 * @param {SweetAlert} instance
4596 * @param {SweetAlertOptions} params
4597 */
4598 const renderCloseButton = (instance, params) => {
4599 const closeButton = getCloseButton();
4600 if (!closeButton) {
4601 return;
4602 }
4603 setInnerHtml(closeButton, params.closeButtonHtml || '');
4604
4605 // Custom class
4606 applyCustomClass(closeButton, params, 'closeButton');
4607 toggle(closeButton, params.showCloseButton);
4608 closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || '');
4609 };
4610
4611 /**
4612 * @param {SweetAlert} instance
4613 * @param {SweetAlertOptions} params
4614 */
4615 const renderContainer = (instance, params) => {
4616 const container = getContainer();
4617 if (!container) {
4618 return;
4619 }
4620 handleBackdropParam(container, params.backdrop);
4621 handlePositionParam(container, params.position);
4622 handleGrowParam(container, params.grow);
4623
4624 // Custom class
4625 applyCustomClass(container, params, 'container');
4626 };
4627
4628 /**
4629 * @param {HTMLElement} container
4630 * @param {SweetAlertOptions['backdrop']} backdrop
4631 */
4632 function handleBackdropParam(container, backdrop) {
4633 if (typeof backdrop === 'string') {
4634 container.style.background = backdrop;
4635 } else if (!backdrop) {
4636 addClass([document.documentElement, document.body], swalClasses['no-backdrop']);
4637 }
4638 }
4639
4640 /**
4641 * @param {HTMLElement} container
4642 * @param {SweetAlertOptions['position']} position
4643 */
4644 function handlePositionParam(container, position) {
4645 if (!position) {
4646 return;
4647 }
4648 if (position in swalClasses) {
4649 addClass(container, swalClasses[position]);
4650 } else {
4651 warn('The "position" parameter is not valid, defaulting to "center"');
4652 addClass(container, swalClasses.center);
4653 }
4654 }
4655
4656 /**
4657 * @param {HTMLElement} container
4658 * @param {SweetAlertOptions['grow']} grow
4659 */
4660 function handleGrowParam(container, grow) {
4661 if (!grow) {
4662 return;
4663 }
4664 addClass(container, swalClasses[`grow-${grow}`]);
4665 }
4666
4667 /**
4668 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
4669 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
4670 * This is the approach that Babel will probably take to implement private methods/fields
4671 * https://github.com/tc39/proposal-private-methods
4672 * https://github.com/babel/babel/pull/7555
4673 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
4674 * then we can use that language feature.
4675 */
4676
4677 var privateProps = {
4678 innerParams: new WeakMap(),
4679 domCache: new WeakMap(),
4680 focusedElement: new WeakMap()
4681 };
4682
4683 /// <reference path="../../../../sweetalert2.d.ts"/>
4684
4685
4686 /** @type {InputClass[]} */
4687 const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
4688
4689 /**
4690 * @param {SweetAlert} instance
4691 * @param {SweetAlertOptions} params
4692 */
4693 const renderInput = (instance, params) => {
4694 const popup = getPopup();
4695 if (!popup) {
4696 return;
4697 }
4698 const innerParams = privateProps.innerParams.get(instance);
4699 const rerender = !innerParams || params.input !== innerParams.input;
4700 inputClasses.forEach(inputClass => {
4701 const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]);
4702 if (!inputContainer) {
4703 return;
4704 }
4705
4706 // set attributes
4707 setAttributes(inputClass, params.inputAttributes);
4708
4709 // set class
4710 inputContainer.className = swalClasses[inputClass];
4711 if (rerender) {
4712 hide(inputContainer);
4713 }
4714 });
4715 if (params.input) {
4716 if (rerender) {
4717 showInput(params);
4718 }
4719 // set custom class
4720 setCustomClass(params);
4721 }
4722 };
4723
4724 /**
4725 * @param {SweetAlertOptions} params
4726 */
4727 const showInput = params => {
4728 if (!params.input) {
4729 return;
4730 }
4731 if (!renderInputType[params.input]) {
4732 error(`Unexpected type of input! Expected ${Object.keys(renderInputType).join(' | ')}, got "${params.input}"`);
4733 return;
4734 }
4735 const inputContainer = getInputContainer(params.input);
4736 if (!inputContainer) {
4737 return;
4738 }
4739 const input = renderInputType[params.input](inputContainer, params);
4740 show(inputContainer);
4741
4742 // input autofocus
4743 if (params.inputAutoFocus) {
4744 setTimeout(() => {
4745 focusInput(input);
4746 });
4747 }
4748 };
4749
4750 /**
4751 * @param {HTMLInputElement} input
4752 */
4753 const removeAttributes = input => {
4754 for (const {
4755 name
4756 } of Array.from(input.attributes)) {
4757 if (!['id', 'type', 'value', 'style'].includes(name)) {
4758 input.removeAttribute(name);
4759 }
4760 }
4761 };
4762
4763 /**
4764 * @param {InputClass} inputClass
4765 * @param {SweetAlertOptions['inputAttributes']} inputAttributes
4766 */
4767 const setAttributes = (inputClass, inputAttributes) => {
4768 const popup = getPopup();
4769 if (!popup) {
4770 return;
4771 }
4772 const input = getInput$1(popup, inputClass);
4773 if (!input) {
4774 return;
4775 }
4776 removeAttributes(input);
4777 for (const attr in inputAttributes) {
4778 input.setAttribute(attr, inputAttributes[attr]);
4779 }
4780 };
4781
4782 /**
4783 * @param {SweetAlertOptions} params
4784 */
4785 const setCustomClass = params => {
4786 if (!params.input) {
4787 return;
4788 }
4789 const inputContainer = getInputContainer(params.input);
4790 if (inputContainer) {
4791 applyCustomClass(inputContainer, params, 'input');
4792 }
4793 };
4794
4795 /**
4796 * @param {HTMLInputElement | HTMLTextAreaElement} input
4797 * @param {SweetAlertOptions} params
4798 */
4799 const setInputPlaceholder = (input, params) => {
4800 if (!input.placeholder && params.inputPlaceholder) {
4801 input.placeholder = params.inputPlaceholder;
4802 }
4803 };
4804
4805 /**
4806 * @param {Input} input
4807 * @param {Input} prependTo
4808 * @param {SweetAlertOptions} params
4809 */
4810 const setInputLabel = (input, prependTo, params) => {
4811 if (params.inputLabel) {
4812 const label = document.createElement('label');
4813 const labelClass = swalClasses['input-label'];
4814 label.setAttribute('for', input.id);
4815 label.className = labelClass;
4816 if (typeof params.customClass === 'object') {
4817 addClass(label, params.customClass.inputLabel);
4818 }
4819 label.innerText = params.inputLabel;
4820 prependTo.insertAdjacentElement('beforebegin', label);
4821 }
4822 };
4823
4824 /**
4825 * @param {SweetAlertInput} inputType
4826 * @returns {HTMLElement | undefined}
4827 */
4828 const getInputContainer = inputType => {
4829 const popup = getPopup();
4830 if (!popup) {
4831 return;
4832 }
4833 return getDirectChildByClass(popup, swalClasses[(/** @type {SwalClass} */inputType)] || swalClasses.input);
4834 };
4835
4836 /**
4837 * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input
4838 * @param {SweetAlertOptions['inputValue']} inputValue
4839 */
4840 const checkAndSetInputValue = (input, inputValue) => {
4841 if (['string', 'number'].includes(typeof inputValue)) {
4842 input.value = `${inputValue}`;
4843 } else if (!isPromise(inputValue)) {
4844 warn(`Unexpected type of inputValue! Expected "string", "number" or "Promise", got "${typeof inputValue}"`);
4845 }
4846 };
4847
4848 /** @type {Record<SweetAlertInput, (input: Input | HTMLElement, params: SweetAlertOptions) => Input>} */
4849 const renderInputType = {};
4850
4851 /**
4852 * @param {Input | HTMLElement} input
4853 * @param {SweetAlertOptions} params
4854 * @returns {Input}
4855 */
4856 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} */
4857 (input, params) => {
4858 // oxfmt-ignore
4859 const inputElement = /** @type {HTMLInputElement} */input;
4860 checkAndSetInputValue(inputElement, params.inputValue);
4861 setInputLabel(inputElement, inputElement, params);
4862 setInputPlaceholder(inputElement, params);
4863 // oxfmt-ignore
4864 inputElement.type = /** @type {string} */params.input;
4865 return inputElement;
4866 };
4867
4868 /**
4869 * @param {Input | HTMLElement} input
4870 * @param {SweetAlertOptions} params
4871 * @returns {Input}
4872 */
4873 renderInputType.file = (input, params) => {
4874 const inputElement = /** @type {HTMLInputElement} */input;
4875 setInputLabel(inputElement, inputElement, params);
4876 setInputPlaceholder(inputElement, params);
4877 return inputElement;
4878 };
4879
4880 /**
4881 * @param {Input | HTMLElement} range
4882 * @param {SweetAlertOptions} params
4883 * @returns {Input}
4884 */
4885 renderInputType.range = (range, params) => {
4886 const rangeContainer = /** @type {HTMLElement} */range;
4887 const rangeInput = rangeContainer.querySelector('input');
4888 const rangeOutput = rangeContainer.querySelector('output');
4889 if (rangeInput) {
4890 checkAndSetInputValue(rangeInput, params.inputValue);
4891 rangeInput.type = /** @type {string} */params.input;
4892 setInputLabel(rangeInput, /** @type {Input} */range, params);
4893 }
4894 if (rangeOutput) {
4895 checkAndSetInputValue(rangeOutput, params.inputValue);
4896 }
4897 return /** @type {Input} */range;
4898 };
4899
4900 /**
4901 * @param {Input | HTMLElement} select
4902 * @param {SweetAlertOptions} params
4903 * @returns {Input}
4904 */
4905 renderInputType.select = (select, params) => {
4906 const selectElement = /** @type {HTMLSelectElement} */select;
4907 selectElement.textContent = '';
4908 if (params.inputPlaceholder) {
4909 const placeholder = document.createElement('option');
4910 setInnerHtml(placeholder, params.inputPlaceholder);
4911 placeholder.value = '';
4912 placeholder.disabled = true;
4913 placeholder.selected = true;
4914 selectElement.appendChild(placeholder);
4915 }
4916 setInputLabel(selectElement, selectElement, params);
4917 return selectElement;
4918 };
4919
4920 /**
4921 * @param {Input | HTMLElement} radio
4922 * @returns {Input}
4923 */
4924 renderInputType.radio = radio => {
4925 const radioElement = /** @type {HTMLElement} */radio;
4926 radioElement.textContent = '';
4927 return /** @type {Input} */radio;
4928 };
4929
4930 /**
4931 * @param {Input | HTMLElement} checkboxContainer
4932 * @param {SweetAlertOptions} params
4933 * @returns {Input}
4934 */
4935 renderInputType.checkbox = (checkboxContainer, params) => {
4936 const popup = getPopup();
4937 if (!popup) {
4938 throw new Error('Popup not found');
4939 }
4940 const checkbox = getInput$1(popup, 'checkbox');
4941 if (!checkbox) {
4942 throw new Error('Checkbox input not found');
4943 }
4944 checkbox.value = '1';
4945 checkbox.checked = Boolean(params.inputValue);
4946 const containerElement = /** @type {HTMLElement} */checkboxContainer;
4947 const label = containerElement.querySelector('span');
4948 if (label) {
4949 const placeholderOrLabel = params.inputPlaceholder || params.inputLabel;
4950 if (placeholderOrLabel) {
4951 setInnerHtml(label, placeholderOrLabel);
4952 }
4953 }
4954 return checkbox;
4955 };
4956
4957 /**
4958 * @param {Input | HTMLElement} textarea
4959 * @param {SweetAlertOptions} params
4960 * @returns {Input}
4961 */
4962 renderInputType.textarea = (textarea, params) => {
4963 const textareaElement = /** @type {HTMLTextAreaElement} */textarea;
4964 checkAndSetInputValue(textareaElement, params.inputValue);
4965 setInputPlaceholder(textareaElement, params);
4966 setInputLabel(textareaElement, textareaElement, params);
4967
4968 /**
4969 * @param {HTMLElement} el
4970 * @returns {number}
4971 */
4972 const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight);
4973
4974 // https://github.com/sweetalert2/sweetalert2/issues/2291
4975 setTimeout(() => {
4976 // https://github.com/sweetalert2/sweetalert2/issues/1699
4977 if ('MutationObserver' in window) {
4978 const popup = getPopup();
4979 if (!popup) {
4980 return;
4981 }
4982 const initialPopupWidth = parseInt(window.getComputedStyle(popup).width);
4983 const textareaResizeHandler = () => {
4984 // check if texarea is still in document (i.e. popup wasn't closed in the meantime)
4985 if (!document.body.contains(textareaElement)) {
4986 return;
4987 }
4988 const textareaWidth = textareaElement.offsetWidth + getMargin(textareaElement);
4989 const popupElement = getPopup();
4990 if (popupElement) {
4991 if (textareaWidth > initialPopupWidth) {
4992 popupElement.style.width = `${textareaWidth}px`;
4993 } else {
4994 applyNumericalStyle(popupElement, 'width', params.width);
4995 }
4996 }
4997 };
4998 new MutationObserver(textareaResizeHandler).observe(textareaElement, {
4999 attributes: true,
5000 attributeFilter: ['style']
5001 });
5002 }
5003 });
5004 return textareaElement;
5005 };
5006
5007 /**
5008 * @param {SweetAlert} instance
5009 * @param {SweetAlertOptions} params
5010 */
5011 const renderContent = (instance, params) => {
5012 const htmlContainer = getHtmlContainer();
5013 if (!htmlContainer) {
5014 return;
5015 }
5016 showWhenInnerHtmlPresent(htmlContainer);
5017 applyCustomClass(htmlContainer, params, 'htmlContainer');
5018
5019 // Content as HTML
5020 if (params.html) {
5021 parseHtmlToContainer(params.html, htmlContainer);
5022 show(htmlContainer, 'block');
5023 }
5024
5025 // Content as plain text
5026 else if (params.text) {
5027 htmlContainer.textContent = params.text;
5028 show(htmlContainer, 'block');
5029 }
5030
5031 // No content
5032 else {
5033 hide(htmlContainer);
5034 }
5035 renderInput(instance, params);
5036 };
5037
5038 /**
5039 * @param {SweetAlert} instance
5040 * @param {SweetAlertOptions} params
5041 */
5042 const renderFooter = (instance, params) => {
5043 const footer = getFooter();
5044 if (!footer) {
5045 return;
5046 }
5047 showWhenInnerHtmlPresent(footer);
5048 toggle(footer, Boolean(params.footer), 'block');
5049 if (params.footer) {
5050 parseHtmlToContainer(params.footer, footer);
5051 }
5052
5053 // Custom class
5054 applyCustomClass(footer, params, 'footer');
5055 };
5056
5057 /**
5058 * @param {SweetAlert} instance
5059 * @param {SweetAlertOptions} params
5060 */
5061 const renderIcon = (instance, params) => {
5062 const innerParams = privateProps.innerParams.get(instance);
5063 const icon = getIcon();
5064 if (!icon) {
5065 return;
5066 }
5067
5068 // if the given icon already rendered, apply the styling without re-rendering the icon
5069 if (innerParams && params.icon === innerParams.icon) {
5070 // Custom or default content
5071 setContent(icon, params);
5072 applyStyles(icon, params);
5073 return;
5074 }
5075 if (!params.icon && !params.iconHtml) {
5076 hide(icon);
5077 return;
5078 }
5079 if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) {
5080 error(`Unknown icon! Expected "success", "error", "warning", "info" or "question", got "${params.icon}"`);
5081 hide(icon);
5082 return;
5083 }
5084 show(icon);
5085
5086 // Custom or default content
5087 setContent(icon, params);
5088 applyStyles(icon, params);
5089
5090 // Animate icon
5091 addClass(icon, params.showClass && params.showClass.icon);
5092
5093 // Re-adjust the success icon on system theme change
5094 const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
5095 colorSchemeQueryList.addEventListener('change', adjustSuccessIconBackgroundColor);
5096 };
5097
5098 /**
5099 * @param {HTMLElement} icon
5100 * @param {SweetAlertOptions} params
5101 */
5102 const applyStyles = (icon, params) => {
5103 for (const [iconType, iconClassName] of Object.entries(iconTypes)) {
5104 if (params.icon !== iconType) {
5105 removeClass(icon, iconClassName);
5106 }
5107 }
5108 addClass(icon, params.icon && iconTypes[params.icon]);
5109
5110 // Icon color
5111 setColor(icon, params);
5112
5113 // Success icon background color
5114 adjustSuccessIconBackgroundColor();
5115
5116 // Custom class
5117 applyCustomClass(icon, params, 'icon');
5118 };
5119
5120 // Adjust success icon background color to match the popup background color
5121 const adjustSuccessIconBackgroundColor = () => {
5122 const popup = getPopup();
5123 if (!popup) {
5124 return;
5125 }
5126 const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color');
5127 /** @type {NodeListOf<HTMLElement>} */
5128 const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix');
5129 successIconParts.forEach(part => {
5130 part.style.backgroundColor = popupBackgroundColor;
5131 });
5132 };
5133
5134 /**
5135 *
5136 * @param {SweetAlertOptions} params
5137 * @returns {string}
5138 */
5139 const successIconHtml = params => `
5140 ${params.animation ? '<div class="swal2-success-circular-line-left"></div>' : ''}
5141 <span class="swal2-success-line-tip"></span> <span class="swal2-success-line-long"></span>
5142 <div class="swal2-success-ring"></div>
5143 ${params.animation ? '<div class="swal2-success-fix"></div>' : ''}
5144 ${params.animation ? '<div class="swal2-success-circular-line-right"></div>' : ''}
5145 `;
5146 const errorIconHtml = `
5147 <span class="swal2-x-mark">
5148 <span class="swal2-x-mark-line-left"></span>
5149 <span class="swal2-x-mark-line-right"></span>
5150 </span>
5151 `;
5152
5153 /**
5154 * @param {HTMLElement} icon
5155 * @param {SweetAlertOptions} params
5156 */
5157 const setContent = (icon, params) => {
5158 if (!params.icon && !params.iconHtml) {
5159 return;
5160 }
5161 let oldContent = icon.innerHTML;
5162 let newContent = '';
5163 if (params.iconHtml) {
5164 newContent = iconContent(params.iconHtml);
5165 } else if (params.icon === 'success') {
5166 newContent = successIconHtml(params);
5167 oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor()
5168 } else if (params.icon === 'error') {
5169 newContent = errorIconHtml;
5170 } else if (params.icon) {
5171 const defaultIconHtml = {
5172 question: '?',
5173 warning: '!',
5174 info: 'i'
5175 };
5176 newContent = iconContent(defaultIconHtml[params.icon]);
5177 }
5178 if (oldContent.trim() !== newContent.trim()) {
5179 setInnerHtml(icon, newContent);
5180 }
5181 };
5182
5183 /**
5184 * @param {HTMLElement} icon
5185 * @param {SweetAlertOptions} params
5186 */
5187 const setColor = (icon, params) => {
5188 if (!params.iconColor) {
5189 return;
5190 }
5191 icon.style.color = params.iconColor;
5192 icon.style.borderColor = params.iconColor;
5193 for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) {
5194 setStyle(icon, sel, 'background-color', params.iconColor);
5195 }
5196 setStyle(icon, '.swal2-success-ring', 'border-color', params.iconColor);
5197 };
5198
5199 /**
5200 * @param {string} content
5201 * @returns {string}
5202 */
5203 const iconContent = content => `<div class="${swalClasses['icon-content']}">${content}</div>`;
5204
5205 /**
5206 * @param {SweetAlert} instance
5207 * @param {SweetAlertOptions} params
5208 */
5209 const renderImage = (instance, params) => {
5210 const image = getImage();
5211 if (!image) {
5212 return;
5213 }
5214 if (!params.imageUrl) {
5215 hide(image);
5216 return;
5217 }
5218 show(image, '');
5219
5220 // Src, alt
5221 image.setAttribute('src', params.imageUrl);
5222 image.setAttribute('alt', params.imageAlt || '');
5223
5224 // Width, height
5225 applyNumericalStyle(image, 'width', params.imageWidth);
5226 applyNumericalStyle(image, 'height', params.imageHeight);
5227
5228 // Class
5229 image.className = swalClasses.image;
5230 applyCustomClass(image, params, 'image');
5231 };
5232
5233 let dragging = false;
5234 let mousedownX = 0;
5235 let mousedownY = 0;
5236 let initialX = 0;
5237 let initialY = 0;
5238
5239 /**
5240 * @param {HTMLElement} popup
5241 */
5242 const addDraggableListeners = popup => {
5243 popup.addEventListener('mousedown', down);
5244 document.body.addEventListener('mousemove', move);
5245 popup.addEventListener('mouseup', up);
5246 popup.addEventListener('touchstart', down);
5247 document.body.addEventListener('touchmove', move);
5248 popup.addEventListener('touchend', up);
5249 };
5250
5251 /**
5252 * @param {HTMLElement} popup
5253 */
5254 const removeDraggableListeners = popup => {
5255 popup.removeEventListener('mousedown', down);
5256 document.body.removeEventListener('mousemove', move);
5257 popup.removeEventListener('mouseup', up);
5258 popup.removeEventListener('touchstart', down);
5259 document.body.removeEventListener('touchmove', move);
5260 popup.removeEventListener('touchend', up);
5261 };
5262
5263 /**
5264 * @param {MouseEvent | TouchEvent} event
5265 */
5266 const down = event => {
5267 const popup = getPopup();
5268 if (!popup) {
5269 return;
5270 }
5271 const icon = getIcon();
5272 if (event.target === popup || icon && icon.contains(/** @type {HTMLElement} */event.target)) {
5273 dragging = true;
5274 const clientXY = getClientXY(event);
5275 mousedownX = clientXY.clientX;
5276 mousedownY = clientXY.clientY;
5277 initialX = parseInt(popup.style.insetInlineStart) || 0;
5278 initialY = parseInt(popup.style.insetBlockStart) || 0;
5279 addClass(popup, 'swal2-dragging');
5280 }
5281 };
5282
5283 /**
5284 * @param {MouseEvent | TouchEvent} event
5285 */
5286 const move = event => {
5287 const popup = getPopup();
5288 if (!popup) {
5289 return;
5290 }
5291 if (dragging) {
5292 let {
5293 clientX,
5294 clientY
5295 } = getClientXY(event);
5296 const deltaX = clientX - mousedownX;
5297 // In RTL mode, negate the horizontal delta since insetInlineStart refers to the right edge
5298 popup.style.insetInlineStart = `${initialX + (globalState.isRTL ? -deltaX : deltaX)}px`;
5299 popup.style.insetBlockStart = `${initialY + (clientY - mousedownY)}px`;
5300 }
5301 };
5302 const up = () => {
5303 const popup = getPopup();
5304 dragging = false;
5305 removeClass(popup, 'swal2-dragging');
5306 };
5307
5308 /**
5309 * @param {MouseEvent | TouchEvent} event
5310 * @returns {{ clientX: number, clientY: number }}
5311 */
5312 const getClientXY = event => {
5313 const source = event.type.startsWith('touch') ? /** @type {TouchEvent} */event.touches[0] : (/** @type {MouseEvent} */event);
5314 return {
5315 clientX: source.clientX,
5316 clientY: source.clientY
5317 };
5318 };
5319
5320 /**
5321 * @param {SweetAlert} instance
5322 * @param {SweetAlertOptions} params
5323 */
5324 const renderPopup = (instance, params) => {
5325 const container = getContainer();
5326 const popup = getPopup();
5327 if (!container || !popup) {
5328 return;
5329 }
5330
5331 // Width
5332 // https://github.com/sweetalert2/sweetalert2/issues/2170
5333 if (params.toast) {
5334 applyNumericalStyle(container, 'width', params.width);
5335 popup.style.width = '100%';
5336 const loader = getLoader();
5337 if (loader) {
5338 popup.insertBefore(loader, getIcon());
5339 }
5340 } else {
5341 applyNumericalStyle(popup, 'width', params.width);
5342 }
5343
5344 // Padding
5345 applyNumericalStyle(popup, 'padding', params.padding);
5346
5347 // Color
5348 if (params.color) {
5349 popup.style.color = params.color;
5350 }
5351
5352 // Background
5353 if (params.background) {
5354 popup.style.background = params.background;
5355 }
5356 hide(getValidationMessage());
5357
5358 // Classes
5359 addClasses$1(popup, params);
5360 if (params.draggable && !params.toast) {
5361 addClass(popup, swalClasses.draggable);
5362 addDraggableListeners(popup);
5363 } else {
5364 removeClass(popup, swalClasses.draggable);
5365 removeDraggableListeners(popup);
5366 }
5367 };
5368
5369 /**
5370 * @param {HTMLElement} popup
5371 * @param {SweetAlertOptions} params
5372 */
5373 const addClasses$1 = (popup, params) => {
5374 const showClass = params.showClass || {};
5375 // Default Class + showClass when updating Swal.update({})
5376 popup.className = `${swalClasses.popup} ${isVisible$1(popup) ? showClass.popup : ''}`;
5377 if (params.toast) {
5378 addClass([document.documentElement, document.body], swalClasses['toast-shown']);
5379 addClass(popup, swalClasses.toast);
5380 } else {
5381 addClass(popup, swalClasses.modal);
5382 }
5383
5384 // Custom class
5385 applyCustomClass(popup, params, 'popup');
5386 // TODO: remove in the next major
5387 if (typeof params.customClass === 'string') {
5388 addClass(popup, params.customClass);
5389 }
5390
5391 // Icon class (#1842)
5392 if (params.icon) {
5393 addClass(popup, swalClasses[`icon-${params.icon}`]);
5394 }
5395 };
5396
5397 /**
5398 * @param {SweetAlert} instance
5399 * @param {SweetAlertOptions} params
5400 */
5401 const renderProgressSteps = (instance, params) => {
5402 const progressStepsContainer = getProgressSteps();
5403 if (!progressStepsContainer) {
5404 return;
5405 }
5406 const {
5407 progressSteps,
5408 currentProgressStep
5409 } = params;
5410 if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) {
5411 hide(progressStepsContainer);
5412 return;
5413 }
5414 show(progressStepsContainer);
5415 progressStepsContainer.textContent = '';
5416 if (currentProgressStep >= progressSteps.length) {
5417 warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)');
5418 }
5419 progressSteps.forEach((step, index) => {
5420 const stepEl = createStepElement(step);
5421 progressStepsContainer.appendChild(stepEl);
5422 if (index === currentProgressStep) {
5423 addClass(stepEl, swalClasses['active-progress-step']);
5424 }
5425 if (index !== progressSteps.length - 1) {
5426 const lineEl = createLineElement(params);
5427 progressStepsContainer.appendChild(lineEl);
5428 }
5429 });
5430 };
5431
5432 /**
5433 * @param {string} step
5434 * @returns {HTMLLIElement}
5435 */
5436 const createStepElement = step => {
5437 const stepEl = document.createElement('li');
5438 addClass(stepEl, swalClasses['progress-step']);
5439 setInnerHtml(stepEl, step);
5440 return stepEl;
5441 };
5442
5443 /**
5444 * @param {SweetAlertOptions} params
5445 * @returns {HTMLLIElement}
5446 */
5447 const createLineElement = params => {
5448 const lineEl = document.createElement('li');
5449 addClass(lineEl, swalClasses['progress-step-line']);
5450 if (params.progressStepsDistance) {
5451 applyNumericalStyle(lineEl, 'width', params.progressStepsDistance);
5452 }
5453 return lineEl;
5454 };
5455
5456 /**
5457 * @param {SweetAlert} instance
5458 * @param {SweetAlertOptions} params
5459 */
5460 const renderTitle = (instance, params) => {
5461 const title = getTitle();
5462 if (!title) {
5463 return;
5464 }
5465 showWhenInnerHtmlPresent(title);
5466 toggle(title, Boolean(params.title || params.titleText), 'block');
5467 if (params.title) {
5468 parseHtmlToContainer(params.title, title);
5469 }
5470 if (params.titleText) {
5471 title.innerText = params.titleText;
5472 }
5473
5474 // Custom class
5475 applyCustomClass(title, params, 'title');
5476 };
5477
5478 /**
5479 * @param {SweetAlert} instance
5480 * @param {SweetAlertOptions} params
5481 */
5482 const render = (instance, params) => {
5483 var _globalState$eventEmi;
5484 renderPopup(instance, params);
5485 renderContainer(instance, params);
5486 renderProgressSteps(instance, params);
5487 renderIcon(instance, params);
5488 renderImage(instance, params);
5489 renderTitle(instance, params);
5490 renderCloseButton(instance, params);
5491 renderContent(instance, params);
5492 renderActions(instance, params);
5493 renderFooter(instance, params);
5494 const popup = getPopup();
5495 if (typeof params.didRender === 'function' && popup) {
5496 params.didRender(popup);
5497 }
5498 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didRender', popup);
5499 };
5500
5501 /*
5502 * Global function to determine if SweetAlert2 popup is shown
5503 */
5504 const isVisible = () => {
5505 return isVisible$1(getPopup());
5506 };
5507
5508 /*
5509 * Global function to click 'Confirm' button
5510 */
5511 const clickConfirm = () => {
5512 var _dom$getConfirmButton;
5513 return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click();
5514 };
5515
5516 /*
5517 * Global function to click 'Deny' button
5518 */
5519 const clickDeny = () => {
5520 var _dom$getDenyButton;
5521 return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click();
5522 };
5523
5524 /*
5525 * Global function to click 'Cancel' button
5526 */
5527 const clickCancel = () => {
5528 var _dom$getCancelButton;
5529 return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click();
5530 };
5531
5532 /** @type {Record<DismissReason, DismissReason>} */
5533 const DismissReason = Object.freeze({
5534 cancel: 'cancel',
5535 backdrop: 'backdrop',
5536 close: 'close',
5537 esc: 'esc',
5538 timer: 'timer'
5539 });
5540
5541 /**
5542 * @param {GlobalState} globalState
5543 */
5544 const removeKeydownHandler = globalState => {
5545 if (globalState.keydownTarget && globalState.keydownHandlerAdded && globalState.keydownHandler) {
5546 const handler = /** @type {EventListenerOrEventListenerObject} */
5547 /** @type {unknown} */globalState.keydownHandler;
5548 globalState.keydownTarget.removeEventListener('keydown', handler, {
5549 capture: globalState.keydownListenerCapture
5550 });
5551 globalState.keydownHandlerAdded = false;
5552 }
5553 };
5554
5555 /**
5556 * @param {GlobalState} globalState
5557 * @param {SweetAlertOptions} innerParams
5558 * @param {(dismiss: DismissReason) => void} dismissWith
5559 */
5560 const addKeydownHandler = (globalState, innerParams, dismissWith) => {
5561 removeKeydownHandler(globalState);
5562 if (!innerParams.toast) {
5563 /** @type {(this: HTMLElement, event: KeyboardEvent) => void} */
5564 const handler = e => keydownHandler(innerParams, e, dismissWith);
5565 globalState.keydownHandler = handler;
5566 const target = innerParams.keydownListenerCapture ? window : getPopup();
5567 if (target) {
5568 globalState.keydownTarget = target;
5569 globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
5570 const eventHandler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */handler;
5571 globalState.keydownTarget.addEventListener('keydown', eventHandler, {
5572 capture: globalState.keydownListenerCapture
5573 });
5574 globalState.keydownHandlerAdded = true;
5575 }
5576 }
5577 };
5578
5579 /**
5580 * @param {number} index
5581 * @param {number} increment
5582 * @returns {boolean} shouldPreventDefault
5583 */
5584 const setFocus = (index, increment) => {
5585 var _dom$getPopup;
5586 const focusableElements = getFocusableElements();
5587 // search for visible elements and select the next possible match
5588 if (focusableElements.length) {
5589 index = index + increment;
5590
5591 // shift + tab when .swal2-popup is focused
5592 if (index === -2) {
5593 index = focusableElements.length - 1;
5594 }
5595
5596 // rollover to first item
5597 if (index === focusableElements.length) {
5598 index = 0;
5599
5600 // go to last item
5601 } else if (index === -1) {
5602 index = focusableElements.length - 1;
5603 }
5604 focusableElements[index].focus();
5605
5606 // don't prevent default for iframes (Firefox fix)
5607 // https://github.com/sweetalert2/sweetalert2/issues/2931
5608 if (isFirefox() && focusableElements[index] instanceof HTMLIFrameElement) {
5609 return false;
5610 }
5611 return true;
5612 }
5613 // no visible focusable elements, focus the popup
5614 (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus();
5615 return true;
5616 };
5617 const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
5618 const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
5619
5620 /**
5621 * @param {SweetAlertOptions} innerParams
5622 * @param {KeyboardEvent} event
5623 * @param {(dismiss: DismissReason) => void} dismissWith
5624 */
5625 const keydownHandler = (innerParams, event, dismissWith) => {
5626 if (!innerParams) {
5627 return; // This instance has already been destroyed
5628 }
5629
5630 // Ignore keydown during IME composition
5631 // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
5632 // https://github.com/sweetalert2/sweetalert2/issues/720
5633 // https://github.com/sweetalert2/sweetalert2/issues/2406
5634 if (event.isComposing || event.keyCode === 229) {
5635 return;
5636 }
5637 if (innerParams.stopKeydownPropagation) {
5638 event.stopPropagation();
5639 }
5640
5641 // ENTER
5642 if (event.key === 'Enter') {
5643 handleEnter(event, innerParams);
5644 }
5645
5646 // TAB
5647 else if (event.key === 'Tab') {
5648 handleTab(event);
5649 }
5650
5651 // ARROWS - switch focus between buttons
5652 else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) {
5653 handleArrows(event.key);
5654 }
5655
5656 // ESC
5657 else if (event.key === 'Escape') {
5658 handleEsc(event, innerParams, dismissWith);
5659 }
5660 };
5661
5662 /**
5663 * @param {KeyboardEvent} event
5664 * @param {SweetAlertOptions} innerParams
5665 */
5666 const handleEnter = (event, innerParams) => {
5667 // https://github.com/sweetalert2/sweetalert2/issues/2386
5668 if (!callIfFunction(innerParams.allowEnterKey)) {
5669 return;
5670 }
5671 const popup = getPopup();
5672 if (!popup || !innerParams.input) {
5673 return;
5674 }
5675 const input = getInput$1(popup, innerParams.input);
5676 if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) {
5677 if (['textarea', 'file'].includes(innerParams.input)) {
5678 return; // do not submit
5679 }
5680 clickConfirm();
5681 event.preventDefault();
5682 }
5683 };
5684
5685 /**
5686 * @param {KeyboardEvent} event
5687 */
5688 const handleTab = event => {
5689 const targetElement = event.target;
5690 const focusableElements = getFocusableElements();
5691 const btnIndex = focusableElements.findIndex(el => el === targetElement);
5692
5693 // don't prevent default for iframes (Firefox fix)
5694 // https://github.com/sweetalert2/sweetalert2/issues/2931
5695 let shouldPreventDefault = true;
5696
5697 // Cycle to the next button
5698 if (!event.shiftKey) {
5699 shouldPreventDefault = setFocus(btnIndex, 1);
5700 }
5701
5702 // Cycle to the prev button
5703 else {
5704 shouldPreventDefault = setFocus(btnIndex, -1);
5705 }
5706 event.stopPropagation();
5707 if (shouldPreventDefault) {
5708 event.preventDefault();
5709 }
5710 };
5711
5712 /**
5713 * @param {string} key
5714 */
5715 const handleArrows = key => {
5716 const actions = getActions();
5717 const confirmButton = getConfirmButton();
5718 const denyButton = getDenyButton();
5719 const cancelButton = getCancelButton();
5720 if (!actions || !confirmButton || !denyButton || !cancelButton) {
5721 return;
5722 }
5723 /** @type HTMLElement[] */
5724 const buttons = [confirmButton, denyButton, cancelButton];
5725 if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) {
5726 return;
5727 }
5728 const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
5729 let buttonToFocus = document.activeElement;
5730 if (!buttonToFocus) {
5731 return;
5732 }
5733 for (let i = 0; i < actions.children.length; i++) {
5734 buttonToFocus = buttonToFocus[sibling];
5735 if (!buttonToFocus) {
5736 return;
5737 }
5738 if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) {
5739 break;
5740 }
5741 }
5742 if (buttonToFocus instanceof HTMLButtonElement) {
5743 buttonToFocus.focus();
5744 }
5745 };
5746
5747 /**
5748 * @param {KeyboardEvent} event
5749 * @param {SweetAlertOptions} innerParams
5750 * @param {(dismiss: DismissReason) => void} dismissWith
5751 */
5752 const handleEsc = (event, innerParams, dismissWith) => {
5753 event.preventDefault();
5754 if (callIfFunction(innerParams.allowEscapeKey)) {
5755 dismissWith(DismissReason.esc);
5756 }
5757 };
5758
5759 /**
5760 * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
5761 * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
5762 * This is the approach that Babel will probably take to implement private methods/fields
5763 * https://github.com/tc39/proposal-private-methods
5764 * https://github.com/babel/babel/pull/7555
5765 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
5766 * then we can use that language feature.
5767 */
5768
5769 var privateMethods = {
5770 swalPromiseResolve: new WeakMap(),
5771 swalPromiseReject: new WeakMap()
5772 };
5773
5774 // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/
5775 // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
5776 // elements not within the active modal dialog will not be surfaced if a user opens a screen
5777 // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
5778
5779 const setAriaHidden = () => {
5780 const container = getContainer();
5781 const bodyChildren = Array.from(document.body.children);
5782 bodyChildren.forEach(el => {
5783 if (el.contains(container)) {
5784 return;
5785 }
5786 if (el.hasAttribute('aria-hidden')) {
5787 el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || '');
5788 }
5789 el.setAttribute('aria-hidden', 'true');
5790 });
5791 };
5792 const unsetAriaHidden = () => {
5793 const bodyChildren = Array.from(document.body.children);
5794 bodyChildren.forEach(el => {
5795 if (el.hasAttribute('data-previous-aria-hidden')) {
5796 el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || '');
5797 el.removeAttribute('data-previous-aria-hidden');
5798 } else {
5799 el.removeAttribute('aria-hidden');
5800 }
5801 });
5802 };
5803
5804 // @ts-ignore
5805 const isSafariOrIOS = typeof window !== 'undefined' && Boolean(window.GestureEvent); // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394
5806
5807 // @ts-ignore
5808 const isIOS = isSafariOrIOS && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
5809
5810 /**
5811 * Fix iOS scrolling
5812 * http://stackoverflow.com/q/39626302
5813 */
5814 const iOSfix = () => {
5815 if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) {
5816 const offset = document.body.scrollTop;
5817 document.body.style.top = `${offset * -1}px`;
5818 addClass(document.body, swalClasses.iosfix);
5819 lockBodyScroll();
5820 }
5821 };
5822
5823 /**
5824 * https://github.com/sweetalert2/sweetalert2/issues/1246
5825 */
5826 const lockBodyScroll = () => {
5827 const container = getContainer();
5828 if (!container) {
5829 return;
5830 }
5831 /** @type {boolean} */
5832 let preventTouchMove;
5833 /**
5834 * @param {TouchEvent} event
5835 */
5836 container.ontouchstart = event => {
5837 preventTouchMove = shouldPreventTouchMove(event);
5838 };
5839 /**
5840 * @param {TouchEvent} event
5841 */
5842 container.ontouchmove = event => {
5843 if (preventTouchMove) {
5844 event.preventDefault();
5845 event.stopPropagation();
5846 }
5847 };
5848 };
5849
5850 /**
5851 * @param {TouchEvent} event
5852 * @returns {boolean}
5853 */
5854 const shouldPreventTouchMove = event => {
5855 const target = event.target;
5856 const container = getContainer();
5857 const htmlContainer = getHtmlContainer();
5858 if (!container || !htmlContainer) {
5859 return false;
5860 }
5861 if (isStylus(event) || isZoom(event)) {
5862 return false;
5863 }
5864 if (target === container) {
5865 return true;
5866 }
5867 if (!isScrollable(container) && target instanceof HTMLElement && !selfOrParentIsScrollable(target, htmlContainer) &&
5868 // #2823
5869 target.tagName !== 'INPUT' &&
5870 // #1603
5871 target.tagName !== 'TEXTAREA' &&
5872 // #2266
5873 !(isScrollable(htmlContainer) &&
5874 // #1944
5875 htmlContainer.contains(target))) {
5876 return true;
5877 }
5878 return false;
5879 };
5880
5881 /**
5882 * https://github.com/sweetalert2/sweetalert2/issues/1786
5883 *
5884 * @param {TouchEvent} event
5885 * @returns {boolean}
5886 */
5887 const isStylus = event => {
5888 return Boolean(event.touches && event.touches.length &&
5889 // @ts-ignore - touchType is not a standard property
5890 event.touches[0].touchType === 'stylus');
5891 };
5892
5893 /**
5894 * https://github.com/sweetalert2/sweetalert2/issues/1891
5895 *
5896 * @param {TouchEvent} event
5897 * @returns {boolean}
5898 */
5899 const isZoom = event => {
5900 return event.touches && event.touches.length > 1;
5901 };
5902 const undoIOSfix = () => {
5903 if (hasClass(document.body, swalClasses.iosfix)) {
5904 const offset = parseInt(document.body.style.top, 10);
5905 removeClass(document.body, swalClasses.iosfix);
5906 document.body.style.top = '';
5907 document.body.scrollTop = offset * -1;
5908 }
5909 };
5910
5911 /**
5912 * Measure scrollbar width for padding body during modal show/hide
5913 * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js
5914 *
5915 * @returns {number}
5916 */
5917 const measureScrollbar = () => {
5918 const scrollDiv = document.createElement('div');
5919 scrollDiv.className = swalClasses['scrollbar-measure'];
5920 document.body.appendChild(scrollDiv);
5921 const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
5922 document.body.removeChild(scrollDiv);
5923 return scrollbarWidth;
5924 };
5925
5926 /**
5927 * Remember state in cases where opening and handling a modal will fiddle with it.
5928 * @type {number | null}
5929 */
5930 let previousBodyPadding = null;
5931
5932 /**
5933 * @param {string} initialBodyOverflow
5934 */
5935 const replaceScrollbarWithPadding = initialBodyOverflow => {
5936 // for queues, do not do this more than once
5937 if (previousBodyPadding !== null) {
5938 return;
5939 }
5940 // if the body has overflow
5941 if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663
5942 ) {
5943 // add padding so the content doesn't shift after removal of scrollbar
5944 previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
5945 document.body.style.paddingRight = `${previousBodyPadding + measureScrollbar()}px`;
5946 }
5947 };
5948 const undoReplaceScrollbarWithPadding = () => {
5949 if (previousBodyPadding !== null) {
5950 document.body.style.paddingRight = `${previousBodyPadding}px`;
5951 previousBodyPadding = null;
5952 }
5953 };
5954
5955 /**
5956 * @param {SweetAlert} instance
5957 * @param {HTMLElement} container
5958 * @param {boolean} returnFocus
5959 * @param {(() => void) | undefined} didClose
5960 */
5961 function removePopupAndResetState(instance, container, returnFocus, didClose) {
5962 if (isToast()) {
5963 triggerDidCloseAndDispose(instance, didClose);
5964 } else {
5965 restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
5966 removeKeydownHandler(globalState);
5967 }
5968
5969 // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088
5970 // for some reason removing the container in Safari will scroll the document to bottom
5971 if (isSafariOrIOS) {
5972 container.setAttribute('style', 'display:none !important');
5973 container.removeAttribute('class');
5974 container.innerHTML = '';
5975 } else {
5976 container.remove();
5977 }
5978 if (isModal()) {
5979 undoReplaceScrollbarWithPadding();
5980 undoIOSfix();
5981 unsetAriaHidden();
5982 }
5983 removeBodyClasses();
5984 }
5985
5986 /**
5987 * Remove SweetAlert2 classes from body
5988 */
5989 function removeBodyClasses() {
5990 removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
5991 }
5992
5993 /**
5994 * Instance method to close sweetAlert
5995 *
5996 * @param {SweetAlertResult | undefined} resolveValue
5997 * @this {SweetAlert}
5998 */
5999 function close(resolveValue) {
6000 resolveValue = prepareResolveValue(resolveValue);
6001 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
6002 const didClose = triggerClosePopup(this);
6003 if (this.isAwaitingPromise) {
6004 // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
6005 if (!resolveValue.isDismissed) {
6006 handleAwaitingPromise(this);
6007 swalPromiseResolve(resolveValue);
6008 }
6009 } else if (didClose) {
6010 // Resolve Swal promise
6011 swalPromiseResolve(resolveValue);
6012 }
6013 }
6014
6015 /**
6016 * @param {SweetAlert} instance
6017 * @returns {boolean}
6018 */
6019 const triggerClosePopup = instance => {
6020 const popup = getPopup();
6021 if (!popup) {
6022 return false;
6023 }
6024 const innerParams = privateProps.innerParams.get(instance);
6025 if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
6026 return false;
6027 }
6028 removeClass(popup, innerParams.showClass.popup);
6029 addClass(popup, innerParams.hideClass.popup);
6030 const backdrop = getContainer();
6031 removeClass(backdrop, innerParams.showClass.backdrop);
6032 addClass(backdrop, innerParams.hideClass.backdrop);
6033 handlePopupAnimation(instance, popup, innerParams);
6034 return true;
6035 };
6036
6037 /**
6038 * @param {Error | string} error
6039 * @this {SweetAlert}
6040 */
6041 function rejectPromise(error) {
6042 const rejectPromise = privateMethods.swalPromiseReject.get(this);
6043 handleAwaitingPromise(this);
6044 if (rejectPromise) {
6045 // Reject Swal promise
6046 rejectPromise(error);
6047 }
6048 }
6049
6050 /**
6051 * @param {SweetAlert} instance
6052 */
6053 const handleAwaitingPromise = instance => {
6054 if (instance.isAwaitingPromise) {
6055 // @ts-ignore
6056 delete instance.isAwaitingPromise;
6057 // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
6058 if (!privateProps.innerParams.get(instance)) {
6059 instance._destroy();
6060 }
6061 }
6062 };
6063
6064 /**
6065 * @param {SweetAlertResult | undefined} resolveValue
6066 * @returns {SweetAlertResult}
6067 */
6068 const prepareResolveValue = resolveValue => {
6069 // When user calls Swal.close()
6070 if (typeof resolveValue === 'undefined') {
6071 return {
6072 isConfirmed: false,
6073 isDenied: false,
6074 isDismissed: true
6075 };
6076 }
6077 return Object.assign({
6078 isConfirmed: false,
6079 isDenied: false,
6080 isDismissed: false
6081 }, resolveValue);
6082 };
6083
6084 /**
6085 * @param {SweetAlert} instance
6086 * @param {HTMLElement} popup
6087 * @param {SweetAlertOptions} innerParams
6088 */
6089 const handlePopupAnimation = (instance, popup, innerParams) => {
6090 var _globalState$eventEmi;
6091 const container = getContainer();
6092 // If animation is supported, animate
6093 const animationIsSupported = hasCssAnimation(popup);
6094 if (typeof innerParams.willClose === 'function') {
6095 innerParams.willClose(popup);
6096 }
6097 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willClose', popup);
6098 if (animationIsSupported && container) {
6099 animatePopup(instance, popup, container, Boolean(innerParams.returnFocus), innerParams.didClose);
6100 } else if (container) {
6101 // Otherwise, remove immediately
6102 removePopupAndResetState(instance, container, Boolean(innerParams.returnFocus), innerParams.didClose);
6103 }
6104 };
6105
6106 /**
6107 * @param {SweetAlert} instance
6108 * @param {HTMLElement} popup
6109 * @param {HTMLElement} container
6110 * @param {boolean} returnFocus
6111 * @param {(() => void) | undefined} didClose
6112 */
6113 const animatePopup = (instance, popup, container, returnFocus, didClose) => {
6114 globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
6115 /**
6116 * @param {AnimationEvent | TransitionEvent} e
6117 */
6118 const swalCloseAnimationFinished = function (e) {
6119 if (e.target === popup) {
6120 var _globalState$swalClos;
6121 (_globalState$swalClos = globalState.swalCloseEventFinishedCallback) === null || _globalState$swalClos === void 0 || _globalState$swalClos.call(globalState);
6122 delete globalState.swalCloseEventFinishedCallback;
6123 popup.removeEventListener('animationend', swalCloseAnimationFinished);
6124 popup.removeEventListener('transitionend', swalCloseAnimationFinished);
6125 }
6126 };
6127 popup.addEventListener('animationend', swalCloseAnimationFinished);
6128 popup.addEventListener('transitionend', swalCloseAnimationFinished);
6129 };
6130
6131 /**
6132 * @param {SweetAlert} instance
6133 * @param {(() => void) | undefined} didClose
6134 */
6135 const triggerDidCloseAndDispose = (instance, didClose) => {
6136 setTimeout(() => {
6137 var _globalState$eventEmi2;
6138 if (typeof didClose === 'function') {
6139 didClose.bind(instance.params)();
6140 }
6141 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didClose');
6142 // instance might have been destroyed already
6143 if (instance._destroy) {
6144 instance._destroy();
6145 }
6146 });
6147 };
6148
6149 /**
6150 * Shows loader (spinner), this is useful with AJAX requests.
6151 * By default the loader be shown instead of the "Confirm" button.
6152 *
6153 * @param {HTMLButtonElement | null} [buttonToReplace]
6154 */
6155 const showLoading = buttonToReplace => {
6156 let popup = getPopup();
6157 if (!popup) {
6158 new Swal();
6159 }
6160 popup = getPopup();
6161 if (!popup) {
6162 return;
6163 }
6164 const loader = getLoader();
6165 if (isToast()) {
6166 hide(getIcon());
6167 } else {
6168 replaceButton(popup, buttonToReplace);
6169 }
6170 show(loader);
6171 popup.setAttribute('data-loading', 'true');
6172 popup.setAttribute('aria-busy', 'true');
6173 popup.focus();
6174 };
6175
6176 /**
6177 * @param {HTMLElement} popup
6178 * @param {HTMLButtonElement | null} [buttonToReplace]
6179 */
6180 const replaceButton = (popup, buttonToReplace) => {
6181 const actions = getActions();
6182 const loader = getLoader();
6183 if (!actions || !loader) {
6184 return;
6185 }
6186 if (!buttonToReplace && isVisible$1(getConfirmButton())) {
6187 buttonToReplace = getConfirmButton();
6188 }
6189 show(actions);
6190 if (buttonToReplace) {
6191 hide(buttonToReplace);
6192 loader.setAttribute('data-button-to-replace', buttonToReplace.className);
6193 actions.insertBefore(loader, buttonToReplace);
6194 }
6195 addClass([popup, actions], swalClasses.loading);
6196 };
6197
6198 /**
6199 * @param {SweetAlert} instance
6200 * @param {SweetAlertOptions} params
6201 */
6202 const handleInputOptionsAndValue = (instance, params) => {
6203 if (params.input === 'select' || params.input === 'radio') {
6204 handleInputOptions(instance, params);
6205 } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
6206 showLoading(getConfirmButton());
6207 handleInputValue(instance, params);
6208 }
6209 };
6210
6211 /**
6212 * @param {SweetAlert} instance
6213 * @param {SweetAlertOptions} innerParams
6214 * @returns {SweetAlertInputValue}
6215 */
6216 const getInputValue = (instance, innerParams) => {
6217 const input = instance.getInput();
6218 if (!input) {
6219 return null;
6220 }
6221 switch (innerParams.input) {
6222 case 'checkbox':
6223 return getCheckboxValue(input);
6224 case 'radio':
6225 return getRadioValue(input);
6226 case 'file':
6227 return getFileValue(input);
6228 default:
6229 return innerParams.inputAutoTrim ? input.value.trim() : input.value;
6230 }
6231 };
6232
6233 /**
6234 * @param {HTMLInputElement} input
6235 * @returns {number}
6236 */
6237 const getCheckboxValue = input => input.checked ? 1 : 0;
6238
6239 /**
6240 * @param {HTMLInputElement} input
6241 * @returns {string | null}
6242 */
6243 const getRadioValue = input => input.checked ? input.value : null;
6244
6245 /**
6246 * @param {HTMLInputElement} input
6247 * @returns {FileList | File | null}
6248 */
6249 const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null;
6250
6251 /**
6252 * @param {SweetAlert} instance
6253 * @param {SweetAlertOptions} params
6254 */
6255 const handleInputOptions = (instance, params) => {
6256 const popup = getPopup();
6257 if (!popup) {
6258 return;
6259 }
6260 /**
6261 * @param {*} inputOptions
6262 */
6263 const processInputOptions = inputOptions => {
6264 if (params.input === 'select') {
6265 populateSelectOptions(popup, formatInputOptions(inputOptions), params);
6266 } else if (params.input === 'radio') {
6267 populateRadioOptions(popup, formatInputOptions(inputOptions), params);
6268 }
6269 };
6270 if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) {
6271 showLoading(getConfirmButton());
6272 asPromise(params.inputOptions).then(inputOptions => {
6273 instance.hideLoading();
6274 processInputOptions(inputOptions);
6275 });
6276 } else if (typeof params.inputOptions === 'object') {
6277 processInputOptions(params.inputOptions);
6278 } else {
6279 error(`Unexpected type of inputOptions! Expected object, Map or Promise, got ${typeof params.inputOptions}`);
6280 }
6281 };
6282
6283 /**
6284 * @param {SweetAlert} instance
6285 * @param {SweetAlertOptions} params
6286 */
6287 const handleInputValue = (instance, params) => {
6288 const input = instance.getInput();
6289 if (!input) {
6290 return;
6291 }
6292 hide(input);
6293 asPromise(params.inputValue).then(inputValue => {
6294 input.value = params.input === 'number' ? `${parseFloat(inputValue) || 0}` : `${inputValue}`;
6295 show(input);
6296 input.focus();
6297 instance.hideLoading();
6298 }).catch(err => {
6299 error(`Error in inputValue promise: ${err}`);
6300 input.value = '';
6301 show(input);
6302 input.focus();
6303 instance.hideLoading();
6304 });
6305 };
6306
6307 /**
6308 * @param {HTMLElement} popup
6309 * @param {InputOptionFlattened[]} inputOptions
6310 * @param {SweetAlertOptions} params
6311 */
6312 function populateSelectOptions(popup, inputOptions, params) {
6313 const select = getDirectChildByClass(popup, swalClasses.select);
6314 if (!select) {
6315 return;
6316 }
6317 /**
6318 * @param {HTMLElement} parent
6319 * @param {string} optionLabel
6320 * @param {string} optionValue
6321 */
6322 const renderOption = (parent, optionLabel, optionValue) => {
6323 const option = document.createElement('option');
6324 option.value = optionValue;
6325 setInnerHtml(option, optionLabel);
6326 option.selected = isSelected(optionValue, params.inputValue);
6327 parent.appendChild(option);
6328 };
6329 inputOptions.forEach(inputOption => {
6330 const optionValue = inputOption[0];
6331 const optionLabel = inputOption[1];
6332 // <optgroup> spec:
6333 // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
6334 // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
6335 // check whether this is a <optgroup>
6336 if (Array.isArray(optionLabel)) {
6337 // if it is an array, then it is an <optgroup>
6338 const optgroup = document.createElement('optgroup');
6339 optgroup.label = optionValue;
6340 optgroup.disabled = false; // not configurable for now
6341 select.appendChild(optgroup);
6342 optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
6343 } else {
6344 // case of <option>
6345 renderOption(select, optionLabel, optionValue);
6346 }
6347 });
6348 select.focus();
6349 }
6350
6351 /**
6352 * @param {HTMLElement} popup
6353 * @param {InputOptionFlattened[]} inputOptions
6354 * @param {SweetAlertOptions} params
6355 */
6356 function populateRadioOptions(popup, inputOptions, params) {
6357 const radio = getDirectChildByClass(popup, swalClasses.radio);
6358 if (!radio) {
6359 return;
6360 }
6361 inputOptions.forEach(inputOption => {
6362 const radioValue = inputOption[0];
6363 const radioLabel = inputOption[1];
6364 const radioInput = document.createElement('input');
6365 const radioLabelElement = document.createElement('label');
6366 radioInput.type = 'radio';
6367 radioInput.name = swalClasses.radio;
6368 radioInput.value = radioValue;
6369 if (isSelected(radioValue, params.inputValue)) {
6370 radioInput.checked = true;
6371 }
6372 const label = document.createElement('span');
6373 setInnerHtml(label, radioLabel);
6374 label.className = swalClasses.label;
6375 radioLabelElement.appendChild(radioInput);
6376 radioLabelElement.appendChild(label);
6377 radio.appendChild(radioLabelElement);
6378 });
6379 const radios = radio.querySelectorAll('input');
6380 if (radios.length) {
6381 radios[0].focus();
6382 }
6383 }
6384
6385 /**
6386 * Converts `inputOptions` into an array of `[value, label]`s
6387 *
6388 * @param {*} inputOptions
6389 * @typedef {string[]} InputOptionFlattened
6390 * @returns {InputOptionFlattened[]}
6391 */
6392 const formatInputOptions = inputOptions => {
6393 const entries = inputOptions instanceof Map ? Array.from(inputOptions) : Object.entries(inputOptions);
6394 return entries.map(([key, value]) => [key, typeof value === 'object' ? formatInputOptions(value) : value]); // case of <optgroup>
6395 };
6396
6397 /**
6398 * @param {string} optionValue
6399 * @param {SweetAlertInputValue} inputValue
6400 * @returns {boolean}
6401 */
6402 const isSelected = (optionValue, inputValue) => Boolean(inputValue) && inputValue != null && inputValue.toString() === optionValue.toString();
6403
6404 /**
6405 * @param {SweetAlert} instance
6406 */
6407 const handleConfirmButtonClick = instance => {
6408 const innerParams = privateProps.innerParams.get(instance);
6409 instance.disableButtons();
6410 if (innerParams.input) {
6411 handleConfirmOrDenyWithInput(instance, 'confirm');
6412 } else {
6413 confirm(instance, true);
6414 }
6415 };
6416
6417 /**
6418 * @param {SweetAlert} instance
6419 */
6420 const handleDenyButtonClick = instance => {
6421 const innerParams = privateProps.innerParams.get(instance);
6422 instance.disableButtons();
6423 if (innerParams.returnInputValueOnDeny) {
6424 handleConfirmOrDenyWithInput(instance, 'deny');
6425 } else {
6426 deny(instance, false);
6427 }
6428 };
6429
6430 /**
6431 * @param {SweetAlert} instance
6432 * @param {(dismiss: DismissReason) => void} dismissWith
6433 */
6434 const handleCancelButtonClick = (instance, dismissWith) => {
6435 instance.disableButtons();
6436 dismissWith(DismissReason.cancel);
6437 };
6438
6439 /**
6440 * @param {SweetAlert} instance
6441 * @param {'confirm' | 'deny'} type
6442 */
6443 const handleConfirmOrDenyWithInput = (instance, type) => {
6444 const innerParams = privateProps.innerParams.get(instance);
6445 if (!innerParams.input) {
6446 error(`The "input" parameter is needed to be set when using returnInputValueOn${capitalizeFirstLetter(type)}`);
6447 return;
6448 }
6449 const input = instance.getInput();
6450 const inputValue = getInputValue(instance, innerParams);
6451 if (innerParams.inputValidator) {
6452 handleInputValidator(instance, inputValue, type);
6453 } else if (input && !input.checkValidity()) {
6454 instance.enableButtons();
6455 instance.showValidationMessage(innerParams.validationMessage || input.validationMessage);
6456 } else if (type === 'deny') {
6457 deny(instance, inputValue);
6458 } else {
6459 confirm(instance, inputValue);
6460 }
6461 };
6462
6463 /**
6464 * @param {SweetAlert} instance
6465 * @param {SweetAlertInputValue} inputValue
6466 * @param {'confirm' | 'deny'} type
6467 */
6468 const handleInputValidator = (instance, inputValue, type) => {
6469 const innerParams = privateProps.innerParams.get(instance);
6470 instance.disableInput();
6471 const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
6472 validationPromise.then(validationMessage => {
6473 instance.enableButtons();
6474 instance.enableInput();
6475 if (validationMessage) {
6476 instance.showValidationMessage(validationMessage);
6477 } else if (type === 'deny') {
6478 deny(instance, inputValue);
6479 } else {
6480 confirm(instance, inputValue);
6481 }
6482 });
6483 };
6484
6485 /**
6486 * @param {SweetAlert} instance
6487 * @param {*} value
6488 */
6489 const deny = (instance, value) => {
6490 const innerParams = privateProps.innerParams.get(instance);
6491 if (innerParams.showLoaderOnDeny) {
6492 showLoading(getDenyButton());
6493 }
6494 if (innerParams.preDeny) {
6495 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
6496 const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
6497 preDenyPromise.then(preDenyValue => {
6498 if (preDenyValue === false) {
6499 instance.hideLoading();
6500 handleAwaitingPromise(instance);
6501 } else {
6502 instance.close(/** @type SweetAlertResult */{
6503 isDenied: true,
6504 value: typeof preDenyValue === 'undefined' ? value : preDenyValue
6505 });
6506 }
6507 }).catch(error => rejectWith(instance, error));
6508 } else {
6509 instance.close(/** @type SweetAlertResult */{
6510 isDenied: true,
6511 value
6512 });
6513 }
6514 };
6515
6516 /**
6517 * @param {SweetAlert} instance
6518 * @param {*} value
6519 */
6520 const succeedWith = (instance, value) => {
6521 instance.close(/** @type SweetAlertResult */{
6522 isConfirmed: true,
6523 value
6524 });
6525 };
6526
6527 /**
6528 *
6529 * @param {SweetAlert} instance
6530 * @param {string} error
6531 */
6532 const rejectWith = (instance, error) => {
6533 instance.rejectPromise(error);
6534 };
6535
6536 /**
6537 *
6538 * @param {SweetAlert} instance
6539 * @param {*} value
6540 */
6541 const confirm = (instance, value) => {
6542 const innerParams = privateProps.innerParams.get(instance);
6543 if (innerParams.showLoaderOnConfirm) {
6544 showLoading();
6545 }
6546 if (innerParams.preConfirm) {
6547 instance.resetValidationMessage();
6548 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
6549 const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
6550 preConfirmPromise.then(preConfirmValue => {
6551 if (isVisible$1(getValidationMessage()) || preConfirmValue === false) {
6552 instance.hideLoading();
6553 handleAwaitingPromise(instance);
6554 } else {
6555 succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
6556 }
6557 }).catch(error => rejectWith(instance, error));
6558 } else {
6559 succeedWith(instance, value);
6560 }
6561 };
6562
6563 /**
6564 * Hides loader and shows back the button which was hidden by .showLoading()
6565 * @this {SweetAlert}
6566 */
6567 function hideLoading() {
6568 // do nothing if popup is closed
6569 const innerParams = privateProps.innerParams.get(this);
6570 if (!innerParams) {
6571 return;
6572 }
6573 const domCache = privateProps.domCache.get(this);
6574 hide(domCache.loader);
6575 if (isToast()) {
6576 if (innerParams.icon) {
6577 show(getIcon());
6578 }
6579 } else {
6580 showRelatedButton(domCache);
6581 }
6582 removeClass([domCache.popup, domCache.actions], swalClasses.loading);
6583 domCache.popup.removeAttribute('aria-busy');
6584 domCache.popup.removeAttribute('data-loading');
6585 this.enableButtons();
6586 }
6587
6588 /**
6589 * @param {DomCache} domCache
6590 */
6591 const showRelatedButton = domCache => {
6592 const dataButtonToReplace = domCache.loader.getAttribute('data-button-to-replace');
6593 const buttonToReplace = dataButtonToReplace ? domCache.popup.getElementsByClassName(dataButtonToReplace) : [];
6594 if (buttonToReplace.length) {
6595 show(/** @type {HTMLElement} */buttonToReplace[0], 'inline-block');
6596 } else if (allButtonsAreHidden()) {
6597 hide(domCache.actions);
6598 }
6599 };
6600
6601 /**
6602 * Gets the input DOM node, this method works with input parameter.
6603 *
6604 * @returns {HTMLInputElement | null}
6605 * @this {SweetAlert}
6606 */
6607 function getInput() {
6608 const innerParams = privateProps.innerParams.get(this);
6609 const domCache = privateProps.domCache.get(this);
6610 if (!domCache) {
6611 return null;
6612 }
6613 return getInput$1(domCache.popup, innerParams.input);
6614 }
6615
6616 /**
6617 * @param {SweetAlert} instance
6618 * @param {string[]} buttons
6619 * @param {boolean} disabled
6620 */
6621 function setButtonsDisabled(instance, buttons, disabled) {
6622 const domCache = privateProps.domCache.get(instance);
6623 buttons.forEach(button => {
6624 domCache[button].disabled = disabled;
6625 });
6626 }
6627
6628 /**
6629 * @param {HTMLInputElement | null} input
6630 * @param {boolean} disabled
6631 */
6632 function setInputDisabled(input, disabled) {
6633 const popup = getPopup();
6634 if (!popup || !input) {
6635 return;
6636 }
6637 if (input.type === 'radio') {
6638 /** @type {NodeListOf<HTMLInputElement>} */
6639 const radios = popup.querySelectorAll(`[name="${swalClasses.radio}"]`);
6640 radios.forEach(radio => {
6641 radio.disabled = disabled;
6642 });
6643 } else {
6644 input.disabled = disabled;
6645 }
6646 }
6647
6648 /**
6649 * Enable all the buttons
6650 * @this {SweetAlert}
6651 */
6652 function enableButtons() {
6653 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
6654 const focusedElement = privateProps.focusedElement.get(this);
6655 if (focusedElement instanceof HTMLElement && document.activeElement === document.body) {
6656 focusedElement.focus();
6657 }
6658 privateProps.focusedElement.delete(this);
6659 }
6660
6661 /**
6662 * Disable all the buttons
6663 * @this {SweetAlert}
6664 */
6665 function disableButtons() {
6666 privateProps.focusedElement.set(this, document.activeElement);
6667 setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
6668 }
6669
6670 /**
6671 * Enable the input field
6672 * @this {SweetAlert}
6673 */
6674 function enableInput() {
6675 setInputDisabled(this.getInput(), false);
6676 }
6677
6678 /**
6679 * Disable the input field
6680 * @this {SweetAlert}
6681 */
6682 function disableInput() {
6683 setInputDisabled(this.getInput(), true);
6684 }
6685
6686 /**
6687 * Show block with validation message
6688 *
6689 * @param {string} error
6690 * @this {SweetAlert}
6691 */
6692 function showValidationMessage(error) {
6693 const domCache = privateProps.domCache.get(this);
6694 const params = privateProps.innerParams.get(this);
6695 setInnerHtml(domCache.validationMessage, error);
6696 domCache.validationMessage.className = swalClasses['validation-message'];
6697 if (params.customClass && params.customClass.validationMessage) {
6698 addClass(domCache.validationMessage, params.customClass.validationMessage);
6699 }
6700 show(domCache.validationMessage);
6701 const input = this.getInput();
6702 if (input) {
6703 input.setAttribute('aria-invalid', 'true');
6704 input.setAttribute('aria-describedby', swalClasses['validation-message']);
6705 focusInput(input);
6706 addClass(input, swalClasses.inputerror);
6707 }
6708 }
6709
6710 /**
6711 * Hide block with validation message
6712 *
6713 * @this {SweetAlert}
6714 */
6715 function resetValidationMessage() {
6716 const domCache = privateProps.domCache.get(this);
6717 if (domCache.validationMessage) {
6718 hide(domCache.validationMessage);
6719 }
6720 const input = this.getInput();
6721 if (input) {
6722 input.removeAttribute('aria-invalid');
6723 input.removeAttribute('aria-describedby');
6724 removeClass(input, swalClasses.inputerror);
6725 }
6726 }
6727
6728 const defaultParams = {
6729 title: '',
6730 titleText: '',
6731 text: '',
6732 html: '',
6733 footer: '',
6734 icon: undefined,
6735 iconColor: undefined,
6736 iconHtml: undefined,
6737 template: undefined,
6738 toast: false,
6739 draggable: false,
6740 animation: true,
6741 theme: 'light',
6742 showClass: {
6743 popup: 'swal2-show',
6744 backdrop: 'swal2-backdrop-show',
6745 icon: 'swal2-icon-show'
6746 },
6747 hideClass: {
6748 popup: 'swal2-hide',
6749 backdrop: 'swal2-backdrop-hide',
6750 icon: 'swal2-icon-hide'
6751 },
6752 customClass: {},
6753 target: 'body',
6754 color: undefined,
6755 backdrop: true,
6756 heightAuto: true,
6757 allowOutsideClick: true,
6758 allowEscapeKey: true,
6759 allowEnterKey: true,
6760 stopKeydownPropagation: true,
6761 keydownListenerCapture: false,
6762 showConfirmButton: true,
6763 showDenyButton: false,
6764 showCancelButton: false,
6765 preConfirm: undefined,
6766 preDeny: undefined,
6767 confirmButtonText: 'OK',
6768 confirmButtonAriaLabel: '',
6769 confirmButtonColor: undefined,
6770 denyButtonText: 'No',
6771 denyButtonAriaLabel: '',
6772 denyButtonColor: undefined,
6773 cancelButtonText: 'Cancel',
6774 cancelButtonAriaLabel: '',
6775 cancelButtonColor: undefined,
6776 buttonsStyling: true,
6777 reverseButtons: false,
6778 focusConfirm: true,
6779 focusDeny: false,
6780 focusCancel: false,
6781 returnFocus: true,
6782 showCloseButton: false,
6783 closeButtonHtml: '&times;',
6784 closeButtonAriaLabel: 'Close this dialog',
6785 loaderHtml: '',
6786 showLoaderOnConfirm: false,
6787 showLoaderOnDeny: false,
6788 imageUrl: undefined,
6789 imageWidth: undefined,
6790 imageHeight: undefined,
6791 imageAlt: '',
6792 timer: undefined,
6793 timerProgressBar: false,
6794 width: undefined,
6795 padding: undefined,
6796 background: undefined,
6797 input: undefined,
6798 inputPlaceholder: '',
6799 inputLabel: '',
6800 inputValue: '',
6801 inputOptions: {},
6802 inputAutoFocus: true,
6803 inputAutoTrim: true,
6804 inputAttributes: {},
6805 inputValidator: undefined,
6806 returnInputValueOnDeny: false,
6807 validationMessage: undefined,
6808 grow: false,
6809 position: 'center',
6810 progressSteps: [],
6811 currentProgressStep: undefined,
6812 progressStepsDistance: undefined,
6813 willOpen: undefined,
6814 didOpen: undefined,
6815 didRender: undefined,
6816 willClose: undefined,
6817 didClose: undefined,
6818 didDestroy: undefined,
6819 scrollbarPadding: true,
6820 topLayer: false
6821 };
6822 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'];
6823
6824 /** @type {Record<string, string | undefined>} */
6825 const deprecatedParams = {
6826 allowEnterKey: undefined
6827 };
6828 const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'draggable', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
6829
6830 /**
6831 * Is valid parameter
6832 *
6833 * @param {string} paramName
6834 * @returns {boolean}
6835 */
6836 const isValidParameter = paramName => {
6837 return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
6838 };
6839
6840 /**
6841 * Is valid parameter for Swal.update() method
6842 *
6843 * @param {string} paramName
6844 * @returns {boolean}
6845 */
6846 const isUpdatableParameter = paramName => {
6847 return updatableParams.indexOf(paramName) !== -1;
6848 };
6849
6850 /**
6851 * Is deprecated parameter
6852 *
6853 * @param {string} paramName
6854 * @returns {string | undefined}
6855 */
6856 const isDeprecatedParameter = paramName => {
6857 return deprecatedParams[paramName];
6858 };
6859
6860 /**
6861 * @param {string} param
6862 */
6863 const checkIfParamIsValid = param => {
6864 if (!isValidParameter(param)) {
6865 warn(`Unknown parameter "${param}"`);
6866 }
6867 };
6868
6869 /**
6870 * @param {string} param
6871 */
6872 const checkIfToastParamIsValid = param => {
6873 if (toastIncompatibleParams.includes(param)) {
6874 warn(`The parameter "${param}" is incompatible with toasts`);
6875 }
6876 };
6877
6878 /**
6879 * @param {string} param
6880 */
6881 const checkIfParamIsDeprecated = param => {
6882 const isDeprecated = isDeprecatedParameter(param);
6883 if (isDeprecated) {
6884 warnAboutDeprecation(param, isDeprecated);
6885 }
6886 };
6887
6888 /**
6889 * Show relevant warnings for given params
6890 *
6891 * @param {SweetAlertOptions} params
6892 */
6893 const showWarningsForParams = params => {
6894 if (params.backdrop === false && params.allowOutsideClick) {
6895 warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
6896 }
6897 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)) {
6898 warn(`Invalid theme "${params.theme}"`);
6899 }
6900 for (const param in params) {
6901 checkIfParamIsValid(param);
6902 if (params.toast) {
6903 checkIfToastParamIsValid(param);
6904 }
6905 checkIfParamIsDeprecated(param);
6906 }
6907 };
6908
6909 /**
6910 * Updates popup parameters.
6911 *
6912 * @this {any}
6913 * @param {SweetAlertOptions} params
6914 */
6915 function update(params) {
6916 const container = getContainer();
6917 const popup = getPopup();
6918 const innerParams = privateProps.innerParams.get(this);
6919 if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
6920 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.`);
6921 return;
6922 }
6923 const validUpdatableParams = filterValidParams(params);
6924 const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
6925 showWarningsForParams(updatedParams);
6926 if (container) {
6927 container.dataset['swal2Theme'] = updatedParams.theme;
6928 }
6929 render(this, updatedParams);
6930 privateProps.innerParams.set(this, updatedParams);
6931 Object.defineProperties(this, {
6932 params: {
6933 value: Object.assign({}, this.params, params),
6934 writable: false,
6935 enumerable: true
6936 }
6937 });
6938 }
6939
6940 /**
6941 * @param {SweetAlertOptions} params
6942 * @returns {SweetAlertOptions}
6943 */
6944 const filterValidParams = params => {
6945 /** @type {Record<string, any>} */
6946 const validUpdatableParams = {};
6947 Object.keys(params).forEach(param => {
6948 if (isUpdatableParameter(param)) {
6949 const typedParams = /** @type {Record<string, any>} */params;
6950 validUpdatableParams[param] = typedParams[param];
6951 } else {
6952 warn(`Invalid parameter to update: ${param}`);
6953 }
6954 });
6955 return validUpdatableParams;
6956 };
6957
6958 /**
6959 * Dispose the current SweetAlert2 instance
6960 * @this {SweetAlert}
6961 */
6962 function _destroy() {
6963 var _globalState$eventEmi;
6964 const domCache = privateProps.domCache.get(this);
6965 const innerParams = privateProps.innerParams.get(this);
6966 if (!innerParams) {
6967 disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
6968 return; // This instance has already been destroyed
6969 }
6970
6971 // Check if there is another Swal closing
6972 if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
6973 globalState.swalCloseEventFinishedCallback();
6974 delete globalState.swalCloseEventFinishedCallback;
6975 }
6976 if (typeof innerParams.didDestroy === 'function') {
6977 innerParams.didDestroy();
6978 }
6979 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didDestroy');
6980 disposeSwal(this);
6981 }
6982
6983 /**
6984 * @param {SweetAlert} instance
6985 */
6986 const disposeSwal = instance => {
6987 disposeWeakMaps(instance);
6988 // Unset this.params so GC will dispose it (#1569)
6989 // @ts-ignore
6990 delete instance.params;
6991 // Unset globalState props so GC will dispose globalState (#1569)
6992 delete globalState.keydownHandler;
6993 delete globalState.keydownTarget;
6994 // Unset currentInstance
6995 delete globalState.currentInstance;
6996 };
6997
6998 /**
6999 * @param {SweetAlert} instance
7000 */
7001 const disposeWeakMaps = instance => {
7002 // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
7003 if (instance.isAwaitingPromise) {
7004 unsetWeakMaps(privateProps, instance);
7005 instance.isAwaitingPromise = true;
7006 } else {
7007 unsetWeakMaps(privateMethods, instance);
7008 unsetWeakMaps(privateProps, instance);
7009
7010 // @ts-ignore
7011 delete instance.isAwaitingPromise;
7012 // Unset instance methods
7013 // @ts-ignore
7014 delete instance.disableButtons;
7015 // @ts-ignore
7016 delete instance.enableButtons;
7017 // @ts-ignore
7018 delete instance.getInput;
7019 // @ts-ignore
7020 delete instance.disableInput;
7021 // @ts-ignore
7022 delete instance.enableInput;
7023 // @ts-ignore
7024 delete instance.hideLoading;
7025 // @ts-ignore
7026 delete instance.disableLoading;
7027 // @ts-ignore
7028 delete instance.showValidationMessage;
7029 // @ts-ignore
7030 delete instance.resetValidationMessage;
7031 // @ts-ignore
7032 delete instance.close;
7033 // @ts-ignore
7034 delete instance.closePopup;
7035 // @ts-ignore
7036 delete instance.closeModal;
7037 // @ts-ignore
7038 delete instance.closeToast;
7039 // @ts-ignore
7040 delete instance.rejectPromise;
7041 // @ts-ignore
7042 delete instance.update;
7043 // @ts-ignore
7044 delete instance._destroy;
7045 }
7046 };
7047
7048 /**
7049 * @param {Record<string, WeakMap<any, any>>} obj
7050 * @param {SweetAlert} instance
7051 */
7052 const unsetWeakMaps = (obj, instance) => {
7053 for (const i in obj) {
7054 obj[i].delete(instance);
7055 }
7056 };
7057
7058 var instanceMethods = /*#__PURE__*/Object.freeze({
7059 __proto__: null,
7060 _destroy: _destroy,
7061 close: close,
7062 closeModal: close,
7063 closePopup: close,
7064 closeToast: close,
7065 disableButtons: disableButtons,
7066 disableInput: disableInput,
7067 disableLoading: hideLoading,
7068 enableButtons: enableButtons,
7069 enableInput: enableInput,
7070 getInput: getInput,
7071 handleAwaitingPromise: handleAwaitingPromise,
7072 hideLoading: hideLoading,
7073 rejectPromise: rejectPromise,
7074 resetValidationMessage: resetValidationMessage,
7075 showValidationMessage: showValidationMessage,
7076 update: update
7077 });
7078
7079 /**
7080 * @param {SweetAlertOptions} innerParams
7081 * @param {DomCache} domCache
7082 * @param {(dismiss: DismissReason) => void} dismissWith
7083 */
7084 const handlePopupClick = (innerParams, domCache, dismissWith) => {
7085 if (innerParams.toast) {
7086 handleToastClick(innerParams, domCache, dismissWith);
7087 } else {
7088 // Ignore click events that had mousedown on the popup but mouseup on the container
7089 // This can happen when the user drags a slider
7090 handleModalMousedown(domCache);
7091
7092 // Ignore click events that had mousedown on the container but mouseup on the popup
7093 handleContainerMousedown(domCache);
7094 handleModalClick(innerParams, domCache, dismissWith);
7095 }
7096 };
7097
7098 /**
7099 * @param {SweetAlertOptions} innerParams
7100 * @param {DomCache} domCache
7101 * @param {(dismiss: DismissReason) => void} dismissWith
7102 */
7103 const handleToastClick = (innerParams, domCache, dismissWith) => {
7104 // Closing toast by internal click
7105 domCache.popup.onclick = () => {
7106 if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
7107 return;
7108 }
7109 dismissWith(DismissReason.close);
7110 };
7111 };
7112
7113 /**
7114 * @param {SweetAlertOptions} innerParams
7115 * @returns {boolean}
7116 */
7117 const isAnyButtonShown = innerParams => {
7118 return Boolean(innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton);
7119 };
7120 let ignoreOutsideClick = false;
7121
7122 /**
7123 * @param {DomCache} domCache
7124 */
7125 const handleModalMousedown = domCache => {
7126 domCache.popup.onmousedown = () => {
7127 domCache.container.onmouseup = function (e) {
7128 domCache.container.onmouseup = () => {};
7129 // We only check if the mouseup target is the container because usually it doesn't
7130 // have any other direct children aside of the popup
7131 if (e.target === domCache.container) {
7132 ignoreOutsideClick = true;
7133 }
7134 };
7135 };
7136 };
7137
7138 /**
7139 * @param {DomCache} domCache
7140 */
7141 const handleContainerMousedown = domCache => {
7142 domCache.container.onmousedown = e => {
7143 // prevent the modal text from being selected on double click on the container (allowOutsideClick: false)
7144 if (e.target === domCache.container) {
7145 e.preventDefault();
7146 }
7147 domCache.popup.onmouseup = function (e) {
7148 domCache.popup.onmouseup = () => {};
7149 // We also need to check if the mouseup target is a child of the popup
7150 if (e.target === domCache.popup || e.target instanceof HTMLElement && domCache.popup.contains(e.target)) {
7151 ignoreOutsideClick = true;
7152 }
7153 };
7154 };
7155 };
7156
7157 /**
7158 * @param {SweetAlertOptions} innerParams
7159 * @param {DomCache} domCache
7160 * @param {(dismiss: DismissReason) => void} dismissWith
7161 */
7162 const handleModalClick = (innerParams, domCache, dismissWith) => {
7163 domCache.container.onclick = e => {
7164 if (ignoreOutsideClick) {
7165 ignoreOutsideClick = false;
7166 return;
7167 }
7168 if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
7169 dismissWith(DismissReason.backdrop);
7170 }
7171 };
7172 };
7173
7174 /**
7175 * @param {unknown} elem
7176 * @returns {boolean}
7177 */
7178 const isJqueryElement = elem => typeof elem === 'object' && elem !== null && 'jquery' in elem;
7179
7180 /**
7181 * @param {unknown} elem
7182 * @returns {boolean}
7183 */
7184 const isElement = elem => elem instanceof Element || isJqueryElement(elem);
7185
7186 /**
7187 * @param {ReadonlyArray<unknown>} args
7188 * @returns {SweetAlertOptions}
7189 */
7190 const argsToParams = args => {
7191 /** @type {Record<string, unknown>} */
7192 const params = {};
7193 if (typeof args[0] === 'object' && !isElement(args[0])) {
7194 Object.assign(params, args[0]);
7195 } else {
7196 ['title', 'html', 'icon'].forEach((name, index) => {
7197 const arg = args[index];
7198 if (typeof arg === 'string' || isElement(arg)) {
7199 params[name] = arg;
7200 } else if (arg !== undefined) {
7201 error(`Unexpected type of ${name}! Expected "string" or "Element", got ${typeof arg}`);
7202 }
7203 });
7204 }
7205 return /** @type {SweetAlertOptions} */params;
7206 };
7207
7208 /**
7209 * Main method to create a new SweetAlert2 popup
7210 *
7211 * @this {new (...args: any[]) => any}
7212 * @param {...SweetAlertOptions} args
7213 * @returns {Promise<SweetAlertResult>}
7214 */
7215 function fire(...args) {
7216 return new this(...args);
7217 }
7218
7219 /**
7220 * Returns an extended version of `Swal` containing `params` as defaults.
7221 * Useful for reusing Swal configuration.
7222 *
7223 * For example:
7224 *
7225 * Before:
7226 * const textPromptOptions = { input: 'text', showCancelButton: true }
7227 * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
7228 * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
7229 *
7230 * After:
7231 * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
7232 * const {value: firstName} = await TextPrompt('What is your first name?')
7233 * const {value: lastName} = await TextPrompt('What is your last name?')
7234 *
7235 * @param {SweetAlertOptions} mixinParams
7236 * @returns {SweetAlert}
7237 * @this {typeof import('../SweetAlert.js').SweetAlert}
7238 */
7239 function mixin(mixinParams) {
7240 // @ts-ignore: 'this' refers to the SweetAlert constructor
7241 class MixinSwal extends this {
7242 /**
7243 * @param {any} params
7244 * @param {any} priorityMixinParams
7245 */
7246 _main(params, priorityMixinParams) {
7247 return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
7248 }
7249 }
7250 // @ts-ignore
7251 return MixinSwal;
7252 }
7253
7254 /**
7255 * If `timer` parameter is set, returns number of milliseconds of timer remained.
7256 * Otherwise, returns undefined.
7257 *
7258 * @returns {number | undefined}
7259 */
7260 const getTimerLeft = () => {
7261 return globalState.timeout && globalState.timeout.getTimerLeft();
7262 };
7263
7264 /**
7265 * Stop timer. Returns number of milliseconds of timer remained.
7266 * If `timer` parameter isn't set, returns undefined.
7267 *
7268 * @returns {number | undefined}
7269 */
7270 const stopTimer = () => {
7271 if (globalState.timeout) {
7272 stopTimerProgressBar();
7273 return globalState.timeout.stop();
7274 }
7275 };
7276
7277 /**
7278 * Resume timer. Returns number of milliseconds of timer remained.
7279 * If `timer` parameter isn't set, returns undefined.
7280 *
7281 * @returns {number | undefined}
7282 */
7283 const resumeTimer = () => {
7284 if (globalState.timeout) {
7285 const remaining = globalState.timeout.start();
7286 animateTimerProgressBar(remaining);
7287 return remaining;
7288 }
7289 };
7290
7291 /**
7292 * Resume timer. Returns number of milliseconds of timer remained.
7293 * If `timer` parameter isn't set, returns undefined.
7294 *
7295 * @returns {number | undefined}
7296 */
7297 const toggleTimer = () => {
7298 const timer = globalState.timeout;
7299 return timer && (timer.running ? stopTimer() : resumeTimer());
7300 };
7301
7302 /**
7303 * Increase timer. Returns number of milliseconds of an updated timer.
7304 * If `timer` parameter isn't set, returns undefined.
7305 *
7306 * @param {number} ms
7307 * @returns {number | undefined}
7308 */
7309 const increaseTimer = ms => {
7310 if (globalState.timeout) {
7311 const remaining = globalState.timeout.increase(ms);
7312 animateTimerProgressBar(remaining, true);
7313 return remaining;
7314 }
7315 };
7316
7317 /**
7318 * Check if timer is running. Returns true if timer is running
7319 * or false if timer is paused or stopped.
7320 * If `timer` parameter isn't set, returns undefined
7321 *
7322 * @returns {boolean}
7323 */
7324 const isTimerRunning = () => {
7325 return Boolean(globalState.timeout && globalState.timeout.isRunning());
7326 };
7327
7328 let bodyClickListenerAdded = false;
7329 /** @type {Record<string, any>} */
7330 const clickHandlers = {};
7331
7332 /**
7333 * @this {any}
7334 * @param {string} attr
7335 */
7336 function bindClickHandler(attr = 'data-swal-template') {
7337 clickHandlers[attr] = this;
7338 if (!bodyClickListenerAdded) {
7339 document.body.addEventListener('click', bodyClickListener);
7340 bodyClickListenerAdded = true;
7341 }
7342 }
7343
7344 /**
7345 * @param {MouseEvent} event
7346 */
7347 const bodyClickListener = event => {
7348 for (let el = /** @type {any} */event.target; el && el !== document; el = el.parentNode) {
7349 for (const attr in clickHandlers) {
7350 const template = el.getAttribute && el.getAttribute(attr);
7351 if (template) {
7352 clickHandlers[attr].fire({
7353 template
7354 });
7355 return;
7356 }
7357 }
7358 }
7359 };
7360
7361 // Source: https://gist.github.com/mudge/5830382?permalink_comment_id=2691957#gistcomment-2691957
7362
7363 class EventEmitter {
7364 constructor() {
7365 /** @type {Events} */
7366 this.events = {};
7367 }
7368
7369 /**
7370 * @param {string} eventName
7371 * @returns {EventHandlers}
7372 */
7373 _getHandlersByEventName(eventName) {
7374 if (typeof this.events[eventName] === 'undefined') {
7375 // not Set because we need to keep the FIFO order
7376 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1748990334
7377 this.events[eventName] = [];
7378 }
7379 return this.events[eventName];
7380 }
7381
7382 /**
7383 * @param {string} eventName
7384 * @param {EventHandler} eventHandler
7385 */
7386 on(eventName, eventHandler) {
7387 const currentHandlers = this._getHandlersByEventName(eventName);
7388 if (!currentHandlers.includes(eventHandler)) {
7389 currentHandlers.push(eventHandler);
7390 }
7391 }
7392
7393 /**
7394 * @param {string} eventName
7395 * @param {EventHandler} eventHandler
7396 */
7397 once(eventName, eventHandler) {
7398 /**
7399 * @param {...any} args
7400 */
7401 const onceFn = (...args) => {
7402 this.removeListener(eventName, onceFn);
7403 // @ts-ignore
7404 eventHandler.apply(this, args);
7405 };
7406 this.on(eventName, onceFn);
7407 }
7408
7409 /**
7410 * @param {string} eventName
7411 * @param {...any} args
7412 */
7413 emit(eventName, ...args) {
7414 this._getHandlersByEventName(eventName).forEach(
7415 /**
7416 * @param {EventHandler} eventHandler
7417 */
7418 eventHandler => {
7419 try {
7420 // @ts-ignore
7421 eventHandler.apply(this, args);
7422 } catch (error) {
7423 console.error(error);
7424 }
7425 });
7426 }
7427
7428 /**
7429 * @param {string} eventName
7430 * @param {EventHandler} eventHandler
7431 */
7432 removeListener(eventName, eventHandler) {
7433 const currentHandlers = this._getHandlersByEventName(eventName);
7434 const index = currentHandlers.indexOf(eventHandler);
7435 if (index > -1) {
7436 currentHandlers.splice(index, 1);
7437 }
7438 }
7439
7440 /**
7441 * @param {string} eventName
7442 */
7443 removeAllListeners(eventName) {
7444 if (this.events[eventName] !== undefined) {
7445 // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1749239222
7446 this.events[eventName].length = 0;
7447 }
7448 }
7449 reset() {
7450 this.events = {};
7451 }
7452 }
7453
7454 globalState.eventEmitter = new EventEmitter();
7455
7456 /**
7457 * @param {string} eventName
7458 * @param {EventHandler} eventHandler
7459 */
7460 const on = (eventName, eventHandler) => {
7461 if (globalState.eventEmitter) {
7462 globalState.eventEmitter.on(eventName, eventHandler);
7463 }
7464 };
7465
7466 /**
7467 * @param {string} eventName
7468 * @param {EventHandler} eventHandler
7469 */
7470 const once = (eventName, eventHandler) => {
7471 if (globalState.eventEmitter) {
7472 globalState.eventEmitter.once(eventName, eventHandler);
7473 }
7474 };
7475
7476 /**
7477 * @param {string} [eventName]
7478 * @param {EventHandler} [eventHandler]
7479 */
7480 const off = (eventName, eventHandler) => {
7481 if (!globalState.eventEmitter) {
7482 return;
7483 }
7484
7485 // Remove all handlers for all events
7486 if (!eventName) {
7487 globalState.eventEmitter.reset();
7488 return;
7489 }
7490 if (eventHandler) {
7491 // Remove a specific handler
7492 globalState.eventEmitter.removeListener(eventName, eventHandler);
7493 } else {
7494 // Remove all handlers for a specific event
7495 globalState.eventEmitter.removeAllListeners(eventName);
7496 }
7497 };
7498
7499 var staticMethods = /*#__PURE__*/Object.freeze({
7500 __proto__: null,
7501 argsToParams: argsToParams,
7502 bindClickHandler: bindClickHandler,
7503 clickCancel: clickCancel,
7504 clickConfirm: clickConfirm,
7505 clickDeny: clickDeny,
7506 enableLoading: showLoading,
7507 fire: fire,
7508 getActions: getActions,
7509 getCancelButton: getCancelButton,
7510 getCloseButton: getCloseButton,
7511 getConfirmButton: getConfirmButton,
7512 getContainer: getContainer,
7513 getDenyButton: getDenyButton,
7514 getFocusableElements: getFocusableElements,
7515 getFooter: getFooter,
7516 getHtmlContainer: getHtmlContainer,
7517 getIcon: getIcon,
7518 getIconContent: getIconContent,
7519 getImage: getImage,
7520 getInputLabel: getInputLabel,
7521 getLoader: getLoader,
7522 getPopup: getPopup,
7523 getProgressSteps: getProgressSteps,
7524 getTimerLeft: getTimerLeft,
7525 getTimerProgressBar: getTimerProgressBar,
7526 getTitle: getTitle,
7527 getValidationMessage: getValidationMessage,
7528 increaseTimer: increaseTimer,
7529 isDeprecatedParameter: isDeprecatedParameter,
7530 isLoading: isLoading,
7531 isTimerRunning: isTimerRunning,
7532 isUpdatableParameter: isUpdatableParameter,
7533 isValidParameter: isValidParameter,
7534 isVisible: isVisible,
7535 mixin: mixin,
7536 off: off,
7537 on: on,
7538 once: once,
7539 resumeTimer: resumeTimer,
7540 showLoading: showLoading,
7541 stopTimer: stopTimer,
7542 toggleTimer: toggleTimer
7543 });
7544
7545 class Timer {
7546 /**
7547 * @param {() => void} callback
7548 * @param {number} delay
7549 */
7550 constructor(callback, delay) {
7551 this.callback = callback;
7552 this.remaining = delay;
7553 this.running = false;
7554 this.start();
7555 }
7556
7557 /**
7558 * @returns {number}
7559 */
7560 start() {
7561 if (!this.running) {
7562 this.running = true;
7563 this.started = new Date();
7564 this.id = setTimeout(this.callback, this.remaining);
7565 }
7566 return this.remaining;
7567 }
7568
7569 /**
7570 * @returns {number}
7571 */
7572 stop() {
7573 if (this.started && this.running) {
7574 this.running = false;
7575 clearTimeout(this.id);
7576 this.remaining -= new Date().getTime() - this.started.getTime();
7577 }
7578 return this.remaining;
7579 }
7580
7581 /**
7582 * @param {number} n
7583 * @returns {number}
7584 */
7585 increase(n) {
7586 const running = this.running;
7587 if (running) {
7588 this.stop();
7589 }
7590 this.remaining += n;
7591 if (running) {
7592 this.start();
7593 }
7594 return this.remaining;
7595 }
7596
7597 /**
7598 * @returns {number}
7599 */
7600 getTimerLeft() {
7601 if (this.running) {
7602 this.stop();
7603 this.start();
7604 }
7605 return this.remaining;
7606 }
7607
7608 /**
7609 * @returns {boolean}
7610 */
7611 isRunning() {
7612 return this.running;
7613 }
7614 }
7615
7616 const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
7617
7618 /**
7619 * @param {SweetAlertOptions} params
7620 * @returns {SweetAlertOptions}
7621 */
7622 const getTemplateParams = params => {
7623 const template = typeof params.template === 'string' ? (/** @type {HTMLTemplateElement} */document.querySelector(params.template)) : params.template;
7624 if (!template) {
7625 return {};
7626 }
7627 /** @type {DocumentFragment} */
7628 const templateContent = template.content;
7629 showWarningsForElements(templateContent);
7630 const result = Object.assign(getSwalParams(templateContent), getSwalFunctionParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
7631 return result;
7632 };
7633
7634 /**
7635 * @param {DocumentFragment} templateContent
7636 * @returns {Record<string, string | boolean | number>}
7637 */
7638 const getSwalParams = templateContent => {
7639 /** @type {Record<string, string | boolean | number>} */
7640 const result = {};
7641 /** @type {HTMLElement[]} */
7642 const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
7643 swalParams.forEach(param => {
7644 showWarningsForAttributes(param, ['name', 'value']);
7645 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7646 const value = param.getAttribute('value');
7647 if (!paramName || !value) {
7648 return;
7649 }
7650 if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'boolean') {
7651 result[paramName] = value !== 'false';
7652 } else if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'object') {
7653 result[paramName] = JSON.parse(value);
7654 } else {
7655 result[paramName] = value;
7656 }
7657 });
7658 return result;
7659 };
7660
7661 /**
7662 * @param {DocumentFragment} templateContent
7663 * @returns {Record<string, () => void>}
7664 */
7665 const getSwalFunctionParams = templateContent => {
7666 /** @type {Record<string, () => void>} */
7667 const result = {};
7668 /** @type {HTMLElement[]} */
7669 const swalFunctions = Array.from(templateContent.querySelectorAll('swal-function-param'));
7670 swalFunctions.forEach(param => {
7671 const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name');
7672 const value = param.getAttribute('value');
7673 if (!paramName || !value) {
7674 return;
7675 }
7676 result[paramName] = new Function(`return ${value}`)();
7677 });
7678 return result;
7679 };
7680
7681 /**
7682 * @param {DocumentFragment} templateContent
7683 * @returns {Record<string, string | boolean>}
7684 */
7685 const getSwalButtons = templateContent => {
7686 /** @type {Record<string, string | boolean>} */
7687 const result = {};
7688 /** @type {HTMLElement[]} */
7689 const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
7690 swalButtons.forEach(button => {
7691 showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
7692 const type = button.getAttribute('type');
7693 if (!type || !['confirm', 'cancel', 'deny'].includes(type)) {
7694 return;
7695 }
7696 result[`${type}ButtonText`] = button.innerHTML;
7697 result[`show${capitalizeFirstLetter(type)}Button`] = true;
7698 const color = button.getAttribute('color');
7699 if (color !== null) {
7700 result[`${type}ButtonColor`] = color;
7701 }
7702 const ariaLabel = button.getAttribute('aria-label');
7703 if (ariaLabel !== null) {
7704 result[`${type}ButtonAriaLabel`] = ariaLabel;
7705 }
7706 });
7707 return result;
7708 };
7709
7710 /**
7711 * @param {DocumentFragment} templateContent
7712 * @returns {Pick<SweetAlertOptions, 'imageUrl' | 'imageWidth' | 'imageHeight' | 'imageAlt'>}
7713 */
7714 const getSwalImage = templateContent => {
7715 const result = {};
7716 /** @type {HTMLElement | null} */
7717 const image = templateContent.querySelector('swal-image');
7718 if (image) {
7719 showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
7720 // getAttribute returns null if attribute is absent; `|| undefined` converts empty string to undefined
7721 const src = image.getAttribute('src');
7722 if (src !== null) result.imageUrl = src || undefined;
7723 const width = image.getAttribute('width');
7724 if (width !== null) result.imageWidth = width || undefined;
7725 const height = image.getAttribute('height');
7726 if (height !== null) result.imageHeight = height || undefined;
7727 const alt = image.getAttribute('alt');
7728 if (alt !== null) result.imageAlt = alt || undefined;
7729 }
7730 return result;
7731 };
7732
7733 /**
7734 * @param {DocumentFragment} templateContent
7735 * @returns {object}
7736 */
7737 const getSwalIcon = templateContent => {
7738 const result = {};
7739 /** @type {HTMLElement | null} */
7740 const icon = templateContent.querySelector('swal-icon');
7741 if (icon) {
7742 showWarningsForAttributes(icon, ['type', 'color']);
7743 if (icon.hasAttribute('type')) {
7744 result.icon = icon.getAttribute('type');
7745 }
7746 if (icon.hasAttribute('color')) {
7747 result.iconColor = icon.getAttribute('color');
7748 }
7749 result.iconHtml = icon.innerHTML;
7750 }
7751 return result;
7752 };
7753
7754 /**
7755 * @param {DocumentFragment} templateContent
7756 * @returns {object}
7757 */
7758 const getSwalInput = templateContent => {
7759 /** @type {Record<string, any>} */
7760 const result = {};
7761 /** @type {HTMLElement | null} */
7762 const input = templateContent.querySelector('swal-input');
7763 if (input) {
7764 showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
7765 result.input = input.getAttribute('type') || 'text';
7766 if (input.hasAttribute('label')) {
7767 result.inputLabel = input.getAttribute('label');
7768 }
7769 if (input.hasAttribute('placeholder')) {
7770 result.inputPlaceholder = input.getAttribute('placeholder');
7771 }
7772 if (input.hasAttribute('value')) {
7773 result.inputValue = input.getAttribute('value');
7774 }
7775 }
7776 /** @type {HTMLElement[]} */
7777 const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
7778 if (inputOptions.length) {
7779 result.inputOptions = {};
7780 inputOptions.forEach(option => {
7781 showWarningsForAttributes(option, ['value']);
7782 const optionValue = option.getAttribute('value');
7783 if (!optionValue) {
7784 return;
7785 }
7786 const optionName = option.innerHTML;
7787 result.inputOptions[optionValue] = optionName;
7788 });
7789 }
7790 return result;
7791 };
7792
7793 /**
7794 * @param {DocumentFragment} templateContent
7795 * @param {string[]} paramNames
7796 * @returns {Record<string, string>}
7797 */
7798 const getSwalStringParams = (templateContent, paramNames) => {
7799 /** @type {Record<string, string>} */
7800 const result = {};
7801 for (const i in paramNames) {
7802 const paramName = paramNames[i];
7803 /** @type {HTMLElement | null} */
7804 const tag = templateContent.querySelector(paramName);
7805 if (tag) {
7806 showWarningsForAttributes(tag, []);
7807 result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
7808 }
7809 }
7810 return result;
7811 };
7812
7813 /**
7814 * @param {DocumentFragment} templateContent
7815 */
7816 const showWarningsForElements = templateContent => {
7817 const allowedElements = swalStringParams.concat(['swal-param', 'swal-function-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
7818 Array.from(templateContent.children).forEach(el => {
7819 const tagName = el.tagName.toLowerCase();
7820 if (!allowedElements.includes(tagName)) {
7821 warn(`Unrecognized element <${tagName}>`);
7822 }
7823 });
7824 };
7825
7826 /**
7827 * @param {HTMLElement} el
7828 * @param {string[]} allowedAttributes
7829 */
7830 const showWarningsForAttributes = (el, allowedAttributes) => {
7831 Array.from(el.attributes).forEach(attribute => {
7832 if (allowedAttributes.indexOf(attribute.name) === -1) {
7833 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.'}`]);
7834 }
7835 });
7836 };
7837
7838 const SHOW_CLASS_TIMEOUT = 10;
7839
7840 /**
7841 * Open popup, add necessary classes and styles, fix scrollbar
7842 *
7843 * @param {SweetAlertOptions} params
7844 */
7845 const openPopup = params => {
7846 var _globalState$eventEmi, _globalState$eventEmi2;
7847 const container = getContainer();
7848 const popup = getPopup();
7849 if (!container || !popup) {
7850 return;
7851 }
7852 if (typeof params.willOpen === 'function') {
7853 params.willOpen(popup);
7854 }
7855 (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willOpen', popup);
7856 const bodyStyles = window.getComputedStyle(document.body);
7857 const initialBodyOverflow = bodyStyles.overflowY;
7858 addClasses(container, popup, params);
7859
7860 // scrolling is 'hidden' until animation is done, after that 'auto'
7861 setTimeout(() => {
7862 setScrollingVisibility(container, popup);
7863 }, SHOW_CLASS_TIMEOUT);
7864 if (isModal()) {
7865 fixScrollContainer(container, params.scrollbarPadding !== undefined ? params.scrollbarPadding : false, initialBodyOverflow);
7866 setAriaHidden();
7867 }
7868
7869 // https://github.com/sweetalert2/sweetalert2/issues/2923
7870 if (isIOS && params.backdrop === false && popup.scrollHeight > container.clientHeight) {
7871 // remove pointer-events: none from container, it breaks scrolling tall popups in iOS
7872 container.style.pointerEvents = 'auto';
7873 }
7874 if (!isToast() && !globalState.previousActiveElement) {
7875 globalState.previousActiveElement = document.activeElement;
7876 }
7877 if (typeof params.didOpen === 'function') {
7878 const didOpen = params.didOpen;
7879 setTimeout(() => didOpen(popup));
7880 }
7881 (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didOpen', popup);
7882 };
7883
7884 /**
7885 * @param {Event} event
7886 */
7887 const swalOpenAnimationFinished = event => {
7888 const popup = getPopup();
7889 if (!popup || event.target !== popup) {
7890 return;
7891 }
7892 const container = getContainer();
7893 if (!container) {
7894 return;
7895 }
7896 popup.removeEventListener('animationend', swalOpenAnimationFinished);
7897 popup.removeEventListener('transitionend', swalOpenAnimationFinished);
7898 container.style.overflowY = 'auto';
7899
7900 // no-transition is added in init() in case one swal is opened right after another
7901 removeClass(container, swalClasses['no-transition']);
7902 };
7903
7904 /**
7905 * @param {HTMLElement} container
7906 * @param {HTMLElement} popup
7907 */
7908 const setScrollingVisibility = (container, popup) => {
7909 if (hasCssAnimation(popup)) {
7910 container.style.overflowY = 'hidden';
7911 popup.addEventListener('animationend', swalOpenAnimationFinished);
7912 popup.addEventListener('transitionend', swalOpenAnimationFinished);
7913 } else {
7914 container.style.overflowY = 'auto';
7915 }
7916 };
7917
7918 /**
7919 * @param {HTMLElement} container
7920 * @param {boolean} scrollbarPadding
7921 * @param {string} initialBodyOverflow
7922 */
7923 const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
7924 iOSfix();
7925 if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
7926 replaceScrollbarWithPadding(initialBodyOverflow);
7927 }
7928
7929 // sweetalert2/issues/1247
7930 setTimeout(() => {
7931 container.scrollTop = 0;
7932 });
7933 };
7934
7935 /**
7936 * @param {HTMLElement} container
7937 * @param {HTMLElement} popup
7938 * @param {SweetAlertOptions} params
7939 */
7940 const addClasses = (container, popup, params) => {
7941 var _params$showClass;
7942 if ((_params$showClass = params.showClass) !== null && _params$showClass !== void 0 && _params$showClass.backdrop) {
7943 addClass(container, params.showClass.backdrop);
7944 }
7945 if (params.animation) {
7946 // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
7947 popup.style.setProperty('opacity', '0', 'important');
7948 show(popup, 'grid');
7949 setTimeout(() => {
7950 var _params$showClass2;
7951 // Animate popup right after showing it
7952 if ((_params$showClass2 = params.showClass) !== null && _params$showClass2 !== void 0 && _params$showClass2.popup) {
7953 addClass(popup, params.showClass.popup);
7954 }
7955 // and remove the opacity workaround
7956 popup.style.removeProperty('opacity');
7957 }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
7958 } else {
7959 show(popup, 'grid');
7960 }
7961 addClass([document.documentElement, document.body], swalClasses.shown);
7962 if (params.heightAuto && params.backdrop && !params.toast) {
7963 addClass([document.documentElement, document.body], swalClasses['height-auto']);
7964 }
7965 };
7966
7967 var defaultInputValidators = {
7968 /**
7969 * @param {string} string
7970 * @param {string} [validationMessage]
7971 * @returns {Promise<string | void>}
7972 */
7973 email: (string, validationMessage) => {
7974 return /^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
7975 },
7976 /**
7977 * @param {string} string
7978 * @param {string} [validationMessage]
7979 * @returns {Promise<string | void>}
7980 */
7981 url: (string, validationMessage) => {
7982 // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
7983 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');
7984 }
7985 };
7986
7987 /**
7988 * @param {SweetAlertOptions} params
7989 */
7990 function setDefaultInputValidators(params) {
7991 // Use default `inputValidator` for supported input types if not provided
7992 if (params.inputValidator) {
7993 return;
7994 }
7995 if (params.input === 'email') {
7996 params.inputValidator = defaultInputValidators['email'];
7997 }
7998 if (params.input === 'url') {
7999 params.inputValidator = defaultInputValidators['url'];
8000 }
8001 }
8002
8003 /**
8004 * @param {SweetAlertOptions} params
8005 */
8006 function validateCustomTargetElement(params) {
8007 // Determine if the custom target element is valid
8008 if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
8009 warn('Target parameter is not valid, defaulting to "body"');
8010 params.target = 'body';
8011 }
8012 }
8013
8014 /**
8015 * Set type, text and actions on popup
8016 *
8017 * @param {SweetAlertOptions} params
8018 */
8019 function setParameters(params) {
8020 setDefaultInputValidators(params);
8021
8022 // showLoaderOnConfirm && preConfirm
8023 if (params.showLoaderOnConfirm && !params.preConfirm) {
8024 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');
8025 }
8026 validateCustomTargetElement(params);
8027
8028 // Replace newlines with <br> in title
8029 if (typeof params.title === 'string') {
8030 params.title = params.title.split('\n').join('<br />');
8031 }
8032 init(params);
8033 }
8034
8035 /** @type {SweetAlert} */
8036 let currentInstance;
8037 var _promise = /*#__PURE__*/new WeakMap();
8038 class SweetAlert {
8039 /**
8040 * @param {...(SweetAlertOptions | string)} args
8041 * @this {SweetAlert}
8042 */
8043 constructor(...args) {
8044 /**
8045 * @type {Promise<SweetAlertResult>}
8046 */
8047 _classPrivateFieldInitSpec(this, _promise, /** @type {Promise<SweetAlertResult>} */
8048 Promise.resolve({
8049 isConfirmed: false,
8050 isDenied: false,
8051 isDismissed: true
8052 }));
8053 // Prevent run in Node env
8054 if (typeof window === 'undefined') {
8055 return;
8056 }
8057 currentInstance = this;
8058
8059 // @ts-ignore
8060 const outerParams = Object.freeze(this.constructor.argsToParams(args));
8061
8062 /** @type {Readonly<SweetAlertOptions>} */
8063 this.params = outerParams;
8064
8065 /** @type {boolean} */
8066 this.isAwaitingPromise = false;
8067 _classPrivateFieldSet2(_promise, this, this._main(currentInstance.params));
8068 }
8069
8070 /**
8071 * @param {any} userParams
8072 * @param {any} mixinParams
8073 */
8074 _main(userParams, mixinParams = {}) {
8075 showWarningsForParams(Object.assign({}, mixinParams, userParams));
8076 if (globalState.currentInstance) {
8077 const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance);
8078 const {
8079 isAwaitingPromise
8080 } = globalState.currentInstance;
8081 globalState.currentInstance._destroy();
8082 if (!isAwaitingPromise) {
8083 swalPromiseResolve({
8084 isDismissed: true
8085 });
8086 }
8087 if (isModal()) {
8088 unsetAriaHidden();
8089 }
8090 }
8091 globalState.currentInstance = currentInstance;
8092 const innerParams = prepareParams(userParams, mixinParams);
8093 setParameters(innerParams);
8094 Object.freeze(innerParams);
8095
8096 // clear the previous timer
8097 if (globalState.timeout) {
8098 globalState.timeout.stop();
8099 delete globalState.timeout;
8100 }
8101
8102 // clear the restore focus timeout
8103 clearTimeout(globalState.restoreFocusTimeout);
8104 const domCache = populateDomCache(currentInstance);
8105 render(currentInstance, innerParams);
8106 privateProps.innerParams.set(currentInstance, innerParams);
8107 return swalPromise(currentInstance, domCache, innerParams);
8108 }
8109
8110 // `catch` cannot be the name of a module export, so we define our thenable methods here instead
8111 /**
8112 * @param {any} onFulfilled
8113 */
8114 // oxlint-disable-next-line unicorn/no-thenable
8115 then(onFulfilled) {
8116 return _classPrivateFieldGet2(_promise, this).then(onFulfilled);
8117 }
8118
8119 /**
8120 * @param {any} onFinally
8121 */
8122 finally(onFinally) {
8123 return _classPrivateFieldGet2(_promise, this).finally(onFinally);
8124 }
8125 }
8126
8127 /**
8128 * @param {SweetAlert} instance
8129 * @param {DomCache} domCache
8130 * @param {SweetAlertOptions} innerParams
8131 * @returns {Promise<SweetAlertResult>}
8132 */
8133 const swalPromise = (instance, domCache, innerParams) => {
8134 return new Promise((resolve, reject) => {
8135 // functions to handle all closings/dismissals
8136 /**
8137 * @param {DismissReason} dismiss
8138 */
8139 const dismissWith = dismiss => {
8140 instance.close({
8141 isDismissed: true,
8142 dismiss,
8143 isConfirmed: false,
8144 isDenied: false
8145 });
8146 };
8147 privateMethods.swalPromiseResolve.set(instance, resolve);
8148 privateMethods.swalPromiseReject.set(instance, reject);
8149 domCache.confirmButton.onclick = () => {
8150 handleConfirmButtonClick(instance);
8151 };
8152 domCache.denyButton.onclick = () => {
8153 handleDenyButtonClick(instance);
8154 };
8155 domCache.cancelButton.onclick = () => {
8156 handleCancelButtonClick(instance, dismissWith);
8157 };
8158 domCache.closeButton.onclick = () => {
8159 dismissWith(DismissReason.close);
8160 };
8161 handlePopupClick(innerParams, domCache, dismissWith);
8162 addKeydownHandler(globalState, innerParams, dismissWith);
8163 handleInputOptionsAndValue(instance, innerParams);
8164 openPopup(innerParams);
8165 setupTimer(globalState, innerParams, dismissWith);
8166 initFocus(domCache, innerParams);
8167
8168 // Scroll container to top on open (#1247, #1946)
8169 setTimeout(() => {
8170 domCache.container.scrollTop = 0;
8171 });
8172 });
8173 };
8174
8175 /**
8176 * @param {SweetAlertOptions} userParams
8177 * @param {SweetAlertOptions} mixinParams
8178 * @returns {SweetAlertOptions}
8179 */
8180 const prepareParams = (userParams, mixinParams) => {
8181 const templateParams = getTemplateParams(userParams);
8182 const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams); // precedence is described in #2131
8183 params.showClass = Object.assign({}, defaultParams.showClass, params.showClass);
8184 params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass);
8185 if (params.animation === false) {
8186 params.showClass = {
8187 backdrop: 'swal2-noanimation'
8188 };
8189 params.hideClass = {};
8190 }
8191 return params;
8192 };
8193
8194 /**
8195 * @param {SweetAlert} instance
8196 * @returns {DomCache}
8197 */
8198 const populateDomCache = instance => {
8199 const domCache = /** @type {DomCache} */{
8200 popup: (/** @type {HTMLElement} */getPopup()),
8201 container: (/** @type {HTMLElement} */getContainer()),
8202 actions: (/** @type {HTMLElement} */getActions()),
8203 confirmButton: (/** @type {HTMLElement} */getConfirmButton()),
8204 denyButton: (/** @type {HTMLElement} */getDenyButton()),
8205 cancelButton: (/** @type {HTMLElement} */getCancelButton()),
8206 loader: (/** @type {HTMLElement} */getLoader()),
8207 closeButton: (/** @type {HTMLElement} */getCloseButton()),
8208 validationMessage: (/** @type {HTMLElement} */getValidationMessage()),
8209 progressSteps: (/** @type {HTMLElement} */getProgressSteps())
8210 };
8211 privateProps.domCache.set(instance, domCache);
8212 return domCache;
8213 };
8214
8215 /**
8216 * @param {GlobalState} globalState
8217 * @param {SweetAlertOptions} innerParams
8218 * @param {(dismiss: DismissReason) => void} dismissWith
8219 */
8220 const setupTimer = (globalState, innerParams, dismissWith) => {
8221 const timerProgressBar = getTimerProgressBar();
8222 hide(timerProgressBar);
8223 if (innerParams.timer) {
8224 globalState.timeout = new Timer(() => {
8225 dismissWith('timer');
8226 delete globalState.timeout;
8227 }, innerParams.timer);
8228 if (innerParams.timerProgressBar && timerProgressBar) {
8229 show(timerProgressBar);
8230 applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar');
8231 setTimeout(() => {
8232 if (globalState.timeout && globalState.timeout.running) {
8233 // timer can be already stopped or unset at this point
8234 animateTimerProgressBar(/** @type {number} */innerParams.timer);
8235 }
8236 });
8237 }
8238 }
8239 };
8240
8241 /**
8242 * Initialize focus in the popup:
8243 *
8244 * 1. If `toast` is `true`, don't steal focus from the document.
8245 * 2. Else if there is an [autofocus] element, focus it.
8246 * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it.
8247 * 4. Else if `focusDeny` is `true` and deny button is visible, focus it.
8248 * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it.
8249 * 6. Else focus the first focusable element in a popup (if any).
8250 *
8251 * @param {DomCache} domCache
8252 * @param {SweetAlertOptions} innerParams
8253 */
8254 const initFocus = (domCache, innerParams) => {
8255 if (innerParams.toast) {
8256 return;
8257 }
8258 // TODO: this is dumb, remove `allowEnterKey` param in the next major version
8259 if (!callIfFunction(innerParams.allowEnterKey)) {
8260 warnAboutDeprecation('allowEnterKey', 'preConfirm: () => false');
8261 domCache.popup.focus();
8262 return;
8263 }
8264 if (focusAutofocus(domCache)) {
8265 return;
8266 }
8267 if (focusButton(domCache, innerParams)) {
8268 return;
8269 }
8270 setFocus(-1, 1);
8271 };
8272
8273 /**
8274 * @param {DomCache} domCache
8275 * @returns {boolean}
8276 */
8277 const focusAutofocus = domCache => {
8278 const autofocusElements = Array.from(domCache.popup.querySelectorAll('[autofocus]'));
8279 for (const autofocusElement of autofocusElements) {
8280 if (autofocusElement instanceof HTMLElement && isVisible$1(autofocusElement)) {
8281 autofocusElement.focus();
8282 return true;
8283 }
8284 }
8285 return false;
8286 };
8287
8288 /**
8289 * @param {DomCache} domCache
8290 * @param {SweetAlertOptions} innerParams
8291 * @returns {boolean}
8292 */
8293 const focusButton = (domCache, innerParams) => {
8294 if (innerParams.focusDeny && isVisible$1(domCache.denyButton)) {
8295 domCache.denyButton.focus();
8296 return true;
8297 }
8298 if (innerParams.focusCancel && isVisible$1(domCache.cancelButton)) {
8299 domCache.cancelButton.focus();
8300 return true;
8301 }
8302 if (innerParams.focusConfirm && isVisible$1(domCache.confirmButton)) {
8303 domCache.confirmButton.focus();
8304 return true;
8305 }
8306 return false;
8307 };
8308
8309 // Assign instance methods from src/instanceMethods/*.js to prototype
8310 SweetAlert.prototype.disableButtons = disableButtons;
8311 SweetAlert.prototype.enableButtons = enableButtons;
8312 SweetAlert.prototype.getInput = getInput;
8313 SweetAlert.prototype.disableInput = disableInput;
8314 SweetAlert.prototype.enableInput = enableInput;
8315 SweetAlert.prototype.hideLoading = hideLoading;
8316 SweetAlert.prototype.disableLoading = hideLoading;
8317 SweetAlert.prototype.showValidationMessage = showValidationMessage;
8318 SweetAlert.prototype.resetValidationMessage = resetValidationMessage;
8319 SweetAlert.prototype.close = close;
8320 SweetAlert.prototype.closePopup = close;
8321 SweetAlert.prototype.closeModal = close;
8322 SweetAlert.prototype.closeToast = close;
8323 SweetAlert.prototype.rejectPromise = rejectPromise;
8324 SweetAlert.prototype.update = update;
8325 SweetAlert.prototype._destroy = _destroy;
8326
8327 // Assign static methods from src/staticMethods/*.js to constructor
8328 Object.assign(SweetAlert, staticMethods);
8329
8330 // Proxy to instance methods to constructor, for now, for backwards compatibility
8331 Object.keys(instanceMethods).forEach(key => {
8332 /**
8333 * @param {...(SweetAlertOptions | string | undefined)} args
8334 * @returns {SweetAlertResult | Promise<SweetAlertResult> | undefined}
8335 */
8336 // @ts-ignore: Dynamic property assignment for backwards compatibility
8337 SweetAlert[key] = function (...args) {
8338 // @ts-ignore
8339 if (currentInstance && currentInstance[key]) {
8340 // @ts-ignore
8341 return currentInstance[key](...args);
8342 }
8343 return undefined;
8344 };
8345 });
8346 SweetAlert.DismissReason = DismissReason;
8347 SweetAlert.version = '11.26.25';
8348
8349 const Swal = SweetAlert;
8350 // @ts-ignore
8351 Swal.default = Swal;
8352
8353 return Swal;
8354
8355 }));
8356 if (typeof this !== 'undefined' && this.Sweetalert2){this.swal = this.sweetAlert = this.Swal = this.SweetAlert = this.Sweetalert2}
8357 "undefined"!=typeof document&&function(e,t){var n=e.createElement("style");if(e.getElementsByTagName("head")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,":root{--swal2-outline: 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-container-padding: 0.625em;--swal2-backdrop: rgba(0, 0, 0, 0.4);--swal2-backdrop-transition: background-color 0.15s;--swal2-width: 32em;--swal2-padding: 0 0 1.25em;--swal2-border: none;--swal2-border-radius: 0.3125rem;--swal2-background: white;--swal2-color: #545454;--swal2-show-animation: swal2-show 0.3s;--swal2-hide-animation: swal2-hide 0.15s forwards;--swal2-icon-zoom: 1;--swal2-title-padding: 0.8em 1em 0;--swal2-html-container-padding: 1em 1.6em 0.3em;--swal2-input-border: 1px solid #d9d9d9;--swal2-input-border-radius: 0.1875em;--swal2-input-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-background: transparent;--swal2-input-transition: border-color 0.2s, box-shadow 0.2s;--swal2-input-hover-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-focus-border: 1px solid #b4dbed;--swal2-input-focus-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-progress-step-background: #add8e6;--swal2-validation-message-background: #f0f0f0;--swal2-validation-message-color: #666;--swal2-footer-border-color: #eee;--swal2-footer-background: transparent;--swal2-footer-color: inherit;--swal2-timer-progress-bar-background: rgba(0, 0, 0, 0.3);--swal2-close-button-position: initial;--swal2-close-button-inset: auto;--swal2-close-button-font-size: 2.5em;--swal2-close-button-color: #ccc;--swal2-close-button-transition: color 0.2s, box-shadow 0.2s;--swal2-close-button-outline: initial;--swal2-close-button-box-shadow: inset 0 0 0 3px transparent;--swal2-close-button-focus-box-shadow: inset var(--swal2-outline);--swal2-close-button-hover-transform: none;--swal2-actions-justify-content: center;--swal2-actions-width: auto;--swal2-actions-margin: 1.25em auto 0;--swal2-actions-padding: 0;--swal2-actions-border-radius: 0;--swal2-actions-background: transparent;--swal2-action-button-transition: background-color 0.2s, box-shadow 0.2s;--swal2-action-button-hover: black 10%;--swal2-action-button-active: black 10%;--swal2-confirm-button-box-shadow: none;--swal2-confirm-button-border-radius: 0.25em;--swal2-confirm-button-background-color: #7066e0;--swal2-confirm-button-color: #fff;--swal2-deny-button-box-shadow: none;--swal2-deny-button-border-radius: 0.25em;--swal2-deny-button-background-color: #dc3741;--swal2-deny-button-color: #fff;--swal2-cancel-button-box-shadow: none;--swal2-cancel-button-border-radius: 0.25em;--swal2-cancel-button-background-color: #6e7881;--swal2-cancel-button-color: #fff;--swal2-toast-show-animation: swal2-toast-show 0.5s;--swal2-toast-hide-animation: swal2-toast-hide 0.1s forwards;--swal2-toast-border: none;--swal2-toast-box-shadow: 0 0 1px hsl(0deg 0% 0% / 0.075), 0 1px 2px hsl(0deg 0% 0% / 0.075), 1px 2px 4px hsl(0deg 0% 0% / 0.075), 1px 3px 8px hsl(0deg 0% 0% / 0.075), 2px 4px 16px hsl(0deg 0% 0% / 0.075)}[data-swal2-theme=dark]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}@media(prefers-color-scheme: dark){[data-swal2-theme=auto]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto !important}body.swal2-no-backdrop .swal2-container{background-color:rgba(0,0,0,0) !important;pointer-events:none}body.swal2-no-backdrop .swal2-container .swal2-popup{pointer-events:auto}body.swal2-no-backdrop .swal2-container .swal2-modal{box-shadow:0 0 10px var(--swal2-backdrop)}body.swal2-toast-shown .swal2-container{box-sizing:border-box;width:360px;max-width:100%;background-color:rgba(0,0,0,0);pointer-events:none}body.swal2-toast-shown .swal2-container.swal2-top{inset:0 auto auto 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{inset:0 0 auto auto}body.swal2-toast-shown .swal2-container.swal2-top-start,body.swal2-toast-shown .swal2-container.swal2-top-left{inset:0 auto auto 0}body.swal2-toast-shown .swal2-container.swal2-center-start,body.swal2-toast-shown .swal2-container.swal2-center-left{inset:50% auto auto 0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{inset:50% auto auto 50%;transform:translate(-50%, -50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{inset:50% 0 auto auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-start,body.swal2-toast-shown .swal2-container.swal2-bottom-left{inset:auto auto 0 0}body.swal2-toast-shown .swal2-container.swal2-bottom{inset:auto auto 0 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{inset:auto 0 0 auto}@media print{body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow-y:scroll !important}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown) .swal2-container{position:static !important}}div:where(.swal2-container){display:grid;position:fixed;z-index:1060;inset:0;box-sizing:border-box;grid-template-areas:\"top-start top top-end\" \"center-start center center-end\" \"bottom-start bottom-center bottom-end\";grid-template-rows:minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);height:100%;padding:var(--swal2-container-padding);overflow-x:hidden;transition:var(--swal2-backdrop-transition);-webkit-overflow-scrolling:touch}div:where(.swal2-container).swal2-backdrop-show,div:where(.swal2-container).swal2-noanimation{background:var(--swal2-backdrop)}div:where(.swal2-container).swal2-backdrop-hide{background:rgba(0,0,0,0) !important}div:where(.swal2-container).swal2-top-start,div:where(.swal2-container).swal2-center-start,div:where(.swal2-container).swal2-bottom-start{grid-template-columns:minmax(0, 1fr) auto auto}div:where(.swal2-container).swal2-top,div:where(.swal2-container).swal2-center,div:where(.swal2-container).swal2-bottom{grid-template-columns:auto minmax(0, 1fr) auto}div:where(.swal2-container).swal2-top-end,div:where(.swal2-container).swal2-center-end,div:where(.swal2-container).swal2-bottom-end{grid-template-columns:auto auto minmax(0, 1fr)}div:where(.swal2-container).swal2-top-start>.swal2-popup{align-self:start}div:where(.swal2-container).swal2-top>.swal2-popup{grid-column:2;place-self:start center}div:where(.swal2-container).swal2-top-end>.swal2-popup,div:where(.swal2-container).swal2-top-right>.swal2-popup{grid-column:3;place-self:start end}div:where(.swal2-container).swal2-center-start>.swal2-popup,div:where(.swal2-container).swal2-center-left>.swal2-popup{grid-row:2;align-self:center}div:where(.swal2-container).swal2-center>.swal2-popup{grid-column:2;grid-row:2;place-self:center center}div:where(.swal2-container).swal2-center-end>.swal2-popup,div:where(.swal2-container).swal2-center-right>.swal2-popup{grid-column:3;grid-row:2;place-self:center end}div:where(.swal2-container).swal2-bottom-start>.swal2-popup,div:where(.swal2-container).swal2-bottom-left>.swal2-popup{grid-column:1;grid-row:3;align-self:end}div:where(.swal2-container).swal2-bottom>.swal2-popup{grid-column:2;grid-row:3;place-self:end center}div:where(.swal2-container).swal2-bottom-end>.swal2-popup,div:where(.swal2-container).swal2-bottom-right>.swal2-popup{grid-column:3;grid-row:3;place-self:end end}div:where(.swal2-container).swal2-grow-row>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-column:1/4;width:100%}div:where(.swal2-container).swal2-grow-column>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-row:1/4;align-self:stretch}div:where(.swal2-container).swal2-no-transition{transition:none !important}div:where(.swal2-container)[popover]{width:auto;border:0}div:where(.swal2-container) div:where(.swal2-popup){display:none;position:relative;box-sizing:border-box;grid-template-columns:minmax(0, 100%);width:var(--swal2-width);max-width:100%;padding:var(--swal2-padding);border:var(--swal2-border);border-radius:var(--swal2-border-radius);background:var(--swal2-background);color:var(--swal2-color);font-family:inherit;font-size:1rem}div:where(.swal2-container) div:where(.swal2-popup):focus{outline:none}div:where(.swal2-container) div:where(.swal2-popup).swal2-loading{overflow-y:hidden}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable{cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable div:where(.swal2-icon){cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging{cursor:grabbing}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging div:where(.swal2-icon){cursor:grabbing}div:where(.swal2-container) h2:where(.swal2-title){position:relative;max-width:100%;margin:0;padding:var(--swal2-title-padding);color:inherit;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;overflow-wrap:break-word;cursor:initial}div:where(.swal2-container) div:where(.swal2-actions){display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:var(--swal2-actions-justify-content);width:var(--swal2-actions-width);margin:var(--swal2-actions-margin);padding:var(--swal2-actions-padding);border-radius:var(--swal2-actions-border-radius);background:var(--swal2-actions-background)}div:where(.swal2-container) div:where(.swal2-loader){display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 rgba(0,0,0,0) #2778c4 rgba(0,0,0,0)}div:where(.swal2-container) button:where(.swal2-styled){margin:.3125em;padding:.625em 1.1em;transition:var(--swal2-action-button-transition);border:none;box-shadow:0 0 0 3px rgba(0,0,0,0);font-weight:500}div:where(.swal2-container) button:where(.swal2-styled):not([disabled]){cursor:pointer}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm){border-radius:var(--swal2-confirm-button-border-radius);background:initial;background-color:var(--swal2-confirm-button-background-color);box-shadow:var(--swal2-confirm-button-box-shadow);color:var(--swal2-confirm-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):hover{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):active{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny){border-radius:var(--swal2-deny-button-border-radius);background:initial;background-color:var(--swal2-deny-button-background-color);box-shadow:var(--swal2-deny-button-box-shadow);color:var(--swal2-deny-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):hover{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):active{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel){border-radius:var(--swal2-cancel-button-border-radius);background:initial;background-color:var(--swal2-cancel-button-background-color);box-shadow:var(--swal2-cancel-button-box-shadow);color:var(--swal2-cancel-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):hover{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):active{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):focus-visible{outline:none;box-shadow:var(--swal2-action-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-styled)[disabled]:not(.swal2-loading){opacity:.4}div:where(.swal2-container) button:where(.swal2-styled)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-footer){margin:1em 0 0;padding:1em 1em 0;border-top:1px solid var(--swal2-footer-border-color);background:var(--swal2-footer-background);color:var(--swal2-footer-color);font-size:1em;text-align:center;cursor:initial}div:where(.swal2-container) .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto !important;overflow:hidden;border-bottom-right-radius:var(--swal2-border-radius);border-bottom-left-radius:var(--swal2-border-radius)}div:where(.swal2-container) div:where(.swal2-timer-progress-bar){width:100%;height:.25em;background:var(--swal2-timer-progress-bar-background)}div:where(.swal2-container) img:where(.swal2-image){max-width:100%;margin:2em auto 1em;cursor:initial}div:where(.swal2-container) button:where(.swal2-close){position:var(--swal2-close-button-position);inset:var(--swal2-close-button-inset);z-index:2;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-top:0;margin-right:0;margin-bottom:-1.2em;padding:0;overflow:hidden;transition:var(--swal2-close-button-transition);border:none;border-radius:var(--swal2-border-radius);outline:var(--swal2-close-button-outline);background:rgba(0,0,0,0);color:var(--swal2-close-button-color);font-family:monospace;font-size:var(--swal2-close-button-font-size);cursor:pointer;justify-self:end}div:where(.swal2-container) button:where(.swal2-close):hover{transform:var(--swal2-close-button-hover-transform);background:rgba(0,0,0,0);color:#f27474}div:where(.swal2-container) button:where(.swal2-close):focus-visible{outline:none;box-shadow:var(--swal2-close-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-close)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-html-container){z-index:1;justify-content:center;margin:0;padding:var(--swal2-html-container-padding);overflow:auto;color:inherit;font-size:1.125em;font-weight:normal;line-height:normal;text-align:center;overflow-wrap:break-word;word-break:break-word;cursor:initial}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea),div:where(.swal2-container) select:where(.swal2-select),div:where(.swal2-container) div:where(.swal2-radio),div:where(.swal2-container) label:where(.swal2-checkbox){margin:1em 2em 3px}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea){box-sizing:border-box;width:auto;transition:var(--swal2-input-transition);border:var(--swal2-input-border);border-radius:var(--swal2-input-border-radius);background:var(--swal2-input-background);box-shadow:var(--swal2-input-box-shadow);color:inherit;font-size:1.125em}div:where(.swal2-container) input:where(.swal2-input).swal2-inputerror,div:where(.swal2-container) input:where(.swal2-file).swal2-inputerror,div:where(.swal2-container) textarea:where(.swal2-textarea).swal2-inputerror{border-color:#f27474 !important;box-shadow:0 0 2px #f27474 !important}div:where(.swal2-container) input:where(.swal2-input):hover,div:where(.swal2-container) input:where(.swal2-file):hover,div:where(.swal2-container) textarea:where(.swal2-textarea):hover{box-shadow:var(--swal2-input-hover-box-shadow)}div:where(.swal2-container) input:where(.swal2-input):focus,div:where(.swal2-container) input:where(.swal2-file):focus,div:where(.swal2-container) textarea:where(.swal2-textarea):focus{border:var(--swal2-input-focus-border);outline:none;box-shadow:var(--swal2-input-focus-box-shadow)}div:where(.swal2-container) input:where(.swal2-input)::placeholder,div:where(.swal2-container) input:where(.swal2-file)::placeholder,div:where(.swal2-container) textarea:where(.swal2-textarea)::placeholder{color:#ccc}div:where(.swal2-container) .swal2-range{margin:1em 2em 3px;background:var(--swal2-background)}div:where(.swal2-container) .swal2-range input{width:80%}div:where(.swal2-container) .swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}div:where(.swal2-container) .swal2-range input,div:where(.swal2-container) .swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}div:where(.swal2-container) .swal2-input{height:2.625em;padding:0 .75em}div:where(.swal2-container) .swal2-file{width:75%;margin-right:auto;margin-left:auto;background:var(--swal2-input-background);font-size:1.125em}div:where(.swal2-container) .swal2-textarea{height:6.75em;padding:.75em}div:where(.swal2-container) .swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:var(--swal2-input-background);color:inherit;font-size:1.125em}div:where(.swal2-container) .swal2-radio,div:where(.swal2-container) .swal2-checkbox{align-items:center;justify-content:center;background:var(--swal2-background);color:inherit}div:where(.swal2-container) .swal2-radio label,div:where(.swal2-container) .swal2-checkbox label{margin:0 .6em;font-size:1.125em}div:where(.swal2-container) .swal2-radio input,div:where(.swal2-container) .swal2-checkbox input{flex-shrink:0;margin:0 .4em}div:where(.swal2-container) label:where(.swal2-input-label){display:flex;justify-content:center;margin:1em auto 0}div:where(.swal2-container) div:where(.swal2-validation-message){align-items:center;justify-content:center;margin:1em 0 0;padding:.625em;overflow:hidden;background:var(--swal2-validation-message-background);color:var(--swal2-validation-message-color);font-size:1em;font-weight:300}div:where(.swal2-container) div:where(.swal2-validation-message)::before{content:\"!\";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}div:where(.swal2-container) .swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:1.25em auto;padding:0;background:rgba(0,0,0,0);font-weight:600}div:where(.swal2-container) .swal2-progress-steps li{display:inline-block;position:relative}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:var(--swal2-progress-step-background);color:#fff}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:var(--swal2-progress-step-background)}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}div:where(.swal2-icon){position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:2.5em auto .6em;zoom:var(--swal2-icon-zoom);border:.25em solid rgba(0,0,0,0);border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;user-select:none}div:where(.swal2-icon) .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}div:where(.swal2-icon).swal2-error{border-color:#f27474;color:#f27474}div:where(.swal2-icon).swal2-error .swal2-x-mark{position:relative;flex-grow:1}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-error.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-error.swal2-icon-show .swal2-x-mark{animation:swal2-animate-error-x-mark .5s}div:where(.swal2-icon).swal2-warning{border-color:#f8bb86;color:#f8bb86}div:where(.swal2-icon).swal2-warning.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-warning.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .5s}div:where(.swal2-icon).swal2-info{border-color:#3fc3ee;color:#3fc3ee}div:where(.swal2-icon).swal2-info.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-info.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .8s}div:where(.swal2-icon).swal2-question{border-color:#87adbd;color:#87adbd}div:where(.swal2-icon).swal2-question.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-question.swal2-icon-show .swal2-icon-content{animation:swal2-animate-question-mark .8s}div:where(.swal2-icon).swal2-success{border-color:#a5dc86;color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;border-radius:50%}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}div:where(.swal2-icon).swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-0.25em;left:-0.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}div:where(.swal2-icon).swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-animate-success-line-tip .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-animate-success-line-long .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-circular-line-right{animation:swal2-rotate-success-circular-line 4.25s ease-in}[class^=swal2]{-webkit-tap-highlight-color:rgba(0,0,0,0)}.swal2-show{animation:var(--swal2-show-animation)}.swal2-hide{animation:var(--swal2-hide-animation)}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{margin-right:initial;margin-left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}.swal2-toast{box-sizing:border-box;grid-column:1/4 !important;grid-row:1/4 !important;grid-template-columns:min-content auto min-content;padding:1em;overflow-y:hidden;border:var(--swal2-toast-border);background:var(--swal2-background);box-shadow:var(--swal2-toast-box-shadow);pointer-events:auto}.swal2-toast>*{grid-column:2}.swal2-toast h2:where(.swal2-title){margin:.5em 1em;padding:0;font-size:1em;text-align:initial}.swal2-toast .swal2-loading{justify-content:center}.swal2-toast input:where(.swal2-input){height:2em;margin:.5em;font-size:1em}.swal2-toast .swal2-validation-message{font-size:1em}.swal2-toast div:where(.swal2-footer){margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-toast button:where(.swal2-close){grid-column:3/3;grid-row:1/99;align-self:center;width:.8em;height:.8em;margin:0;font-size:2em}.swal2-toast div:where(.swal2-html-container){margin:.5em 1em;padding:0;overflow:initial;font-size:1em;text-align:initial}.swal2-toast div:where(.swal2-html-container):empty{padding:0}.swal2-toast .swal2-loader{grid-column:1;grid-row:1/99;align-self:center;width:2em;height:2em;margin:.25em}.swal2-toast .swal2-icon{grid-column:1;grid-row:1/99;align-self:center;width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:bold}.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-toast div:where(.swal2-actions){justify-content:flex-start;height:auto;margin:0;margin-top:.5em;padding:0 .5em}.swal2-toast button:where(.swal2-styled){margin:.25em .5em;padding:.4em .6em;font-size:1em}.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;border-radius:50%}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.8em;left:-0.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-toast-animate-success-line-tip .75s}.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-toast-animate-success-line-long .75s}.swal2-toast.swal2-show{animation:var(--swal2-toast-show-animation)}.swal2-toast.swal2-hide{animation:var(--swal2-toast-hide-animation)}@keyframes swal2-show{0%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}100%{transform:translate3d(0, 0, 0) scale(1);opacity:1}}@keyframes swal2-hide{0%{transform:translate3d(0, 0, 0) scale(1);opacity:1}100%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-0.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(0.4);opacity:0}50%{margin-top:1.625em;transform:scale(0.4);opacity:0}80%{margin-top:-0.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);opacity:1}}@keyframes swal2-rotate-loading{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes swal2-animate-question-mark{0%{transform:rotateY(-360deg)}100%{transform:rotateY(0)}}@keyframes swal2-animate-i-mark{0%{transform:rotateZ(45deg);opacity:0}25%{transform:rotateZ(-25deg);opacity:.4}50%{transform:rotateZ(15deg);opacity:.8}75%{transform:rotateZ(-5deg);opacity:1}100%{transform:rotateX(0);opacity:1}}@keyframes swal2-toast-show{0%{transform:translateY(-0.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(0.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0deg)}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-0.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}");
8358
8359 /***/ },
8360
8361 /***/ "./node_modules/@kurkle/color/dist/color.esm.js"
8362 /*!******************************************************!*\
8363 !*** ./node_modules/@kurkle/color/dist/color.esm.js ***!
8364 \******************************************************/
8365 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8366
8367 "use strict";
8368 __webpack_require__.r(__webpack_exports__);
8369 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8370 /* harmony export */ Color: () => (/* binding */ Color),
8371 /* harmony export */ b2n: () => (/* binding */ b2n),
8372 /* harmony export */ b2p: () => (/* binding */ b2p),
8373 /* harmony export */ "default": () => (/* binding */ index_esm),
8374 /* harmony export */ hexParse: () => (/* binding */ hexParse),
8375 /* harmony export */ hexString: () => (/* binding */ hexString),
8376 /* harmony export */ hsl2rgb: () => (/* binding */ hsl2rgb),
8377 /* harmony export */ hslString: () => (/* binding */ hslString),
8378 /* harmony export */ hsv2rgb: () => (/* binding */ hsv2rgb),
8379 /* harmony export */ hueParse: () => (/* binding */ hueParse),
8380 /* harmony export */ hwb2rgb: () => (/* binding */ hwb2rgb),
8381 /* harmony export */ lim: () => (/* binding */ lim),
8382 /* harmony export */ n2b: () => (/* binding */ n2b),
8383 /* harmony export */ n2p: () => (/* binding */ n2p),
8384 /* harmony export */ nameParse: () => (/* binding */ nameParse),
8385 /* harmony export */ p2b: () => (/* binding */ p2b),
8386 /* harmony export */ rgb2hsl: () => (/* binding */ rgb2hsl),
8387 /* harmony export */ rgbParse: () => (/* binding */ rgbParse),
8388 /* harmony export */ rgbString: () => (/* binding */ rgbString),
8389 /* harmony export */ rotate: () => (/* binding */ rotate),
8390 /* harmony export */ round: () => (/* binding */ round)
8391 /* harmony export */ });
8392 /*!
8393 * @kurkle/color v0.3.4
8394 * https://github.com/kurkle/color#readme
8395 * (c) 2024 Jukka Kurkela
8396 * Released under the MIT License
8397 */
8398 function round(v) {
8399 return v + 0.5 | 0;
8400 }
8401 const lim = (v, l, h) => Math.max(Math.min(v, h), l);
8402 function p2b(v) {
8403 return lim(round(v * 2.55), 0, 255);
8404 }
8405 function b2p(v) {
8406 return lim(round(v / 2.55), 0, 100);
8407 }
8408 function n2b(v) {
8409 return lim(round(v * 255), 0, 255);
8410 }
8411 function b2n(v) {
8412 return lim(round(v / 2.55) / 100, 0, 1);
8413 }
8414 function n2p(v) {
8415 return lim(round(v * 100), 0, 100);
8416 }
8417
8418 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};
8419 const hex = [...'0123456789ABCDEF'];
8420 const h1 = b => hex[b & 0xF];
8421 const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF];
8422 const eq = b => ((b & 0xF0) >> 4) === (b & 0xF);
8423 const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);
8424 function hexParse(str) {
8425 var len = str.length;
8426 var ret;
8427 if (str[0] === '#') {
8428 if (len === 4 || len === 5) {
8429 ret = {
8430 r: 255 & map$1[str[1]] * 17,
8431 g: 255 & map$1[str[2]] * 17,
8432 b: 255 & map$1[str[3]] * 17,
8433 a: len === 5 ? map$1[str[4]] * 17 : 255
8434 };
8435 } else if (len === 7 || len === 9) {
8436 ret = {
8437 r: map$1[str[1]] << 4 | map$1[str[2]],
8438 g: map$1[str[3]] << 4 | map$1[str[4]],
8439 b: map$1[str[5]] << 4 | map$1[str[6]],
8440 a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255
8441 };
8442 }
8443 }
8444 return ret;
8445 }
8446 const alpha = (a, f) => a < 255 ? f(a) : '';
8447 function hexString(v) {
8448 var f = isShort(v) ? h1 : h2;
8449 return v
8450 ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f)
8451 : undefined;
8452 }
8453
8454 const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
8455 function hsl2rgbn(h, s, l) {
8456 const a = s * Math.min(l, 1 - l);
8457 const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
8458 return [f(0), f(8), f(4)];
8459 }
8460 function hsv2rgbn(h, s, v) {
8461 const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
8462 return [f(5), f(3), f(1)];
8463 }
8464 function hwb2rgbn(h, w, b) {
8465 const rgb = hsl2rgbn(h, 1, 0.5);
8466 let i;
8467 if (w + b > 1) {
8468 i = 1 / (w + b);
8469 w *= i;
8470 b *= i;
8471 }
8472 for (i = 0; i < 3; i++) {
8473 rgb[i] *= 1 - w - b;
8474 rgb[i] += w;
8475 }
8476 return rgb;
8477 }
8478 function hueValue(r, g, b, d, max) {
8479 if (r === max) {
8480 return ((g - b) / d) + (g < b ? 6 : 0);
8481 }
8482 if (g === max) {
8483 return (b - r) / d + 2;
8484 }
8485 return (r - g) / d + 4;
8486 }
8487 function rgb2hsl(v) {
8488 const range = 255;
8489 const r = v.r / range;
8490 const g = v.g / range;
8491 const b = v.b / range;
8492 const max = Math.max(r, g, b);
8493 const min = Math.min(r, g, b);
8494 const l = (max + min) / 2;
8495 let h, s, d;
8496 if (max !== min) {
8497 d = max - min;
8498 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
8499 h = hueValue(r, g, b, d, max);
8500 h = h * 60 + 0.5;
8501 }
8502 return [h | 0, s || 0, l];
8503 }
8504 function calln(f, a, b, c) {
8505 return (
8506 Array.isArray(a)
8507 ? f(a[0], a[1], a[2])
8508 : f(a, b, c)
8509 ).map(n2b);
8510 }
8511 function hsl2rgb(h, s, l) {
8512 return calln(hsl2rgbn, h, s, l);
8513 }
8514 function hwb2rgb(h, w, b) {
8515 return calln(hwb2rgbn, h, w, b);
8516 }
8517 function hsv2rgb(h, s, v) {
8518 return calln(hsv2rgbn, h, s, v);
8519 }
8520 function hue(h) {
8521 return (h % 360 + 360) % 360;
8522 }
8523 function hueParse(str) {
8524 const m = HUE_RE.exec(str);
8525 let a = 255;
8526 let v;
8527 if (!m) {
8528 return;
8529 }
8530 if (m[5] !== v) {
8531 a = m[6] ? p2b(+m[5]) : n2b(+m[5]);
8532 }
8533 const h = hue(+m[2]);
8534 const p1 = +m[3] / 100;
8535 const p2 = +m[4] / 100;
8536 if (m[1] === 'hwb') {
8537 v = hwb2rgb(h, p1, p2);
8538 } else if (m[1] === 'hsv') {
8539 v = hsv2rgb(h, p1, p2);
8540 } else {
8541 v = hsl2rgb(h, p1, p2);
8542 }
8543 return {
8544 r: v[0],
8545 g: v[1],
8546 b: v[2],
8547 a: a
8548 };
8549 }
8550 function rotate(v, deg) {
8551 var h = rgb2hsl(v);
8552 h[0] = hue(h[0] + deg);
8553 h = hsl2rgb(h);
8554 v.r = h[0];
8555 v.g = h[1];
8556 v.b = h[2];
8557 }
8558 function hslString(v) {
8559 if (!v) {
8560 return;
8561 }
8562 const a = rgb2hsl(v);
8563 const h = a[0];
8564 const s = n2p(a[1]);
8565 const l = n2p(a[2]);
8566 return v.a < 255
8567 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`
8568 : `hsl(${h}, ${s}%, ${l}%)`;
8569 }
8570
8571 const map = {
8572 x: 'dark',
8573 Z: 'light',
8574 Y: 're',
8575 X: 'blu',
8576 W: 'gr',
8577 V: 'medium',
8578 U: 'slate',
8579 A: 'ee',
8580 T: 'ol',
8581 S: 'or',
8582 B: 'ra',
8583 C: 'lateg',
8584 D: 'ights',
8585 R: 'in',
8586 Q: 'turquois',
8587 E: 'hi',
8588 P: 'ro',
8589 O: 'al',
8590 N: 'le',
8591 M: 'de',
8592 L: 'yello',
8593 F: 'en',
8594 K: 'ch',
8595 G: 'arks',
8596 H: 'ea',
8597 I: 'ightg',
8598 J: 'wh'
8599 };
8600 const names$1 = {
8601 OiceXe: 'f0f8ff',
8602 antiquewEte: 'faebd7',
8603 aqua: 'ffff',
8604 aquamarRe: '7fffd4',
8605 azuY: 'f0ffff',
8606 beige: 'f5f5dc',
8607 bisque: 'ffe4c4',
8608 black: '0',
8609 blanKedOmond: 'ffebcd',
8610 Xe: 'ff',
8611 XeviTet: '8a2be2',
8612 bPwn: 'a52a2a',
8613 burlywood: 'deb887',
8614 caMtXe: '5f9ea0',
8615 KartYuse: '7fff00',
8616 KocTate: 'd2691e',
8617 cSO: 'ff7f50',
8618 cSnflowerXe: '6495ed',
8619 cSnsilk: 'fff8dc',
8620 crimson: 'dc143c',
8621 cyan: 'ffff',
8622 xXe: '8b',
8623 xcyan: '8b8b',
8624 xgTMnPd: 'b8860b',
8625 xWay: 'a9a9a9',
8626 xgYF: '6400',
8627 xgYy: 'a9a9a9',
8628 xkhaki: 'bdb76b',
8629 xmagFta: '8b008b',
8630 xTivegYF: '556b2f',
8631 xSange: 'ff8c00',
8632 xScEd: '9932cc',
8633 xYd: '8b0000',
8634 xsOmon: 'e9967a',
8635 xsHgYF: '8fbc8f',
8636 xUXe: '483d8b',
8637 xUWay: '2f4f4f',
8638 xUgYy: '2f4f4f',
8639 xQe: 'ced1',
8640 xviTet: '9400d3',
8641 dAppRk: 'ff1493',
8642 dApskyXe: 'bfff',
8643 dimWay: '696969',
8644 dimgYy: '696969',
8645 dodgerXe: '1e90ff',
8646 fiYbrick: 'b22222',
8647 flSOwEte: 'fffaf0',
8648 foYstWAn: '228b22',
8649 fuKsia: 'ff00ff',
8650 gaRsbSo: 'dcdcdc',
8651 ghostwEte: 'f8f8ff',
8652 gTd: 'ffd700',
8653 gTMnPd: 'daa520',
8654 Way: '808080',
8655 gYF: '8000',
8656 gYFLw: 'adff2f',
8657 gYy: '808080',
8658 honeyMw: 'f0fff0',
8659 hotpRk: 'ff69b4',
8660 RdianYd: 'cd5c5c',
8661 Rdigo: '4b0082',
8662 ivSy: 'fffff0',
8663 khaki: 'f0e68c',
8664 lavFMr: 'e6e6fa',
8665 lavFMrXsh: 'fff0f5',
8666 lawngYF: '7cfc00',
8667 NmoncEffon: 'fffacd',
8668 ZXe: 'add8e6',
8669 ZcSO: 'f08080',
8670 Zcyan: 'e0ffff',
8671 ZgTMnPdLw: 'fafad2',
8672 ZWay: 'd3d3d3',
8673 ZgYF: '90ee90',
8674 ZgYy: 'd3d3d3',
8675 ZpRk: 'ffb6c1',
8676 ZsOmon: 'ffa07a',
8677 ZsHgYF: '20b2aa',
8678 ZskyXe: '87cefa',
8679 ZUWay: '778899',
8680 ZUgYy: '778899',
8681 ZstAlXe: 'b0c4de',
8682 ZLw: 'ffffe0',
8683 lime: 'ff00',
8684 limegYF: '32cd32',
8685 lRF: 'faf0e6',
8686 magFta: 'ff00ff',
8687 maPon: '800000',
8688 VaquamarRe: '66cdaa',
8689 VXe: 'cd',
8690 VScEd: 'ba55d3',
8691 VpurpN: '9370db',
8692 VsHgYF: '3cb371',
8693 VUXe: '7b68ee',
8694 VsprRggYF: 'fa9a',
8695 VQe: '48d1cc',
8696 VviTetYd: 'c71585',
8697 midnightXe: '191970',
8698 mRtcYam: 'f5fffa',
8699 mistyPse: 'ffe4e1',
8700 moccasR: 'ffe4b5',
8701 navajowEte: 'ffdead',
8702 navy: '80',
8703 Tdlace: 'fdf5e6',
8704 Tive: '808000',
8705 TivedBb: '6b8e23',
8706 Sange: 'ffa500',
8707 SangeYd: 'ff4500',
8708 ScEd: 'da70d6',
8709 pOegTMnPd: 'eee8aa',
8710 pOegYF: '98fb98',
8711 pOeQe: 'afeeee',
8712 pOeviTetYd: 'db7093',
8713 papayawEp: 'ffefd5',
8714 pHKpuff: 'ffdab9',
8715 peru: 'cd853f',
8716 pRk: 'ffc0cb',
8717 plum: 'dda0dd',
8718 powMrXe: 'b0e0e6',
8719 purpN: '800080',
8720 YbeccapurpN: '663399',
8721 Yd: 'ff0000',
8722 Psybrown: 'bc8f8f',
8723 PyOXe: '4169e1',
8724 saddNbPwn: '8b4513',
8725 sOmon: 'fa8072',
8726 sandybPwn: 'f4a460',
8727 sHgYF: '2e8b57',
8728 sHshell: 'fff5ee',
8729 siFna: 'a0522d',
8730 silver: 'c0c0c0',
8731 skyXe: '87ceeb',
8732 UXe: '6a5acd',
8733 UWay: '708090',
8734 UgYy: '708090',
8735 snow: 'fffafa',
8736 sprRggYF: 'ff7f',
8737 stAlXe: '4682b4',
8738 tan: 'd2b48c',
8739 teO: '8080',
8740 tEstN: 'd8bfd8',
8741 tomato: 'ff6347',
8742 Qe: '40e0d0',
8743 viTet: 'ee82ee',
8744 JHt: 'f5deb3',
8745 wEte: 'ffffff',
8746 wEtesmoke: 'f5f5f5',
8747 Lw: 'ffff00',
8748 LwgYF: '9acd32'
8749 };
8750 function unpack() {
8751 const unpacked = {};
8752 const keys = Object.keys(names$1);
8753 const tkeys = Object.keys(map);
8754 let i, j, k, ok, nk;
8755 for (i = 0; i < keys.length; i++) {
8756 ok = nk = keys[i];
8757 for (j = 0; j < tkeys.length; j++) {
8758 k = tkeys[j];
8759 nk = nk.replace(k, map[k]);
8760 }
8761 k = parseInt(names$1[ok], 16);
8762 unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];
8763 }
8764 return unpacked;
8765 }
8766
8767 let names;
8768 function nameParse(str) {
8769 if (!names) {
8770 names = unpack();
8771 names.transparent = [0, 0, 0, 0];
8772 }
8773 const a = names[str.toLowerCase()];
8774 return a && {
8775 r: a[0],
8776 g: a[1],
8777 b: a[2],
8778 a: a.length === 4 ? a[3] : 255
8779 };
8780 }
8781
8782 const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
8783 function rgbParse(str) {
8784 const m = RGB_RE.exec(str);
8785 let a = 255;
8786 let r, g, b;
8787 if (!m) {
8788 return;
8789 }
8790 if (m[7] !== r) {
8791 const v = +m[7];
8792 a = m[8] ? p2b(v) : lim(v * 255, 0, 255);
8793 }
8794 r = +m[1];
8795 g = +m[3];
8796 b = +m[5];
8797 r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255));
8798 g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255));
8799 b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255));
8800 return {
8801 r: r,
8802 g: g,
8803 b: b,
8804 a: a
8805 };
8806 }
8807 function rgbString(v) {
8808 return v && (
8809 v.a < 255
8810 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`
8811 : `rgb(${v.r}, ${v.g}, ${v.b})`
8812 );
8813 }
8814
8815 const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055;
8816 const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
8817 function interpolate(rgb1, rgb2, t) {
8818 const r = from(b2n(rgb1.r));
8819 const g = from(b2n(rgb1.g));
8820 const b = from(b2n(rgb1.b));
8821 return {
8822 r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))),
8823 g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))),
8824 b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))),
8825 a: rgb1.a + t * (rgb2.a - rgb1.a)
8826 };
8827 }
8828
8829 function modHSL(v, i, ratio) {
8830 if (v) {
8831 let tmp = rgb2hsl(v);
8832 tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));
8833 tmp = hsl2rgb(tmp);
8834 v.r = tmp[0];
8835 v.g = tmp[1];
8836 v.b = tmp[2];
8837 }
8838 }
8839 function clone(v, proto) {
8840 return v ? Object.assign(proto || {}, v) : v;
8841 }
8842 function fromObject(input) {
8843 var v = {r: 0, g: 0, b: 0, a: 255};
8844 if (Array.isArray(input)) {
8845 if (input.length >= 3) {
8846 v = {r: input[0], g: input[1], b: input[2], a: 255};
8847 if (input.length > 3) {
8848 v.a = n2b(input[3]);
8849 }
8850 }
8851 } else {
8852 v = clone(input, {r: 0, g: 0, b: 0, a: 1});
8853 v.a = n2b(v.a);
8854 }
8855 return v;
8856 }
8857 function functionParse(str) {
8858 if (str.charAt(0) === 'r') {
8859 return rgbParse(str);
8860 }
8861 return hueParse(str);
8862 }
8863 class Color {
8864 constructor(input) {
8865 if (input instanceof Color) {
8866 return input;
8867 }
8868 const type = typeof input;
8869 let v;
8870 if (type === 'object') {
8871 v = fromObject(input);
8872 } else if (type === 'string') {
8873 v = hexParse(input) || nameParse(input) || functionParse(input);
8874 }
8875 this._rgb = v;
8876 this._valid = !!v;
8877 }
8878 get valid() {
8879 return this._valid;
8880 }
8881 get rgb() {
8882 var v = clone(this._rgb);
8883 if (v) {
8884 v.a = b2n(v.a);
8885 }
8886 return v;
8887 }
8888 set rgb(obj) {
8889 this._rgb = fromObject(obj);
8890 }
8891 rgbString() {
8892 return this._valid ? rgbString(this._rgb) : undefined;
8893 }
8894 hexString() {
8895 return this._valid ? hexString(this._rgb) : undefined;
8896 }
8897 hslString() {
8898 return this._valid ? hslString(this._rgb) : undefined;
8899 }
8900 mix(color, weight) {
8901 if (color) {
8902 const c1 = this.rgb;
8903 const c2 = color.rgb;
8904 let w2;
8905 const p = weight === w2 ? 0.5 : weight;
8906 const w = 2 * p - 1;
8907 const a = c1.a - c2.a;
8908 const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
8909 w2 = 1 - w1;
8910 c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;
8911 c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;
8912 c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;
8913 c1.a = p * c1.a + (1 - p) * c2.a;
8914 this.rgb = c1;
8915 }
8916 return this;
8917 }
8918 interpolate(color, t) {
8919 if (color) {
8920 this._rgb = interpolate(this._rgb, color._rgb, t);
8921 }
8922 return this;
8923 }
8924 clone() {
8925 return new Color(this.rgb);
8926 }
8927 alpha(a) {
8928 this._rgb.a = n2b(a);
8929 return this;
8930 }
8931 clearer(ratio) {
8932 const rgb = this._rgb;
8933 rgb.a *= 1 - ratio;
8934 return this;
8935 }
8936 greyscale() {
8937 const rgb = this._rgb;
8938 const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
8939 rgb.r = rgb.g = rgb.b = val;
8940 return this;
8941 }
8942 opaquer(ratio) {
8943 const rgb = this._rgb;
8944 rgb.a *= 1 + ratio;
8945 return this;
8946 }
8947 negate() {
8948 const v = this._rgb;
8949 v.r = 255 - v.r;
8950 v.g = 255 - v.g;
8951 v.b = 255 - v.b;
8952 return this;
8953 }
8954 lighten(ratio) {
8955 modHSL(this._rgb, 2, ratio);
8956 return this;
8957 }
8958 darken(ratio) {
8959 modHSL(this._rgb, 2, -ratio);
8960 return this;
8961 }
8962 saturate(ratio) {
8963 modHSL(this._rgb, 1, ratio);
8964 return this;
8965 }
8966 desaturate(ratio) {
8967 modHSL(this._rgb, 1, -ratio);
8968 return this;
8969 }
8970 rotate(deg) {
8971 rotate(this._rgb, deg);
8972 return this;
8973 }
8974 }
8975
8976 function index_esm(input) {
8977 return new Color(input);
8978 }
8979
8980
8981
8982
8983 /***/ },
8984
8985 /***/ "./node_modules/chart.js/auto/auto.js"
8986 /*!********************************************!*\
8987 !*** ./node_modules/chart.js/auto/auto.js ***!
8988 \********************************************/
8989 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
8990
8991 "use strict";
8992 __webpack_require__.r(__webpack_exports__);
8993 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8994 /* harmony export */ Animation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animation),
8995 /* harmony export */ Animations: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animations),
8996 /* harmony export */ ArcElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ArcElement),
8997 /* harmony export */ BarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarController),
8998 /* harmony export */ BarElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarElement),
8999 /* harmony export */ BasePlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasePlatform),
9000 /* harmony export */ BasicPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasicPlatform),
9001 /* harmony export */ BubbleController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BubbleController),
9002 /* harmony export */ CategoryScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.CategoryScale),
9003 /* harmony export */ Chart: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart),
9004 /* harmony export */ Colors: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Colors),
9005 /* harmony export */ DatasetController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DatasetController),
9006 /* harmony export */ Decimation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Decimation),
9007 /* harmony export */ DomPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DomPlatform),
9008 /* harmony export */ DoughnutController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DoughnutController),
9009 /* harmony export */ Element: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Element),
9010 /* harmony export */ Filler: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Filler),
9011 /* harmony export */ Interaction: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Interaction),
9012 /* harmony export */ Legend: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Legend),
9013 /* harmony export */ LineController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineController),
9014 /* harmony export */ LineElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineElement),
9015 /* harmony export */ LinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LinearScale),
9016 /* harmony export */ LogarithmicScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LogarithmicScale),
9017 /* harmony export */ PieController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PieController),
9018 /* harmony export */ PointElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PointElement),
9019 /* harmony export */ PolarAreaController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PolarAreaController),
9020 /* harmony export */ RadarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadarController),
9021 /* harmony export */ RadialLinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadialLinearScale),
9022 /* harmony export */ Scale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Scale),
9023 /* harmony export */ ScatterController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ScatterController),
9024 /* harmony export */ SubTitle: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.SubTitle),
9025 /* harmony export */ Ticks: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Ticks),
9026 /* harmony export */ TimeScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeScale),
9027 /* harmony export */ TimeSeriesScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeSeriesScale),
9028 /* harmony export */ Title: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Title),
9029 /* harmony export */ Tooltip: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Tooltip),
9030 /* harmony export */ _adapters: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._adapters),
9031 /* harmony export */ _detectPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._detectPlatform),
9032 /* harmony export */ animator: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.animator),
9033 /* harmony export */ controllers: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.controllers),
9034 /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
9035 /* harmony export */ defaults: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.defaults),
9036 /* harmony export */ elements: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.elements),
9037 /* harmony export */ layouts: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.layouts),
9038 /* harmony export */ plugins: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.plugins),
9039 /* harmony export */ registerables: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables),
9040 /* harmony export */ registry: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registry),
9041 /* harmony export */ scales: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.scales)
9042 /* harmony export */ });
9043 /* harmony import */ var _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../dist/chart.js */ "./node_modules/chart.js/dist/chart.js");
9044
9045
9046 _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart.register(..._dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables);
9047
9048
9049 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart);
9050
9051
9052 /***/ },
9053
9054 /***/ "./node_modules/chart.js/dist/chart.js"
9055 /*!*********************************************!*\
9056 !*** ./node_modules/chart.js/dist/chart.js ***!
9057 \*********************************************/
9058 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
9059
9060 "use strict";
9061 __webpack_require__.r(__webpack_exports__);
9062 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9063 /* harmony export */ Animation: () => (/* binding */ Animation),
9064 /* harmony export */ Animations: () => (/* binding */ Animations),
9065 /* harmony export */ ArcElement: () => (/* binding */ ArcElement),
9066 /* harmony export */ BarController: () => (/* binding */ BarController),
9067 /* harmony export */ BarElement: () => (/* binding */ BarElement),
9068 /* harmony export */ BasePlatform: () => (/* binding */ BasePlatform),
9069 /* harmony export */ BasicPlatform: () => (/* binding */ BasicPlatform),
9070 /* harmony export */ BubbleController: () => (/* binding */ BubbleController),
9071 /* harmony export */ CategoryScale: () => (/* binding */ CategoryScale),
9072 /* harmony export */ Chart: () => (/* binding */ Chart),
9073 /* harmony export */ Colors: () => (/* binding */ plugin_colors),
9074 /* harmony export */ DatasetController: () => (/* binding */ DatasetController),
9075 /* harmony export */ Decimation: () => (/* binding */ plugin_decimation),
9076 /* harmony export */ DomPlatform: () => (/* binding */ DomPlatform),
9077 /* harmony export */ DoughnutController: () => (/* binding */ DoughnutController),
9078 /* harmony export */ Element: () => (/* binding */ Element),
9079 /* harmony export */ Filler: () => (/* binding */ index),
9080 /* harmony export */ Interaction: () => (/* binding */ Interaction),
9081 /* harmony export */ Legend: () => (/* binding */ plugin_legend),
9082 /* harmony export */ LineController: () => (/* binding */ LineController),
9083 /* harmony export */ LineElement: () => (/* binding */ LineElement),
9084 /* harmony export */ LinearScale: () => (/* binding */ LinearScale),
9085 /* harmony export */ LogarithmicScale: () => (/* binding */ LogarithmicScale),
9086 /* harmony export */ PieController: () => (/* binding */ PieController),
9087 /* harmony export */ PointElement: () => (/* binding */ PointElement),
9088 /* harmony export */ PolarAreaController: () => (/* binding */ PolarAreaController),
9089 /* harmony export */ RadarController: () => (/* binding */ RadarController),
9090 /* harmony export */ RadialLinearScale: () => (/* binding */ RadialLinearScale),
9091 /* harmony export */ Scale: () => (/* binding */ Scale),
9092 /* harmony export */ ScatterController: () => (/* binding */ ScatterController),
9093 /* harmony export */ SubTitle: () => (/* binding */ plugin_subtitle),
9094 /* harmony export */ Ticks: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM),
9095 /* harmony export */ TimeScale: () => (/* binding */ TimeScale),
9096 /* harmony export */ TimeSeriesScale: () => (/* binding */ TimeSeriesScale),
9097 /* harmony export */ Title: () => (/* binding */ plugin_title),
9098 /* harmony export */ Tooltip: () => (/* binding */ plugin_tooltip),
9099 /* harmony export */ _adapters: () => (/* binding */ adapters),
9100 /* harmony export */ _detectPlatform: () => (/* binding */ _detectPlatform),
9101 /* harmony export */ animator: () => (/* binding */ animator),
9102 /* harmony export */ controllers: () => (/* binding */ controllers),
9103 /* harmony export */ defaults: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d),
9104 /* harmony export */ elements: () => (/* binding */ elements),
9105 /* harmony export */ layouts: () => (/* binding */ layouts),
9106 /* harmony export */ plugins: () => (/* binding */ plugins),
9107 /* harmony export */ registerables: () => (/* binding */ registerables),
9108 /* harmony export */ registry: () => (/* binding */ registry),
9109 /* harmony export */ scales: () => (/* binding */ scales)
9110 /* harmony export */ });
9111 /* 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");
9112 /*!
9113 * Chart.js v4.5.1
9114 * https://www.chartjs.org
9115 * (c) 2025 Chart.js Contributors
9116 * Released under the MIT License
9117 */
9118
9119
9120
9121 class Animator {
9122 constructor(){
9123 this._request = null;
9124 this._charts = new Map();
9125 this._running = false;
9126 this._lastDate = undefined;
9127 }
9128 _notify(chart, anims, date, type) {
9129 const callbacks = anims.listeners[type];
9130 const numSteps = anims.duration;
9131 callbacks.forEach((fn)=>fn({
9132 chart,
9133 initial: anims.initial,
9134 numSteps,
9135 currentStep: Math.min(date - anims.start, numSteps)
9136 }));
9137 }
9138 _refresh() {
9139 if (this._request) {
9140 return;
9141 }
9142 this._running = true;
9143 this._request = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.r.call(window, ()=>{
9144 this._update();
9145 this._request = null;
9146 if (this._running) {
9147 this._refresh();
9148 }
9149 });
9150 }
9151 _update(date = Date.now()) {
9152 let remaining = 0;
9153 this._charts.forEach((anims, chart)=>{
9154 if (!anims.running || !anims.items.length) {
9155 return;
9156 }
9157 const items = anims.items;
9158 let i = items.length - 1;
9159 let draw = false;
9160 let item;
9161 for(; i >= 0; --i){
9162 item = items[i];
9163 if (item._active) {
9164 if (item._total > anims.duration) {
9165 anims.duration = item._total;
9166 }
9167 item.tick(date);
9168 draw = true;
9169 } else {
9170 items[i] = items[items.length - 1];
9171 items.pop();
9172 }
9173 }
9174 if (draw) {
9175 chart.draw();
9176 this._notify(chart, anims, date, 'progress');
9177 }
9178 if (!items.length) {
9179 anims.running = false;
9180 this._notify(chart, anims, date, 'complete');
9181 anims.initial = false;
9182 }
9183 remaining += items.length;
9184 });
9185 this._lastDate = date;
9186 if (remaining === 0) {
9187 this._running = false;
9188 }
9189 }
9190 _getAnims(chart) {
9191 const charts = this._charts;
9192 let anims = charts.get(chart);
9193 if (!anims) {
9194 anims = {
9195 running: false,
9196 initial: true,
9197 items: [],
9198 listeners: {
9199 complete: [],
9200 progress: []
9201 }
9202 };
9203 charts.set(chart, anims);
9204 }
9205 return anims;
9206 }
9207 listen(chart, event, cb) {
9208 this._getAnims(chart).listeners[event].push(cb);
9209 }
9210 add(chart, items) {
9211 if (!items || !items.length) {
9212 return;
9213 }
9214 this._getAnims(chart).items.push(...items);
9215 }
9216 has(chart) {
9217 return this._getAnims(chart).items.length > 0;
9218 }
9219 start(chart) {
9220 const anims = this._charts.get(chart);
9221 if (!anims) {
9222 return;
9223 }
9224 anims.running = true;
9225 anims.start = Date.now();
9226 anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0);
9227 this._refresh();
9228 }
9229 running(chart) {
9230 if (!this._running) {
9231 return false;
9232 }
9233 const anims = this._charts.get(chart);
9234 if (!anims || !anims.running || !anims.items.length) {
9235 return false;
9236 }
9237 return true;
9238 }
9239 stop(chart) {
9240 const anims = this._charts.get(chart);
9241 if (!anims || !anims.items.length) {
9242 return;
9243 }
9244 const items = anims.items;
9245 let i = items.length - 1;
9246 for(; i >= 0; --i){
9247 items[i].cancel();
9248 }
9249 anims.items = [];
9250 this._notify(chart, anims, Date.now(), 'complete');
9251 }
9252 remove(chart) {
9253 return this._charts.delete(chart);
9254 }
9255 }
9256 var animator = /* #__PURE__ */ new Animator();
9257
9258 const transparent = 'transparent';
9259 const interpolators = {
9260 boolean (from, to, factor) {
9261 return factor > 0.5 ? to : from;
9262 },
9263 color (from, to, factor) {
9264 const c0 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(from || transparent);
9265 const c1 = c0.valid && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(to || transparent);
9266 return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;
9267 },
9268 number (from, to, factor) {
9269 return from + (to - from) * factor;
9270 }
9271 };
9272 class Animation {
9273 constructor(cfg, target, prop, to){
9274 const currentValue = target[prop];
9275 to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9276 cfg.to,
9277 to,
9278 currentValue,
9279 cfg.from
9280 ]);
9281 const from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9282 cfg.from,
9283 currentValue,
9284 to
9285 ]);
9286 this._active = true;
9287 this._fn = cfg.fn || interpolators[cfg.type || typeof from];
9288 this._easing = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e[cfg.easing] || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e.linear;
9289 this._start = Math.floor(Date.now() + (cfg.delay || 0));
9290 this._duration = this._total = Math.floor(cfg.duration);
9291 this._loop = !!cfg.loop;
9292 this._target = target;
9293 this._prop = prop;
9294 this._from = from;
9295 this._to = to;
9296 this._promises = undefined;
9297 }
9298 active() {
9299 return this._active;
9300 }
9301 update(cfg, to, date) {
9302 if (this._active) {
9303 this._notify(false);
9304 const currentValue = this._target[this._prop];
9305 const elapsed = date - this._start;
9306 const remain = this._duration - elapsed;
9307 this._start = date;
9308 this._duration = Math.floor(Math.max(remain, cfg.duration));
9309 this._total += elapsed;
9310 this._loop = !!cfg.loop;
9311 this._to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9312 cfg.to,
9313 to,
9314 currentValue,
9315 cfg.from
9316 ]);
9317 this._from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
9318 cfg.from,
9319 currentValue,
9320 to
9321 ]);
9322 }
9323 }
9324 cancel() {
9325 if (this._active) {
9326 this.tick(Date.now());
9327 this._active = false;
9328 this._notify(false);
9329 }
9330 }
9331 tick(date) {
9332 const elapsed = date - this._start;
9333 const duration = this._duration;
9334 const prop = this._prop;
9335 const from = this._from;
9336 const loop = this._loop;
9337 const to = this._to;
9338 let factor;
9339 this._active = from !== to && (loop || elapsed < duration);
9340 if (!this._active) {
9341 this._target[prop] = to;
9342 this._notify(true);
9343 return;
9344 }
9345 if (elapsed < 0) {
9346 this._target[prop] = from;
9347 return;
9348 }
9349 factor = elapsed / duration % 2;
9350 factor = loop && factor > 1 ? 2 - factor : factor;
9351 factor = this._easing(Math.min(1, Math.max(0, factor)));
9352 this._target[prop] = this._fn(from, to, factor);
9353 }
9354 wait() {
9355 const promises = this._promises || (this._promises = []);
9356 return new Promise((res, rej)=>{
9357 promises.push({
9358 res,
9359 rej
9360 });
9361 });
9362 }
9363 _notify(resolved) {
9364 const method = resolved ? 'res' : 'rej';
9365 const promises = this._promises || [];
9366 for(let i = 0; i < promises.length; i++){
9367 promises[i][method]();
9368 }
9369 }
9370 }
9371
9372 class Animations {
9373 constructor(chart, config){
9374 this._chart = chart;
9375 this._properties = new Map();
9376 this.configure(config);
9377 }
9378 configure(config) {
9379 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(config)) {
9380 return;
9381 }
9382 const animationOptions = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.animation);
9383 const animatedProps = this._properties;
9384 Object.getOwnPropertyNames(config).forEach((key)=>{
9385 const cfg = config[key];
9386 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(cfg)) {
9387 return;
9388 }
9389 const resolved = {};
9390 for (const option of animationOptions){
9391 resolved[option] = cfg[option];
9392 }
9393 ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(cfg.properties) && cfg.properties || [
9394 key
9395 ]).forEach((prop)=>{
9396 if (prop === key || !animatedProps.has(prop)) {
9397 animatedProps.set(prop, resolved);
9398 }
9399 });
9400 });
9401 }
9402 _animateOptions(target, values) {
9403 const newOptions = values.options;
9404 const options = resolveTargetOptions(target, newOptions);
9405 if (!options) {
9406 return [];
9407 }
9408 const animations = this._createAnimations(options, newOptions);
9409 if (newOptions.$shared) {
9410 awaitAll(target.options.$animations, newOptions).then(()=>{
9411 target.options = newOptions;
9412 }, ()=>{
9413 });
9414 }
9415 return animations;
9416 }
9417 _createAnimations(target, values) {
9418 const animatedProps = this._properties;
9419 const animations = [];
9420 const running = target.$animations || (target.$animations = {});
9421 const props = Object.keys(values);
9422 const date = Date.now();
9423 let i;
9424 for(i = props.length - 1; i >= 0; --i){
9425 const prop = props[i];
9426 if (prop.charAt(0) === '$') {
9427 continue;
9428 }
9429 if (prop === 'options') {
9430 animations.push(...this._animateOptions(target, values));
9431 continue;
9432 }
9433 const value = values[prop];
9434 let animation = running[prop];
9435 const cfg = animatedProps.get(prop);
9436 if (animation) {
9437 if (cfg && animation.active()) {
9438 animation.update(cfg, value, date);
9439 continue;
9440 } else {
9441 animation.cancel();
9442 }
9443 }
9444 if (!cfg || !cfg.duration) {
9445 target[prop] = value;
9446 continue;
9447 }
9448 running[prop] = animation = new Animation(cfg, target, prop, value);
9449 animations.push(animation);
9450 }
9451 return animations;
9452 }
9453 update(target, values) {
9454 if (this._properties.size === 0) {
9455 Object.assign(target, values);
9456 return;
9457 }
9458 const animations = this._createAnimations(target, values);
9459 if (animations.length) {
9460 animator.add(this._chart, animations);
9461 return true;
9462 }
9463 }
9464 }
9465 function awaitAll(animations, properties) {
9466 const running = [];
9467 const keys = Object.keys(properties);
9468 for(let i = 0; i < keys.length; i++){
9469 const anim = animations[keys[i]];
9470 if (anim && anim.active()) {
9471 running.push(anim.wait());
9472 }
9473 }
9474 return Promise.all(running);
9475 }
9476 function resolveTargetOptions(target, newOptions) {
9477 if (!newOptions) {
9478 return;
9479 }
9480 let options = target.options;
9481 if (!options) {
9482 target.options = newOptions;
9483 return;
9484 }
9485 if (options.$shared) {
9486 target.options = options = Object.assign({}, options, {
9487 $shared: false,
9488 $animations: {}
9489 });
9490 }
9491 return options;
9492 }
9493
9494 function scaleClip(scale, allowedOverflow) {
9495 const opts = scale && scale.options || {};
9496 const reverse = opts.reverse;
9497 const min = opts.min === undefined ? allowedOverflow : 0;
9498 const max = opts.max === undefined ? allowedOverflow : 0;
9499 return {
9500 start: reverse ? max : min,
9501 end: reverse ? min : max
9502 };
9503 }
9504 function defaultClip(xScale, yScale, allowedOverflow) {
9505 if (allowedOverflow === false) {
9506 return false;
9507 }
9508 const x = scaleClip(xScale, allowedOverflow);
9509 const y = scaleClip(yScale, allowedOverflow);
9510 return {
9511 top: y.end,
9512 right: x.end,
9513 bottom: y.start,
9514 left: x.start
9515 };
9516 }
9517 function toClip(value) {
9518 let t, r, b, l;
9519 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value)) {
9520 t = value.top;
9521 r = value.right;
9522 b = value.bottom;
9523 l = value.left;
9524 } else {
9525 t = r = b = l = value;
9526 }
9527 return {
9528 top: t,
9529 right: r,
9530 bottom: b,
9531 left: l,
9532 disabled: value === false
9533 };
9534 }
9535 function getSortedDatasetIndices(chart, filterVisible) {
9536 const keys = [];
9537 const metasets = chart._getSortedDatasetMetas(filterVisible);
9538 let i, ilen;
9539 for(i = 0, ilen = metasets.length; i < ilen; ++i){
9540 keys.push(metasets[i].index);
9541 }
9542 return keys;
9543 }
9544 function applyStack(stack, value, dsIndex, options = {}) {
9545 const keys = stack.keys;
9546 const singleMode = options.mode === 'single';
9547 let i, ilen, datasetIndex, otherValue;
9548 if (value === null) {
9549 return;
9550 }
9551 let found = false;
9552 for(i = 0, ilen = keys.length; i < ilen; ++i){
9553 datasetIndex = +keys[i];
9554 if (datasetIndex === dsIndex) {
9555 found = true;
9556 if (options.all) {
9557 continue;
9558 }
9559 break;
9560 }
9561 otherValue = stack.values[datasetIndex];
9562 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))) {
9563 value += otherValue;
9564 }
9565 }
9566 if (!found && !options.all) {
9567 return 0;
9568 }
9569 return value;
9570 }
9571 function convertObjectDataToArray(data, meta) {
9572 const { iScale , vScale } = meta;
9573 const iAxisKey = iScale.axis === 'x' ? 'x' : 'y';
9574 const vAxisKey = vScale.axis === 'x' ? 'x' : 'y';
9575 const keys = Object.keys(data);
9576 const adata = new Array(keys.length);
9577 let i, ilen, key;
9578 for(i = 0, ilen = keys.length; i < ilen; ++i){
9579 key = keys[i];
9580 adata[i] = {
9581 [iAxisKey]: key,
9582 [vAxisKey]: data[key]
9583 };
9584 }
9585 return adata;
9586 }
9587 function isStacked(scale, meta) {
9588 const stacked = scale && scale.options.stacked;
9589 return stacked || stacked === undefined && meta.stack !== undefined;
9590 }
9591 function getStackKey(indexScale, valueScale, meta) {
9592 return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
9593 }
9594 function getUserBounds(scale) {
9595 const { min , max , minDefined , maxDefined } = scale.getUserBounds();
9596 return {
9597 min: minDefined ? min : Number.NEGATIVE_INFINITY,
9598 max: maxDefined ? max : Number.POSITIVE_INFINITY
9599 };
9600 }
9601 function getOrCreateStack(stacks, stackKey, indexValue) {
9602 const subStack = stacks[stackKey] || (stacks[stackKey] = {});
9603 return subStack[indexValue] || (subStack[indexValue] = {});
9604 }
9605 function getLastIndexInStack(stack, vScale, positive, type) {
9606 for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){
9607 const value = stack[meta.index];
9608 if (positive && value > 0 || !positive && value < 0) {
9609 return meta.index;
9610 }
9611 }
9612 return null;
9613 }
9614 function updateStacks(controller, parsed) {
9615 const { chart , _cachedMeta: meta } = controller;
9616 const stacks = chart._stacks || (chart._stacks = {});
9617 const { iScale , vScale , index: datasetIndex } = meta;
9618 const iAxis = iScale.axis;
9619 const vAxis = vScale.axis;
9620 const key = getStackKey(iScale, vScale, meta);
9621 const ilen = parsed.length;
9622 let stack;
9623 for(let i = 0; i < ilen; ++i){
9624 const item = parsed[i];
9625 const { [iAxis]: index , [vAxis]: value } = item;
9626 const itemStacks = item._stacks || (item._stacks = {});
9627 stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
9628 stack[datasetIndex] = value;
9629 stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
9630 stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
9631 const visualValues = stack._visualValues || (stack._visualValues = {});
9632 visualValues[datasetIndex] = value;
9633 }
9634 }
9635 function getFirstScaleId(chart, axis) {
9636 const scales = chart.scales;
9637 return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift();
9638 }
9639 function createDatasetContext(parent, index) {
9640 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9641 active: false,
9642 dataset: undefined,
9643 datasetIndex: index,
9644 index,
9645 mode: 'default',
9646 type: 'dataset'
9647 });
9648 }
9649 function createDataContext(parent, index, element) {
9650 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
9651 active: false,
9652 dataIndex: index,
9653 parsed: undefined,
9654 raw: undefined,
9655 element,
9656 index,
9657 mode: 'default',
9658 type: 'data'
9659 });
9660 }
9661 function clearStacks(meta, items) {
9662 const datasetIndex = meta.controller.index;
9663 const axis = meta.vScale && meta.vScale.axis;
9664 if (!axis) {
9665 return;
9666 }
9667 items = items || meta._parsed;
9668 for (const parsed of items){
9669 const stacks = parsed._stacks;
9670 if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {
9671 return;
9672 }
9673 delete stacks[axis][datasetIndex];
9674 if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) {
9675 delete stacks[axis]._visualValues[datasetIndex];
9676 }
9677 }
9678 }
9679 const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none';
9680 const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached);
9681 const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && {
9682 keys: getSortedDatasetIndices(chart, true),
9683 values: null
9684 };
9685 class DatasetController {
9686 static defaults = {};
9687 static datasetElementType = null;
9688 static dataElementType = null;
9689 constructor(chart, datasetIndex){
9690 this.chart = chart;
9691 this._ctx = chart.ctx;
9692 this.index = datasetIndex;
9693 this._cachedDataOpts = {};
9694 this._cachedMeta = this.getMeta();
9695 this._type = this._cachedMeta.type;
9696 this.options = undefined;
9697 this._parsing = false;
9698 this._data = undefined;
9699 this._objectData = undefined;
9700 this._sharedOptions = undefined;
9701 this._drawStart = undefined;
9702 this._drawCount = undefined;
9703 this.enableOptionSharing = false;
9704 this.supportsDecimation = false;
9705 this.$context = undefined;
9706 this._syncList = [];
9707 this.datasetElementType = new.target.datasetElementType;
9708 this.dataElementType = new.target.dataElementType;
9709 this.initialize();
9710 }
9711 initialize() {
9712 const meta = this._cachedMeta;
9713 this.configure();
9714 this.linkScales();
9715 meta._stacked = isStacked(meta.vScale, meta);
9716 this.addElements();
9717 if (this.options.fill && !this.chart.isPluginEnabled('filler')) {
9718 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");
9719 }
9720 }
9721 updateIndex(datasetIndex) {
9722 if (this.index !== datasetIndex) {
9723 clearStacks(this._cachedMeta);
9724 }
9725 this.index = datasetIndex;
9726 }
9727 linkScales() {
9728 const chart = this.chart;
9729 const meta = this._cachedMeta;
9730 const dataset = this.getDataset();
9731 const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y;
9732 const xid = meta.xAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.xAxisID, getFirstScaleId(chart, 'x'));
9733 const yid = meta.yAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.yAxisID, getFirstScaleId(chart, 'y'));
9734 const rid = meta.rAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.rAxisID, getFirstScaleId(chart, 'r'));
9735 const indexAxis = meta.indexAxis;
9736 const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
9737 const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
9738 meta.xScale = this.getScaleForId(xid);
9739 meta.yScale = this.getScaleForId(yid);
9740 meta.rScale = this.getScaleForId(rid);
9741 meta.iScale = this.getScaleForId(iid);
9742 meta.vScale = this.getScaleForId(vid);
9743 }
9744 getDataset() {
9745 return this.chart.data.datasets[this.index];
9746 }
9747 getMeta() {
9748 return this.chart.getDatasetMeta(this.index);
9749 }
9750 getScaleForId(scaleID) {
9751 return this.chart.scales[scaleID];
9752 }
9753 _getOtherScale(scale) {
9754 const meta = this._cachedMeta;
9755 return scale === meta.iScale ? meta.vScale : meta.iScale;
9756 }
9757 reset() {
9758 this._update('reset');
9759 }
9760 _destroy() {
9761 const meta = this._cachedMeta;
9762 if (this._data) {
9763 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(this._data, this);
9764 }
9765 if (meta._stacked) {
9766 clearStacks(meta);
9767 }
9768 }
9769 _dataCheck() {
9770 const dataset = this.getDataset();
9771 const data = dataset.data || (dataset.data = []);
9772 const _data = this._data;
9773 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data)) {
9774 const meta = this._cachedMeta;
9775 this._data = convertObjectDataToArray(data, meta);
9776 } else if (_data !== data) {
9777 if (_data) {
9778 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(_data, this);
9779 const meta = this._cachedMeta;
9780 clearStacks(meta);
9781 meta._parsed = [];
9782 }
9783 if (data && Object.isExtensible(data)) {
9784 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.l)(data, this);
9785 }
9786 this._syncList = [];
9787 this._data = data;
9788 }
9789 }
9790 addElements() {
9791 const meta = this._cachedMeta;
9792 this._dataCheck();
9793 if (this.datasetElementType) {
9794 meta.dataset = new this.datasetElementType();
9795 }
9796 }
9797 buildOrUpdateElements(resetNewElements) {
9798 const meta = this._cachedMeta;
9799 const dataset = this.getDataset();
9800 let stackChanged = false;
9801 this._dataCheck();
9802 const oldStacked = meta._stacked;
9803 meta._stacked = isStacked(meta.vScale, meta);
9804 if (meta.stack !== dataset.stack) {
9805 stackChanged = true;
9806 clearStacks(meta);
9807 meta.stack = dataset.stack;
9808 }
9809 this._resyncElements(resetNewElements);
9810 if (stackChanged || oldStacked !== meta._stacked) {
9811 updateStacks(this, meta._parsed);
9812 meta._stacked = isStacked(meta.vScale, meta);
9813 }
9814 }
9815 configure() {
9816 const config = this.chart.config;
9817 const scopeKeys = config.datasetScopeKeys(this._type);
9818 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
9819 this.options = config.createResolver(scopes, this.getContext());
9820 this._parsing = this.options.parsing;
9821 this._cachedDataOpts = {};
9822 }
9823 parse(start, count) {
9824 const { _cachedMeta: meta , _data: data } = this;
9825 const { iScale , _stacked } = meta;
9826 const iAxis = iScale.axis;
9827 let sorted = start === 0 && count === data.length ? true : meta._sorted;
9828 let prev = start > 0 && meta._parsed[start - 1];
9829 let i, cur, parsed;
9830 if (this._parsing === false) {
9831 meta._parsed = data;
9832 meta._sorted = true;
9833 parsed = data;
9834 } else {
9835 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(data[start])) {
9836 parsed = this.parseArrayData(meta, data, start, count);
9837 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
9838 parsed = this.parseObjectData(meta, data, start, count);
9839 } else {
9840 parsed = this.parsePrimitiveData(meta, data, start, count);
9841 }
9842 const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];
9843 for(i = 0; i < count; ++i){
9844 meta._parsed[i + start] = cur = parsed[i];
9845 if (sorted) {
9846 if (isNotInOrderComparedToPrev()) {
9847 sorted = false;
9848 }
9849 prev = cur;
9850 }
9851 }
9852 meta._sorted = sorted;
9853 }
9854 if (_stacked) {
9855 updateStacks(this, parsed);
9856 }
9857 }
9858 parsePrimitiveData(meta, data, start, count) {
9859 const { iScale , vScale } = meta;
9860 const iAxis = iScale.axis;
9861 const vAxis = vScale.axis;
9862 const labels = iScale.getLabels();
9863 const singleScale = iScale === vScale;
9864 const parsed = new Array(count);
9865 let i, ilen, index;
9866 for(i = 0, ilen = count; i < ilen; ++i){
9867 index = i + start;
9868 parsed[i] = {
9869 [iAxis]: singleScale || iScale.parse(labels[index], index),
9870 [vAxis]: vScale.parse(data[index], index)
9871 };
9872 }
9873 return parsed;
9874 }
9875 parseArrayData(meta, data, start, count) {
9876 const { xScale , yScale } = meta;
9877 const parsed = new Array(count);
9878 let i, ilen, index, item;
9879 for(i = 0, ilen = count; i < ilen; ++i){
9880 index = i + start;
9881 item = data[index];
9882 parsed[i] = {
9883 x: xScale.parse(item[0], index),
9884 y: yScale.parse(item[1], index)
9885 };
9886 }
9887 return parsed;
9888 }
9889 parseObjectData(meta, data, start, count) {
9890 const { xScale , yScale } = meta;
9891 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
9892 const parsed = new Array(count);
9893 let i, ilen, index, item;
9894 for(i = 0, ilen = count; i < ilen; ++i){
9895 index = i + start;
9896 item = data[index];
9897 parsed[i] = {
9898 x: xScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, xAxisKey), index),
9899 y: yScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, yAxisKey), index)
9900 };
9901 }
9902 return parsed;
9903 }
9904 getParsed(index) {
9905 return this._cachedMeta._parsed[index];
9906 }
9907 getDataElement(index) {
9908 return this._cachedMeta.data[index];
9909 }
9910 applyStack(scale, parsed, mode) {
9911 const chart = this.chart;
9912 const meta = this._cachedMeta;
9913 const value = parsed[scale.axis];
9914 const stack = {
9915 keys: getSortedDatasetIndices(chart, true),
9916 values: parsed._stacks[scale.axis]._visualValues
9917 };
9918 return applyStack(stack, value, meta.index, {
9919 mode
9920 });
9921 }
9922 updateRangeFromParsed(range, scale, parsed, stack) {
9923 const parsedValue = parsed[scale.axis];
9924 let value = parsedValue === null ? NaN : parsedValue;
9925 const values = stack && parsed._stacks[scale.axis];
9926 if (stack && values) {
9927 stack.values = values;
9928 value = applyStack(stack, parsedValue, this._cachedMeta.index);
9929 }
9930 range.min = Math.min(range.min, value);
9931 range.max = Math.max(range.max, value);
9932 }
9933 getMinMax(scale, canStack) {
9934 const meta = this._cachedMeta;
9935 const _parsed = meta._parsed;
9936 const sorted = meta._sorted && scale === meta.iScale;
9937 const ilen = _parsed.length;
9938 const otherScale = this._getOtherScale(scale);
9939 const stack = createStack(canStack, meta, this.chart);
9940 const range = {
9941 min: Number.POSITIVE_INFINITY,
9942 max: Number.NEGATIVE_INFINITY
9943 };
9944 const { min: otherMin , max: otherMax } = getUserBounds(otherScale);
9945 let i, parsed;
9946 function _skip() {
9947 parsed = _parsed[i];
9948 const otherValue = parsed[otherScale.axis];
9949 return !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
9950 }
9951 for(i = 0; i < ilen; ++i){
9952 if (_skip()) {
9953 continue;
9954 }
9955 this.updateRangeFromParsed(range, scale, parsed, stack);
9956 if (sorted) {
9957 break;
9958 }
9959 }
9960 if (sorted) {
9961 for(i = ilen - 1; i >= 0; --i){
9962 if (_skip()) {
9963 continue;
9964 }
9965 this.updateRangeFromParsed(range, scale, parsed, stack);
9966 break;
9967 }
9968 }
9969 return range;
9970 }
9971 getAllParsedValues(scale) {
9972 const parsed = this._cachedMeta._parsed;
9973 const values = [];
9974 let i, ilen, value;
9975 for(i = 0, ilen = parsed.length; i < ilen; ++i){
9976 value = parsed[i][scale.axis];
9977 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
9978 values.push(value);
9979 }
9980 }
9981 return values;
9982 }
9983 getMaxOverflow() {
9984 return false;
9985 }
9986 getLabelAndValue(index) {
9987 const meta = this._cachedMeta;
9988 const iScale = meta.iScale;
9989 const vScale = meta.vScale;
9990 const parsed = this.getParsed(index);
9991 return {
9992 label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
9993 value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
9994 };
9995 }
9996 _update(mode) {
9997 const meta = this._cachedMeta;
9998 this.update(mode || 'default');
9999 meta._clip = toClip((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
10000 }
10001 update(mode) {}
10002 draw() {
10003 const ctx = this._ctx;
10004 const chart = this.chart;
10005 const meta = this._cachedMeta;
10006 const elements = meta.data || [];
10007 const area = chart.chartArea;
10008 const active = [];
10009 const start = this._drawStart || 0;
10010 const count = this._drawCount || elements.length - start;
10011 const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
10012 let i;
10013 if (meta.dataset) {
10014 meta.dataset.draw(ctx, area, start, count);
10015 }
10016 for(i = start; i < start + count; ++i){
10017 const element = elements[i];
10018 if (element.hidden) {
10019 continue;
10020 }
10021 if (element.active && drawActiveElementsOnTop) {
10022 active.push(element);
10023 } else {
10024 element.draw(ctx, area);
10025 }
10026 }
10027 for(i = 0; i < active.length; ++i){
10028 active[i].draw(ctx, area);
10029 }
10030 }
10031 getStyle(index, active) {
10032 const mode = active ? 'active' : 'default';
10033 return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);
10034 }
10035 getContext(index, active, mode) {
10036 const dataset = this.getDataset();
10037 let context;
10038 if (index >= 0 && index < this._cachedMeta.data.length) {
10039 const element = this._cachedMeta.data[index];
10040 context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));
10041 context.parsed = this.getParsed(index);
10042 context.raw = dataset.data[index];
10043 context.index = context.dataIndex = index;
10044 } else {
10045 context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));
10046 context.dataset = dataset;
10047 context.index = context.datasetIndex = this.index;
10048 }
10049 context.active = !!active;
10050 context.mode = mode;
10051 return context;
10052 }
10053 resolveDatasetElementOptions(mode) {
10054 return this._resolveElementOptions(this.datasetElementType.id, mode);
10055 }
10056 resolveDataElementOptions(index, mode) {
10057 return this._resolveElementOptions(this.dataElementType.id, mode, index);
10058 }
10059 _resolveElementOptions(elementType, mode = 'default', index) {
10060 const active = mode === 'active';
10061 const cache = this._cachedDataOpts;
10062 const cacheKey = elementType + '-' + mode;
10063 const cached = cache[cacheKey];
10064 const sharing = this.enableOptionSharing && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(index);
10065 if (cached) {
10066 return cloneIfNotShared(cached, sharing);
10067 }
10068 const config = this.chart.config;
10069 const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
10070 const prefixes = active ? [
10071 `${elementType}Hover`,
10072 'hover',
10073 elementType,
10074 ''
10075 ] : [
10076 elementType,
10077 ''
10078 ];
10079 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
10080 const names = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.elements[elementType]);
10081 const context = ()=>this.getContext(index, active, mode);
10082 const values = config.resolveNamedOptions(scopes, names, context, prefixes);
10083 if (values.$shared) {
10084 values.$shared = sharing;
10085 cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
10086 }
10087 return values;
10088 }
10089 _resolveAnimations(index, transition, active) {
10090 const chart = this.chart;
10091 const cache = this._cachedDataOpts;
10092 const cacheKey = `animation-${transition}`;
10093 const cached = cache[cacheKey];
10094 if (cached) {
10095 return cached;
10096 }
10097 let options;
10098 if (chart.options.animation !== false) {
10099 const config = this.chart.config;
10100 const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
10101 const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
10102 options = config.createResolver(scopes, this.getContext(index, active, transition));
10103 }
10104 const animations = new Animations(chart, options && options.animations);
10105 if (options && options._cacheable) {
10106 cache[cacheKey] = Object.freeze(animations);
10107 }
10108 return animations;
10109 }
10110 getSharedOptions(options) {
10111 if (!options.$shared) {
10112 return;
10113 }
10114 return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
10115 }
10116 includeOptions(mode, sharedOptions) {
10117 return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
10118 }
10119 _getSharedOptions(start, mode) {
10120 const firstOpts = this.resolveDataElementOptions(start, mode);
10121 const previouslySharedOptions = this._sharedOptions;
10122 const sharedOptions = this.getSharedOptions(firstOpts);
10123 const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;
10124 this.updateSharedOptions(sharedOptions, mode, firstOpts);
10125 return {
10126 sharedOptions,
10127 includeOptions
10128 };
10129 }
10130 updateElement(element, index, properties, mode) {
10131 if (isDirectUpdateMode(mode)) {
10132 Object.assign(element, properties);
10133 } else {
10134 this._resolveAnimations(index, mode).update(element, properties);
10135 }
10136 }
10137 updateSharedOptions(sharedOptions, mode, newOptions) {
10138 if (sharedOptions && !isDirectUpdateMode(mode)) {
10139 this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);
10140 }
10141 }
10142 _setStyle(element, index, mode, active) {
10143 element.active = active;
10144 const options = this.getStyle(index, active);
10145 this._resolveAnimations(index, mode, active).update(element, {
10146 options: !active && this.getSharedOptions(options) || options
10147 });
10148 }
10149 removeHoverStyle(element, datasetIndex, index) {
10150 this._setStyle(element, index, 'active', false);
10151 }
10152 setHoverStyle(element, datasetIndex, index) {
10153 this._setStyle(element, index, 'active', true);
10154 }
10155 _removeDatasetHoverStyle() {
10156 const element = this._cachedMeta.dataset;
10157 if (element) {
10158 this._setStyle(element, undefined, 'active', false);
10159 }
10160 }
10161 _setDatasetHoverStyle() {
10162 const element = this._cachedMeta.dataset;
10163 if (element) {
10164 this._setStyle(element, undefined, 'active', true);
10165 }
10166 }
10167 _resyncElements(resetNewElements) {
10168 const data = this._data;
10169 const elements = this._cachedMeta.data;
10170 for (const [method, arg1, arg2] of this._syncList){
10171 this[method](arg1, arg2);
10172 }
10173 this._syncList = [];
10174 const numMeta = elements.length;
10175 const numData = data.length;
10176 const count = Math.min(numData, numMeta);
10177 if (count) {
10178 this.parse(0, count);
10179 }
10180 if (numData > numMeta) {
10181 this._insertElements(numMeta, numData - numMeta, resetNewElements);
10182 } else if (numData < numMeta) {
10183 this._removeElements(numData, numMeta - numData);
10184 }
10185 }
10186 _insertElements(start, count, resetNewElements = true) {
10187 const meta = this._cachedMeta;
10188 const data = meta.data;
10189 const end = start + count;
10190 let i;
10191 const move = (arr)=>{
10192 arr.length += count;
10193 for(i = arr.length - 1; i >= end; i--){
10194 arr[i] = arr[i - count];
10195 }
10196 };
10197 move(data);
10198 for(i = start; i < end; ++i){
10199 data[i] = new this.dataElementType();
10200 }
10201 if (this._parsing) {
10202 move(meta._parsed);
10203 }
10204 this.parse(start, count);
10205 if (resetNewElements) {
10206 this.updateElements(data, start, count, 'reset');
10207 }
10208 }
10209 updateElements(element, start, count, mode) {}
10210 _removeElements(start, count) {
10211 const meta = this._cachedMeta;
10212 if (this._parsing) {
10213 const removed = meta._parsed.splice(start, count);
10214 if (meta._stacked) {
10215 clearStacks(meta, removed);
10216 }
10217 }
10218 meta.data.splice(start, count);
10219 }
10220 _sync(args) {
10221 if (this._parsing) {
10222 this._syncList.push(args);
10223 } else {
10224 const [method, arg1, arg2] = args;
10225 this[method](arg1, arg2);
10226 }
10227 this.chart._dataChanges.push([
10228 this.index,
10229 ...args
10230 ]);
10231 }
10232 _onDataPush() {
10233 const count = arguments.length;
10234 this._sync([
10235 '_insertElements',
10236 this.getDataset().data.length - count,
10237 count
10238 ]);
10239 }
10240 _onDataPop() {
10241 this._sync([
10242 '_removeElements',
10243 this._cachedMeta.data.length - 1,
10244 1
10245 ]);
10246 }
10247 _onDataShift() {
10248 this._sync([
10249 '_removeElements',
10250 0,
10251 1
10252 ]);
10253 }
10254 _onDataSplice(start, count) {
10255 if (count) {
10256 this._sync([
10257 '_removeElements',
10258 start,
10259 count
10260 ]);
10261 }
10262 const newCount = arguments.length - 2;
10263 if (newCount) {
10264 this._sync([
10265 '_insertElements',
10266 start,
10267 newCount
10268 ]);
10269 }
10270 }
10271 _onDataUnshift() {
10272 this._sync([
10273 '_insertElements',
10274 0,
10275 arguments.length
10276 ]);
10277 }
10278 }
10279
10280 function getAllScaleValues(scale, type) {
10281 if (!scale._cache.$bar) {
10282 const visibleMetas = scale.getMatchingVisibleMetas(type);
10283 let values = [];
10284 for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){
10285 values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));
10286 }
10287 scale._cache.$bar = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort((a, b)=>a - b));
10288 }
10289 return scale._cache.$bar;
10290 }
10291 function computeMinSampleSize(meta) {
10292 const scale = meta.iScale;
10293 const values = getAllScaleValues(scale, meta.type);
10294 let min = scale._length;
10295 let i, ilen, curr, prev;
10296 const updateMinAndPrev = ()=>{
10297 if (curr === 32767 || curr === -32768) {
10298 return;
10299 }
10300 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(prev)) {
10301 min = Math.min(min, Math.abs(curr - prev) || min);
10302 }
10303 prev = curr;
10304 };
10305 for(i = 0, ilen = values.length; i < ilen; ++i){
10306 curr = scale.getPixelForValue(values[i]);
10307 updateMinAndPrev();
10308 }
10309 prev = undefined;
10310 for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){
10311 curr = scale.getPixelForTick(i);
10312 updateMinAndPrev();
10313 }
10314 return min;
10315 }
10316 function computeFitCategoryTraits(index, ruler, options, stackCount) {
10317 const thickness = options.barThickness;
10318 let size, ratio;
10319 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(thickness)) {
10320 size = ruler.min * options.categoryPercentage;
10321 ratio = options.barPercentage;
10322 } else {
10323 size = thickness * stackCount;
10324 ratio = 1;
10325 }
10326 return {
10327 chunk: size / stackCount,
10328 ratio,
10329 start: ruler.pixels[index] - size / 2
10330 };
10331 }
10332 function computeFlexCategoryTraits(index, ruler, options, stackCount) {
10333 const pixels = ruler.pixels;
10334 const curr = pixels[index];
10335 let prev = index > 0 ? pixels[index - 1] : null;
10336 let next = index < pixels.length - 1 ? pixels[index + 1] : null;
10337 const percent = options.categoryPercentage;
10338 if (prev === null) {
10339 prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
10340 }
10341 if (next === null) {
10342 next = curr + curr - prev;
10343 }
10344 const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
10345 const size = Math.abs(next - prev) / 2 * percent;
10346 return {
10347 chunk: size / stackCount,
10348 ratio: options.barPercentage,
10349 start
10350 };
10351 }
10352 function parseFloatBar(entry, item, vScale, i) {
10353 const startValue = vScale.parse(entry[0], i);
10354 const endValue = vScale.parse(entry[1], i);
10355 const min = Math.min(startValue, endValue);
10356 const max = Math.max(startValue, endValue);
10357 let barStart = min;
10358 let barEnd = max;
10359 if (Math.abs(min) > Math.abs(max)) {
10360 barStart = max;
10361 barEnd = min;
10362 }
10363 item[vScale.axis] = barEnd;
10364 item._custom = {
10365 barStart,
10366 barEnd,
10367 start: startValue,
10368 end: endValue,
10369 min,
10370 max
10371 };
10372 }
10373 function parseValue(entry, item, vScale, i) {
10374 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(entry)) {
10375 parseFloatBar(entry, item, vScale, i);
10376 } else {
10377 item[vScale.axis] = vScale.parse(entry, i);
10378 }
10379 return item;
10380 }
10381 function parseArrayOrPrimitive(meta, data, start, count) {
10382 const iScale = meta.iScale;
10383 const vScale = meta.vScale;
10384 const labels = iScale.getLabels();
10385 const singleScale = iScale === vScale;
10386 const parsed = [];
10387 let i, ilen, item, entry;
10388 for(i = start, ilen = start + count; i < ilen; ++i){
10389 entry = data[i];
10390 item = {};
10391 item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
10392 parsed.push(parseValue(entry, item, vScale, i));
10393 }
10394 return parsed;
10395 }
10396 function isFloatBar(custom) {
10397 return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
10398 }
10399 function barSign(size, vScale, actualBase) {
10400 if (size !== 0) {
10401 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size);
10402 }
10403 return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
10404 }
10405 function borderProps(properties) {
10406 let reverse, start, end, top, bottom;
10407 if (properties.horizontal) {
10408 reverse = properties.base > properties.x;
10409 start = 'left';
10410 end = 'right';
10411 } else {
10412 reverse = properties.base < properties.y;
10413 start = 'bottom';
10414 end = 'top';
10415 }
10416 if (reverse) {
10417 top = 'end';
10418 bottom = 'start';
10419 } else {
10420 top = 'start';
10421 bottom = 'end';
10422 }
10423 return {
10424 start,
10425 end,
10426 reverse,
10427 top,
10428 bottom
10429 };
10430 }
10431 function setBorderSkipped(properties, options, stack, index) {
10432 let edge = options.borderSkipped;
10433 const res = {};
10434 if (!edge) {
10435 properties.borderSkipped = res;
10436 return;
10437 }
10438 if (edge === true) {
10439 properties.borderSkipped = {
10440 top: true,
10441 right: true,
10442 bottom: true,
10443 left: true
10444 };
10445 return;
10446 }
10447 const { start , end , reverse , top , bottom } = borderProps(properties);
10448 if (edge === 'middle' && stack) {
10449 properties.enableBorderRadius = true;
10450 if ((stack._top || 0) === index) {
10451 edge = top;
10452 } else if ((stack._bottom || 0) === index) {
10453 edge = bottom;
10454 } else {
10455 res[parseEdge(bottom, start, end, reverse)] = true;
10456 edge = top;
10457 }
10458 }
10459 res[parseEdge(edge, start, end, reverse)] = true;
10460 properties.borderSkipped = res;
10461 }
10462 function parseEdge(edge, a, b, reverse) {
10463 if (reverse) {
10464 edge = swap(edge, a, b);
10465 edge = startEnd(edge, b, a);
10466 } else {
10467 edge = startEnd(edge, a, b);
10468 }
10469 return edge;
10470 }
10471 function swap(orig, v1, v2) {
10472 return orig === v1 ? v2 : orig === v2 ? v1 : orig;
10473 }
10474 function startEnd(v, start, end) {
10475 return v === 'start' ? start : v === 'end' ? end : v;
10476 }
10477 function setInflateAmount(properties, { inflateAmount }, ratio) {
10478 properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount;
10479 }
10480 class BarController extends DatasetController {
10481 static id = 'bar';
10482 static defaults = {
10483 datasetElementType: false,
10484 dataElementType: 'bar',
10485 categoryPercentage: 0.8,
10486 barPercentage: 0.9,
10487 grouped: true,
10488 animations: {
10489 numbers: {
10490 type: 'number',
10491 properties: [
10492 'x',
10493 'y',
10494 'base',
10495 'width',
10496 'height'
10497 ]
10498 }
10499 }
10500 };
10501 static overrides = {
10502 scales: {
10503 _index_: {
10504 type: 'category',
10505 offset: true,
10506 grid: {
10507 offset: true
10508 }
10509 },
10510 _value_: {
10511 type: 'linear',
10512 beginAtZero: true
10513 }
10514 }
10515 };
10516 parsePrimitiveData(meta, data, start, count) {
10517 return parseArrayOrPrimitive(meta, data, start, count);
10518 }
10519 parseArrayData(meta, data, start, count) {
10520 return parseArrayOrPrimitive(meta, data, start, count);
10521 }
10522 parseObjectData(meta, data, start, count) {
10523 const { iScale , vScale } = meta;
10524 const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;
10525 const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
10526 const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
10527 const parsed = [];
10528 let i, ilen, item, obj;
10529 for(i = start, ilen = start + count; i < ilen; ++i){
10530 obj = data[i];
10531 item = {};
10532 item[iScale.axis] = iScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, iAxisKey), i);
10533 parsed.push(parseValue((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, vAxisKey), item, vScale, i));
10534 }
10535 return parsed;
10536 }
10537 updateRangeFromParsed(range, scale, parsed, stack) {
10538 super.updateRangeFromParsed(range, scale, parsed, stack);
10539 const custom = parsed._custom;
10540 if (custom && scale === this._cachedMeta.vScale) {
10541 range.min = Math.min(range.min, custom.min);
10542 range.max = Math.max(range.max, custom.max);
10543 }
10544 }
10545 getMaxOverflow() {
10546 return 0;
10547 }
10548 getLabelAndValue(index) {
10549 const meta = this._cachedMeta;
10550 const { iScale , vScale } = meta;
10551 const parsed = this.getParsed(index);
10552 const custom = parsed._custom;
10553 const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]);
10554 return {
10555 label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
10556 value
10557 };
10558 }
10559 initialize() {
10560 this.enableOptionSharing = true;
10561 super.initialize();
10562 const meta = this._cachedMeta;
10563 meta.stack = this.getDataset().stack;
10564 }
10565 update(mode) {
10566 const meta = this._cachedMeta;
10567 this.updateElements(meta.data, 0, meta.data.length, mode);
10568 }
10569 updateElements(bars, start, count, mode) {
10570 const reset = mode === 'reset';
10571 const { index , _cachedMeta: { vScale } } = this;
10572 const base = vScale.getBasePixel();
10573 const horizontal = vScale.isHorizontal();
10574 const ruler = this._getRuler();
10575 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10576 for(let i = start; i < start + count; i++){
10577 const parsed = this.getParsed(i);
10578 const vpixels = reset || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vScale.axis]) ? {
10579 base,
10580 head: base
10581 } : this._calculateBarValuePixels(i);
10582 const ipixels = this._calculateBarIndexPixels(i, ruler);
10583 const stack = (parsed._stacks || {})[vScale.axis];
10584 const properties = {
10585 horizontal,
10586 base: vpixels.base,
10587 enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,
10588 x: horizontal ? vpixels.head : ipixels.center,
10589 y: horizontal ? ipixels.center : vpixels.head,
10590 height: horizontal ? ipixels.size : Math.abs(vpixels.size),
10591 width: horizontal ? Math.abs(vpixels.size) : ipixels.size
10592 };
10593 if (includeOptions) {
10594 properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);
10595 }
10596 const options = properties.options || bars[i].options;
10597 setBorderSkipped(properties, options, stack, index);
10598 setInflateAmount(properties, options, ruler.ratio);
10599 this.updateElement(bars[i], i, properties, mode);
10600 }
10601 }
10602 _getStacks(last, dataIndex) {
10603 const { iScale } = this._cachedMeta;
10604 const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped);
10605 const stacked = iScale.options.stacked;
10606 const stacks = [];
10607 const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);
10608 const iScaleValue = currentParsed && currentParsed[iScale.axis];
10609 const skipNull = (meta)=>{
10610 const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue);
10611 const val = parsed && parsed[meta.vScale.axis];
10612 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(val) || isNaN(val)) {
10613 return true;
10614 }
10615 };
10616 for (const meta of metasets){
10617 if (dataIndex !== undefined && skipNull(meta)) {
10618 continue;
10619 }
10620 if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) {
10621 stacks.push(meta.stack);
10622 }
10623 if (meta.index === last) {
10624 break;
10625 }
10626 }
10627 if (!stacks.length) {
10628 stacks.push(undefined);
10629 }
10630 return stacks;
10631 }
10632 _getStackCount(index) {
10633 return this._getStacks(undefined, index).length;
10634 }
10635 _getAxisCount() {
10636 return this._getAxis().length;
10637 }
10638 getFirstScaleIdForIndexAxis() {
10639 const scales = this.chart.scales;
10640 const indexScaleId = this.chart.options.indexAxis;
10641 return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift();
10642 }
10643 _getAxis() {
10644 const axis = {};
10645 const firstScaleAxisId = this.getFirstScaleIdForIndexAxis();
10646 for (const dataset of this.chart.data.datasets){
10647 axis[(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true;
10648 }
10649 return Object.keys(axis);
10650 }
10651 _getStackIndex(datasetIndex, name, dataIndex) {
10652 const stacks = this._getStacks(datasetIndex, dataIndex);
10653 const index = name !== undefined ? stacks.indexOf(name) : -1;
10654 return index === -1 ? stacks.length - 1 : index;
10655 }
10656 _getRuler() {
10657 const opts = this.options;
10658 const meta = this._cachedMeta;
10659 const iScale = meta.iScale;
10660 const pixels = [];
10661 let i, ilen;
10662 for(i = 0, ilen = meta.data.length; i < ilen; ++i){
10663 pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));
10664 }
10665 const barThickness = opts.barThickness;
10666 const min = barThickness || computeMinSampleSize(meta);
10667 return {
10668 min,
10669 pixels,
10670 start: iScale._startPixel,
10671 end: iScale._endPixel,
10672 stackCount: this._getStackCount(),
10673 scale: iScale,
10674 grouped: opts.grouped,
10675 ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
10676 };
10677 }
10678 _calculateBarValuePixels(index) {
10679 const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this;
10680 const actualBase = baseValue || 0;
10681 const parsed = this.getParsed(index);
10682 const custom = parsed._custom;
10683 const floating = isFloatBar(custom);
10684 let value = parsed[vScale.axis];
10685 let start = 0;
10686 let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
10687 let head, size;
10688 if (length !== value) {
10689 start = length - value;
10690 length = value;
10691 }
10692 if (floating) {
10693 value = custom.barStart;
10694 length = custom.barEnd - custom.barStart;
10695 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)) {
10696 start = 0;
10697 }
10698 start += value;
10699 }
10700 const startValue = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(baseValue) && !floating ? baseValue : start;
10701 let base = vScale.getPixelForValue(startValue);
10702 if (this.chart.getDataVisibility(index)) {
10703 head = vScale.getPixelForValue(start + length);
10704 } else {
10705 head = base;
10706 }
10707 size = head - base;
10708 if (Math.abs(size) < minBarLength) {
10709 size = barSign(size, vScale, actualBase) * minBarLength;
10710 if (value === actualBase) {
10711 base -= size / 2;
10712 }
10713 const startPixel = vScale.getPixelForDecimal(0);
10714 const endPixel = vScale.getPixelForDecimal(1);
10715 const min = Math.min(startPixel, endPixel);
10716 const max = Math.max(startPixel, endPixel);
10717 base = Math.max(Math.min(base, max), min);
10718 head = base + size;
10719 if (_stacked && !floating) {
10720 parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);
10721 }
10722 }
10723 if (base === vScale.getPixelForValue(actualBase)) {
10724 const halfGrid = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size) * vScale.getLineWidthForValue(actualBase) / 2;
10725 base += halfGrid;
10726 size -= halfGrid;
10727 }
10728 return {
10729 size,
10730 base,
10731 head,
10732 center: head + size / 2
10733 };
10734 }
10735 _calculateBarIndexPixels(index, ruler) {
10736 const scale = ruler.scale;
10737 const options = this.options;
10738 const skipNull = options.skipNull;
10739 const maxBarThickness = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.maxBarThickness, Infinity);
10740 let center, size;
10741 const axisCount = this._getAxisCount();
10742 if (ruler.grouped) {
10743 const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
10744 const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount);
10745 const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID;
10746 const axisNumber = this._getAxis().indexOf((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(axisID, this.getFirstScaleIdForIndexAxis()));
10747 const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber;
10748 center = range.start + range.chunk * stackIndex + range.chunk / 2;
10749 size = Math.min(maxBarThickness, range.chunk * range.ratio);
10750 } else {
10751 center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
10752 size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
10753 }
10754 return {
10755 base: center - size / 2,
10756 head: center + size / 2,
10757 center,
10758 size
10759 };
10760 }
10761 draw() {
10762 const meta = this._cachedMeta;
10763 const vScale = meta.vScale;
10764 const rects = meta.data;
10765 const ilen = rects.length;
10766 let i = 0;
10767 for(; i < ilen; ++i){
10768 if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) {
10769 rects[i].draw(this._ctx);
10770 }
10771 }
10772 }
10773 }
10774
10775 class BubbleController extends DatasetController {
10776 static id = 'bubble';
10777 static defaults = {
10778 datasetElementType: false,
10779 dataElementType: 'point',
10780 animations: {
10781 numbers: {
10782 type: 'number',
10783 properties: [
10784 'x',
10785 'y',
10786 'borderWidth',
10787 'radius'
10788 ]
10789 }
10790 }
10791 };
10792 static overrides = {
10793 scales: {
10794 x: {
10795 type: 'linear'
10796 },
10797 y: {
10798 type: 'linear'
10799 }
10800 }
10801 };
10802 initialize() {
10803 this.enableOptionSharing = true;
10804 super.initialize();
10805 }
10806 parsePrimitiveData(meta, data, start, count) {
10807 const parsed = super.parsePrimitiveData(meta, data, start, count);
10808 for(let i = 0; i < parsed.length; i++){
10809 parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;
10810 }
10811 return parsed;
10812 }
10813 parseArrayData(meta, data, start, count) {
10814 const parsed = super.parseArrayData(meta, data, start, count);
10815 for(let i = 0; i < parsed.length; i++){
10816 const item = data[start + i];
10817 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item[2], this.resolveDataElementOptions(i + start).radius);
10818 }
10819 return parsed;
10820 }
10821 parseObjectData(meta, data, start, count) {
10822 const parsed = super.parseObjectData(meta, data, start, count);
10823 for(let i = 0; i < parsed.length; i++){
10824 const item = data[start + i];
10825 parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);
10826 }
10827 return parsed;
10828 }
10829 getMaxOverflow() {
10830 const data = this._cachedMeta.data;
10831 let max = 0;
10832 for(let i = data.length - 1; i >= 0; --i){
10833 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
10834 }
10835 return max > 0 && max;
10836 }
10837 getLabelAndValue(index) {
10838 const meta = this._cachedMeta;
10839 const labels = this.chart.data.labels || [];
10840 const { xScale , yScale } = meta;
10841 const parsed = this.getParsed(index);
10842 const x = xScale.getLabelForValue(parsed.x);
10843 const y = yScale.getLabelForValue(parsed.y);
10844 const r = parsed._custom;
10845 return {
10846 label: labels[index] || '',
10847 value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
10848 };
10849 }
10850 update(mode) {
10851 const points = this._cachedMeta.data;
10852 this.updateElements(points, 0, points.length, mode);
10853 }
10854 updateElements(points, start, count, mode) {
10855 const reset = mode === 'reset';
10856 const { iScale , vScale } = this._cachedMeta;
10857 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
10858 const iAxis = iScale.axis;
10859 const vAxis = vScale.axis;
10860 for(let i = start; i < start + count; i++){
10861 const point = points[i];
10862 const parsed = !reset && this.getParsed(i);
10863 const properties = {};
10864 const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);
10865 const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);
10866 properties.skip = isNaN(iPixel) || isNaN(vPixel);
10867 if (includeOptions) {
10868 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
10869 if (reset) {
10870 properties.options.radius = 0;
10871 }
10872 }
10873 this.updateElement(point, i, properties, mode);
10874 }
10875 }
10876 resolveDataElementOptions(index, mode) {
10877 const parsed = this.getParsed(index);
10878 let values = super.resolveDataElementOptions(index, mode);
10879 if (values.$shared) {
10880 values = Object.assign({}, values, {
10881 $shared: false
10882 });
10883 }
10884 const radius = values.radius;
10885 if (mode !== 'active') {
10886 values.radius = 0;
10887 }
10888 values.radius += (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(parsed && parsed._custom, radius);
10889 return values;
10890 }
10891 }
10892
10893 function getRatioAndOffset(rotation, circumference, cutout) {
10894 let ratioX = 1;
10895 let ratioY = 1;
10896 let offsetX = 0;
10897 let offsetY = 0;
10898 if (circumference < _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) {
10899 const startAngle = rotation;
10900 const endAngle = startAngle + circumference;
10901 const startX = Math.cos(startAngle);
10902 const startY = Math.sin(startAngle);
10903 const endX = Math.cos(endAngle);
10904 const endY = Math.sin(endAngle);
10905 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);
10906 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);
10907 const maxX = calcMax(0, startX, endX);
10908 const maxY = calcMax(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10909 const minX = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, startX, endX);
10910 const minY = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY);
10911 ratioX = (maxX - minX) / 2;
10912 ratioY = (maxY - minY) / 2;
10913 offsetX = -(maxX + minX) / 2;
10914 offsetY = -(maxY + minY) / 2;
10915 }
10916 return {
10917 ratioX,
10918 ratioY,
10919 offsetX,
10920 offsetY
10921 };
10922 }
10923 class DoughnutController extends DatasetController {
10924 static id = 'doughnut';
10925 static defaults = {
10926 datasetElementType: false,
10927 dataElementType: 'arc',
10928 animation: {
10929 animateRotate: true,
10930 animateScale: false
10931 },
10932 animations: {
10933 numbers: {
10934 type: 'number',
10935 properties: [
10936 'circumference',
10937 'endAngle',
10938 'innerRadius',
10939 'outerRadius',
10940 'startAngle',
10941 'x',
10942 'y',
10943 'offset',
10944 'borderWidth',
10945 'spacing'
10946 ]
10947 }
10948 },
10949 cutout: '50%',
10950 rotation: 0,
10951 circumference: 360,
10952 radius: '100%',
10953 spacing: 0,
10954 indexAxis: 'r'
10955 };
10956 static descriptors = {
10957 _scriptable: (name)=>name !== 'spacing',
10958 _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash')
10959 };
10960 static overrides = {
10961 aspectRatio: 1,
10962 plugins: {
10963 legend: {
10964 labels: {
10965 generateLabels (chart) {
10966 const data = chart.data;
10967 const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
10968 if (data.labels.length && data.datasets.length) {
10969 return data.labels.map((label, i)=>{
10970 const meta = chart.getDatasetMeta(0);
10971 const style = meta.controller.getStyle(i);
10972 return {
10973 text: label,
10974 fillStyle: style.backgroundColor,
10975 fontColor: color,
10976 hidden: !chart.getDataVisibility(i),
10977 lineDash: style.borderDash,
10978 lineDashOffset: style.borderDashOffset,
10979 lineJoin: style.borderJoinStyle,
10980 lineWidth: style.borderWidth,
10981 strokeStyle: style.borderColor,
10982 textAlign: textAlign,
10983 pointStyle: pointStyle,
10984 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
10985 index: i
10986 };
10987 });
10988 }
10989 return [];
10990 }
10991 },
10992 onClick (e, legendItem, legend) {
10993 legend.chart.toggleDataVisibility(legendItem.index);
10994 legend.chart.update();
10995 }
10996 }
10997 }
10998 };
10999 constructor(chart, datasetIndex){
11000 super(chart, datasetIndex);
11001 this.enableOptionSharing = true;
11002 this.innerRadius = undefined;
11003 this.outerRadius = undefined;
11004 this.offsetX = undefined;
11005 this.offsetY = undefined;
11006 }
11007 linkScales() {}
11008 parse(start, count) {
11009 const data = this.getDataset().data;
11010 const meta = this._cachedMeta;
11011 if (this._parsing === false) {
11012 meta._parsed = data;
11013 } else {
11014 let getter = (i)=>+data[i];
11015 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) {
11016 const { key ='value' } = this._parsing;
11017 getter = (i)=>+(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(data[i], key);
11018 }
11019 let i, ilen;
11020 for(i = start, ilen = start + count; i < ilen; ++i){
11021 meta._parsed[i] = getter(i);
11022 }
11023 }
11024 }
11025 _getRotation() {
11026 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.rotation - 90);
11027 }
11028 _getCircumference() {
11029 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.circumference);
11030 }
11031 _getRotationExtents() {
11032 let min = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
11033 let max = -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T;
11034 for(let i = 0; i < this.chart.data.datasets.length; ++i){
11035 if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) {
11036 const controller = this.chart.getDatasetMeta(i).controller;
11037 const rotation = controller._getRotation();
11038 const circumference = controller._getCircumference();
11039 min = Math.min(min, rotation);
11040 max = Math.max(max, rotation + circumference);
11041 }
11042 }
11043 return {
11044 rotation: min,
11045 circumference: max - min
11046 };
11047 }
11048 update(mode) {
11049 const chart = this.chart;
11050 const { chartArea } = chart;
11051 const meta = this._cachedMeta;
11052 const arcs = meta.data;
11053 const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
11054 const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
11055 const cutout = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.m)(this.options.cutout, maxSize), 1);
11056 const chartWeight = this._getRingWeight(this.index);
11057 const { circumference , rotation } = this._getRotationExtents();
11058 const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout);
11059 const maxWidth = (chartArea.width - spacing) / ratioX;
11060 const maxHeight = (chartArea.height - spacing) / ratioY;
11061 const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
11062 const outerRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.n)(this.options.radius, maxRadius);
11063 const innerRadius = Math.max(outerRadius * cutout, 0);
11064 const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
11065 this.offsetX = offsetX * outerRadius;
11066 this.offsetY = offsetY * outerRadius;
11067 meta.total = this.calculateTotal();
11068 this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
11069 this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
11070 this.updateElements(arcs, 0, arcs.length, mode);
11071 }
11072 _circumference(i, reset) {
11073 const opts = this.options;
11074 const meta = this._cachedMeta;
11075 const circumference = this._getCircumference();
11076 if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
11077 return 0;
11078 }
11079 return this.calculateCircumference(meta._parsed[i] * circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
11080 }
11081 updateElements(arcs, start, count, mode) {
11082 const reset = mode === 'reset';
11083 const chart = this.chart;
11084 const chartArea = chart.chartArea;
11085 const opts = chart.options;
11086 const animationOpts = opts.animation;
11087 const centerX = (chartArea.left + chartArea.right) / 2;
11088 const centerY = (chartArea.top + chartArea.bottom) / 2;
11089 const animateScale = reset && animationOpts.animateScale;
11090 const innerRadius = animateScale ? 0 : this.innerRadius;
11091 const outerRadius = animateScale ? 0 : this.outerRadius;
11092 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11093 let startAngle = this._getRotation();
11094 let i;
11095 for(i = 0; i < start; ++i){
11096 startAngle += this._circumference(i, reset);
11097 }
11098 for(i = start; i < start + count; ++i){
11099 const circumference = this._circumference(i, reset);
11100 const arc = arcs[i];
11101 const properties = {
11102 x: centerX + this.offsetX,
11103 y: centerY + this.offsetY,
11104 startAngle,
11105 endAngle: startAngle + circumference,
11106 circumference,
11107 outerRadius,
11108 innerRadius
11109 };
11110 if (includeOptions) {
11111 properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);
11112 }
11113 startAngle += circumference;
11114 this.updateElement(arc, i, properties, mode);
11115 }
11116 }
11117 calculateTotal() {
11118 const meta = this._cachedMeta;
11119 const metaData = meta.data;
11120 let total = 0;
11121 let i;
11122 for(i = 0; i < metaData.length; i++){
11123 const value = meta._parsed[i];
11124 if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
11125 total += Math.abs(value);
11126 }
11127 }
11128 return total;
11129 }
11130 calculateCircumference(value) {
11131 const total = this._cachedMeta.total;
11132 if (total > 0 && !isNaN(value)) {
11133 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T * (Math.abs(value) / total);
11134 }
11135 return 0;
11136 }
11137 getLabelAndValue(index) {
11138 const meta = this._cachedMeta;
11139 const chart = this.chart;
11140 const labels = chart.data.labels || [];
11141 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index], chart.options.locale);
11142 return {
11143 label: labels[index] || '',
11144 value
11145 };
11146 }
11147 getMaxBorderWidth(arcs) {
11148 let max = 0;
11149 const chart = this.chart;
11150 let i, ilen, meta, controller, options;
11151 if (!arcs) {
11152 for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){
11153 if (chart.isDatasetVisible(i)) {
11154 meta = chart.getDatasetMeta(i);
11155 arcs = meta.data;
11156 controller = meta.controller;
11157 break;
11158 }
11159 }
11160 }
11161 if (!arcs) {
11162 return 0;
11163 }
11164 for(i = 0, ilen = arcs.length; i < ilen; ++i){
11165 options = controller.resolveDataElementOptions(i);
11166 if (options.borderAlign !== 'inner') {
11167 max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
11168 }
11169 }
11170 return max;
11171 }
11172 getMaxOffset(arcs) {
11173 let max = 0;
11174 for(let i = 0, ilen = arcs.length; i < ilen; ++i){
11175 const options = this.resolveDataElementOptions(i);
11176 max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
11177 }
11178 return max;
11179 }
11180 _getRingWeightOffset(datasetIndex) {
11181 let ringWeightOffset = 0;
11182 for(let i = 0; i < datasetIndex; ++i){
11183 if (this.chart.isDatasetVisible(i)) {
11184 ringWeightOffset += this._getRingWeight(i);
11185 }
11186 }
11187 return ringWeightOffset;
11188 }
11189 _getRingWeight(datasetIndex) {
11190 return Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.data.datasets[datasetIndex].weight, 1), 0);
11191 }
11192 _getVisibleDatasetWeightTotal() {
11193 return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
11194 }
11195 }
11196
11197 class LineController extends DatasetController {
11198 static id = 'line';
11199 static defaults = {
11200 datasetElementType: 'line',
11201 dataElementType: 'point',
11202 showLine: true,
11203 spanGaps: false
11204 };
11205 static overrides = {
11206 scales: {
11207 _index_: {
11208 type: 'category'
11209 },
11210 _value_: {
11211 type: 'linear'
11212 }
11213 }
11214 };
11215 initialize() {
11216 this.enableOptionSharing = true;
11217 this.supportsDecimation = true;
11218 super.initialize();
11219 }
11220 update(mode) {
11221 const meta = this._cachedMeta;
11222 const { dataset: line , data: points = [] , _dataset } = meta;
11223 const animationsDisabled = this.chart._animationsDisabled;
11224 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11225 this._drawStart = start;
11226 this._drawCount = count;
11227 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11228 start = 0;
11229 count = points.length;
11230 }
11231 line._chart = this.chart;
11232 line._datasetIndex = this.index;
11233 line._decimated = !!_dataset._decimated;
11234 line.points = points;
11235 const options = this.resolveDatasetElementOptions(mode);
11236 if (!this.options.showLine) {
11237 options.borderWidth = 0;
11238 }
11239 options.segment = this.options.segment;
11240 this.updateElement(line, undefined, {
11241 animated: !animationsDisabled,
11242 options
11243 }, mode);
11244 this.updateElements(points, start, count, mode);
11245 }
11246 updateElements(points, start, count, mode) {
11247 const reset = mode === 'reset';
11248 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11249 const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);
11250 const iAxis = iScale.axis;
11251 const vAxis = vScale.axis;
11252 const { spanGaps , segment } = this.options;
11253 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11254 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11255 const end = start + count;
11256 const pointsCount = points.length;
11257 let prevParsed = start > 0 && this.getParsed(start - 1);
11258 for(let i = 0; i < pointsCount; ++i){
11259 const point = points[i];
11260 const properties = directUpdate ? point : {};
11261 if (i < start || i >= end) {
11262 properties.skip = true;
11263 continue;
11264 }
11265 const parsed = this.getParsed(i);
11266 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11267 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11268 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11269 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11270 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11271 if (segment) {
11272 properties.parsed = parsed;
11273 properties.raw = _dataset.data[i];
11274 }
11275 if (includeOptions) {
11276 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11277 }
11278 if (!directUpdate) {
11279 this.updateElement(point, i, properties, mode);
11280 }
11281 prevParsed = parsed;
11282 }
11283 }
11284 getMaxOverflow() {
11285 const meta = this._cachedMeta;
11286 const dataset = meta.dataset;
11287 const border = dataset.options && dataset.options.borderWidth || 0;
11288 const data = meta.data || [];
11289 if (!data.length) {
11290 return border;
11291 }
11292 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11293 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11294 return Math.max(border, firstPoint, lastPoint) / 2;
11295 }
11296 draw() {
11297 const meta = this._cachedMeta;
11298 meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);
11299 super.draw();
11300 }
11301 }
11302
11303 class PolarAreaController extends DatasetController {
11304 static id = 'polarArea';
11305 static defaults = {
11306 dataElementType: 'arc',
11307 animation: {
11308 animateRotate: true,
11309 animateScale: true
11310 },
11311 animations: {
11312 numbers: {
11313 type: 'number',
11314 properties: [
11315 'x',
11316 'y',
11317 'startAngle',
11318 'endAngle',
11319 'innerRadius',
11320 'outerRadius'
11321 ]
11322 }
11323 },
11324 indexAxis: 'r',
11325 startAngle: 0
11326 };
11327 static overrides = {
11328 aspectRatio: 1,
11329 plugins: {
11330 legend: {
11331 labels: {
11332 generateLabels (chart) {
11333 const data = chart.data;
11334 if (data.labels.length && data.datasets.length) {
11335 const { labels: { pointStyle , color } } = chart.legend.options;
11336 return data.labels.map((label, i)=>{
11337 const meta = chart.getDatasetMeta(0);
11338 const style = meta.controller.getStyle(i);
11339 return {
11340 text: label,
11341 fillStyle: style.backgroundColor,
11342 strokeStyle: style.borderColor,
11343 fontColor: color,
11344 lineWidth: style.borderWidth,
11345 pointStyle: pointStyle,
11346 hidden: !chart.getDataVisibility(i),
11347 index: i
11348 };
11349 });
11350 }
11351 return [];
11352 }
11353 },
11354 onClick (e, legendItem, legend) {
11355 legend.chart.toggleDataVisibility(legendItem.index);
11356 legend.chart.update();
11357 }
11358 }
11359 },
11360 scales: {
11361 r: {
11362 type: 'radialLinear',
11363 angleLines: {
11364 display: false
11365 },
11366 beginAtZero: true,
11367 grid: {
11368 circular: true
11369 },
11370 pointLabels: {
11371 display: false
11372 },
11373 startAngle: 0
11374 }
11375 }
11376 };
11377 constructor(chart, datasetIndex){
11378 super(chart, datasetIndex);
11379 this.innerRadius = undefined;
11380 this.outerRadius = undefined;
11381 }
11382 getLabelAndValue(index) {
11383 const meta = this._cachedMeta;
11384 const chart = this.chart;
11385 const labels = chart.data.labels || [];
11386 const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index].r, chart.options.locale);
11387 return {
11388 label: labels[index] || '',
11389 value
11390 };
11391 }
11392 parseObjectData(meta, data, start, count) {
11393 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11394 }
11395 update(mode) {
11396 const arcs = this._cachedMeta.data;
11397 this._updateRadius();
11398 this.updateElements(arcs, 0, arcs.length, mode);
11399 }
11400 getMinMax() {
11401 const meta = this._cachedMeta;
11402 const range = {
11403 min: Number.POSITIVE_INFINITY,
11404 max: Number.NEGATIVE_INFINITY
11405 };
11406 meta.data.forEach((element, index)=>{
11407 const parsed = this.getParsed(index).r;
11408 if (!isNaN(parsed) && this.chart.getDataVisibility(index)) {
11409 if (parsed < range.min) {
11410 range.min = parsed;
11411 }
11412 if (parsed > range.max) {
11413 range.max = parsed;
11414 }
11415 }
11416 });
11417 return range;
11418 }
11419 _updateRadius() {
11420 const chart = this.chart;
11421 const chartArea = chart.chartArea;
11422 const opts = chart.options;
11423 const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
11424 const outerRadius = Math.max(minSize / 2, 0);
11425 const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0);
11426 const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
11427 this.outerRadius = outerRadius - radiusLength * this.index;
11428 this.innerRadius = this.outerRadius - radiusLength;
11429 }
11430 updateElements(arcs, start, count, mode) {
11431 const reset = mode === 'reset';
11432 const chart = this.chart;
11433 const opts = chart.options;
11434 const animationOpts = opts.animation;
11435 const scale = this._cachedMeta.rScale;
11436 const centerX = scale.xCenter;
11437 const centerY = scale.yCenter;
11438 const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P;
11439 let angle = datasetStartAngle;
11440 let i;
11441 const defaultAngle = 360 / this.countVisibleElements();
11442 for(i = 0; i < start; ++i){
11443 angle += this._computeAngle(i, mode, defaultAngle);
11444 }
11445 for(i = start; i < start + count; i++){
11446 const arc = arcs[i];
11447 let startAngle = angle;
11448 let endAngle = angle + this._computeAngle(i, mode, defaultAngle);
11449 let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0;
11450 angle = endAngle;
11451 if (reset) {
11452 if (animationOpts.animateScale) {
11453 outerRadius = 0;
11454 }
11455 if (animationOpts.animateRotate) {
11456 startAngle = endAngle = datasetStartAngle;
11457 }
11458 }
11459 const properties = {
11460 x: centerX,
11461 y: centerY,
11462 innerRadius: 0,
11463 outerRadius,
11464 startAngle,
11465 endAngle,
11466 options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)
11467 };
11468 this.updateElement(arc, i, properties, mode);
11469 }
11470 }
11471 countVisibleElements() {
11472 const meta = this._cachedMeta;
11473 let count = 0;
11474 meta.data.forEach((element, index)=>{
11475 if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) {
11476 count++;
11477 }
11478 });
11479 return count;
11480 }
11481 _computeAngle(index, mode, defaultAngle) {
11482 return this.chart.getDataVisibility(index) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0;
11483 }
11484 }
11485
11486 class PieController extends DoughnutController {
11487 static id = 'pie';
11488 static defaults = {
11489 cutout: 0,
11490 rotation: 0,
11491 circumference: 360,
11492 radius: '100%'
11493 };
11494 }
11495
11496 class RadarController extends DatasetController {
11497 static id = 'radar';
11498 static defaults = {
11499 datasetElementType: 'line',
11500 dataElementType: 'point',
11501 indexAxis: 'r',
11502 showLine: true,
11503 elements: {
11504 line: {
11505 fill: 'start'
11506 }
11507 }
11508 };
11509 static overrides = {
11510 aspectRatio: 1,
11511 scales: {
11512 r: {
11513 type: 'radialLinear'
11514 }
11515 }
11516 };
11517 getLabelAndValue(index) {
11518 const vScale = this._cachedMeta.vScale;
11519 const parsed = this.getParsed(index);
11520 return {
11521 label: vScale.getLabels()[index],
11522 value: '' + vScale.getLabelForValue(parsed[vScale.axis])
11523 };
11524 }
11525 parseObjectData(meta, data, start, count) {
11526 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count);
11527 }
11528 update(mode) {
11529 const meta = this._cachedMeta;
11530 const line = meta.dataset;
11531 const points = meta.data || [];
11532 const labels = meta.iScale.getLabels();
11533 line.points = points;
11534 if (mode !== 'resize') {
11535 const options = this.resolveDatasetElementOptions(mode);
11536 if (!this.options.showLine) {
11537 options.borderWidth = 0;
11538 }
11539 const properties = {
11540 _loop: true,
11541 _fullLoop: labels.length === points.length,
11542 options
11543 };
11544 this.updateElement(line, undefined, properties, mode);
11545 }
11546 this.updateElements(points, 0, points.length, mode);
11547 }
11548 updateElements(points, start, count, mode) {
11549 const scale = this._cachedMeta.rScale;
11550 const reset = mode === 'reset';
11551 for(let i = start; i < start + count; i++){
11552 const point = points[i];
11553 const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11554 const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r);
11555 const x = reset ? scale.xCenter : pointPosition.x;
11556 const y = reset ? scale.yCenter : pointPosition.y;
11557 const properties = {
11558 x,
11559 y,
11560 angle: pointPosition.angle,
11561 skip: isNaN(x) || isNaN(y),
11562 options
11563 };
11564 this.updateElement(point, i, properties, mode);
11565 }
11566 }
11567 }
11568
11569 class ScatterController extends DatasetController {
11570 static id = 'scatter';
11571 static defaults = {
11572 datasetElementType: false,
11573 dataElementType: 'point',
11574 showLine: false,
11575 fill: false
11576 };
11577 static overrides = {
11578 interaction: {
11579 mode: 'point'
11580 },
11581 scales: {
11582 x: {
11583 type: 'linear'
11584 },
11585 y: {
11586 type: 'linear'
11587 }
11588 }
11589 };
11590 getLabelAndValue(index) {
11591 const meta = this._cachedMeta;
11592 const labels = this.chart.data.labels || [];
11593 const { xScale , yScale } = meta;
11594 const parsed = this.getParsed(index);
11595 const x = xScale.getLabelForValue(parsed.x);
11596 const y = yScale.getLabelForValue(parsed.y);
11597 return {
11598 label: labels[index] || '',
11599 value: '(' + x + ', ' + y + ')'
11600 };
11601 }
11602 update(mode) {
11603 const meta = this._cachedMeta;
11604 const { data: points = [] } = meta;
11605 const animationsDisabled = this.chart._animationsDisabled;
11606 let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled);
11607 this._drawStart = start;
11608 this._drawCount = count;
11609 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) {
11610 start = 0;
11611 count = points.length;
11612 }
11613 if (this.options.showLine) {
11614 if (!this.datasetElementType) {
11615 this.addElements();
11616 }
11617 const { dataset: line , _dataset } = meta;
11618 line._chart = this.chart;
11619 line._datasetIndex = this.index;
11620 line._decimated = !!_dataset._decimated;
11621 line.points = points;
11622 const options = this.resolveDatasetElementOptions(mode);
11623 options.segment = this.options.segment;
11624 this.updateElement(line, undefined, {
11625 animated: !animationsDisabled,
11626 options
11627 }, mode);
11628 } else if (this.datasetElementType) {
11629 delete meta.dataset;
11630 this.datasetElementType = false;
11631 }
11632 this.updateElements(points, start, count, mode);
11633 }
11634 addElements() {
11635 const { showLine } = this.options;
11636 if (!this.datasetElementType && showLine) {
11637 this.datasetElementType = this.chart.registry.getElement('line');
11638 }
11639 super.addElements();
11640 }
11641 updateElements(points, start, count, mode) {
11642 const reset = mode === 'reset';
11643 const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;
11644 const firstOpts = this.resolveDataElementOptions(start, mode);
11645 const sharedOptions = this.getSharedOptions(firstOpts);
11646 const includeOptions = this.includeOptions(mode, sharedOptions);
11647 const iAxis = iScale.axis;
11648 const vAxis = vScale.axis;
11649 const { spanGaps , segment } = this.options;
11650 const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
11651 const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
11652 let prevParsed = start > 0 && this.getParsed(start - 1);
11653 for(let i = start; i < start + count; ++i){
11654 const point = points[i];
11655 const parsed = this.getParsed(i);
11656 const properties = directUpdate ? point : {};
11657 const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]);
11658 const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
11659 const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
11660 properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
11661 properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
11662 if (segment) {
11663 properties.parsed = parsed;
11664 properties.raw = _dataset.data[i];
11665 }
11666 if (includeOptions) {
11667 properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
11668 }
11669 if (!directUpdate) {
11670 this.updateElement(point, i, properties, mode);
11671 }
11672 prevParsed = parsed;
11673 }
11674 this.updateSharedOptions(sharedOptions, mode, firstOpts);
11675 }
11676 getMaxOverflow() {
11677 const meta = this._cachedMeta;
11678 const data = meta.data || [];
11679 if (!this.options.showLine) {
11680 let max = 0;
11681 for(let i = data.length - 1; i >= 0; --i){
11682 max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
11683 }
11684 return max > 0 && max;
11685 }
11686 const dataset = meta.dataset;
11687 const border = dataset.options && dataset.options.borderWidth || 0;
11688 if (!data.length) {
11689 return border;
11690 }
11691 const firstPoint = data[0].size(this.resolveDataElementOptions(0));
11692 const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
11693 return Math.max(border, firstPoint, lastPoint) / 2;
11694 }
11695 }
11696
11697 var controllers = /*#__PURE__*/Object.freeze({
11698 __proto__: null,
11699 BarController: BarController,
11700 BubbleController: BubbleController,
11701 DoughnutController: DoughnutController,
11702 LineController: LineController,
11703 PieController: PieController,
11704 PolarAreaController: PolarAreaController,
11705 RadarController: RadarController,
11706 ScatterController: ScatterController
11707 });
11708
11709 /**
11710 * @namespace Chart._adapters
11711 * @since 2.8.0
11712 * @private
11713 */ function abstract() {
11714 throw new Error('This method is not implemented: Check that a complete date adapter is provided.');
11715 }
11716 /**
11717 * Date adapter (current used by the time scale)
11718 * @namespace Chart._adapters._date
11719 * @memberof Chart._adapters
11720 * @private
11721 */ class DateAdapterBase {
11722 /**
11723 * Override default date adapter methods.
11724 * Accepts type parameter to define options type.
11725 * @example
11726 * Chart._adapters._date.override<{myAdapterOption: string}>({
11727 * init() {
11728 * console.log(this.options.myAdapterOption);
11729 * }
11730 * })
11731 */ static override(members) {
11732 Object.assign(DateAdapterBase.prototype, members);
11733 }
11734 options;
11735 constructor(options){
11736 this.options = options || {};
11737 }
11738 // eslint-disable-next-line @typescript-eslint/no-empty-function
11739 init() {}
11740 formats() {
11741 return abstract();
11742 }
11743 parse() {
11744 return abstract();
11745 }
11746 format() {
11747 return abstract();
11748 }
11749 add() {
11750 return abstract();
11751 }
11752 diff() {
11753 return abstract();
11754 }
11755 startOf() {
11756 return abstract();
11757 }
11758 endOf() {
11759 return abstract();
11760 }
11761 }
11762 var adapters = {
11763 _date: DateAdapterBase
11764 };
11765
11766 function binarySearch(metaset, axis, value, intersect) {
11767 const { controller , data , _sorted } = metaset;
11768 const iScale = controller._cachedMeta.iScale;
11769 const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null;
11770 if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
11771 const lookupMethod = iScale._reversePixels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.A : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B;
11772 if (!intersect) {
11773 const result = lookupMethod(data, axis, value);
11774 if (spanGaps) {
11775 const { vScale } = controller._cachedMeta;
11776 const { _parsed } = metaset;
11777 const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11778 result.lo -= Math.max(0, distanceToDefinedLo);
11779 const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis]));
11780 result.hi += Math.max(0, distanceToDefinedHi);
11781 }
11782 return result;
11783 } else if (controller._sharedOptions) {
11784 const el = data[0];
11785 const range = typeof el.getRange === 'function' && el.getRange(axis);
11786 if (range) {
11787 const start = lookupMethod(data, axis, value - range);
11788 const end = lookupMethod(data, axis, value + range);
11789 return {
11790 lo: start.lo,
11791 hi: end.hi
11792 };
11793 }
11794 }
11795 }
11796 return {
11797 lo: 0,
11798 hi: data.length - 1
11799 };
11800 }
11801 function evaluateInteractionItems(chart, axis, position, handler, intersect) {
11802 const metasets = chart.getSortedVisibleDatasetMetas();
11803 const value = position[axis];
11804 for(let i = 0, ilen = metasets.length; i < ilen; ++i){
11805 const { index , data } = metasets[i];
11806 const { lo , hi } = binarySearch(metasets[i], axis, value, intersect);
11807 for(let j = lo; j <= hi; ++j){
11808 const element = data[j];
11809 if (!element.skip) {
11810 handler(element, index, j);
11811 }
11812 }
11813 }
11814 }
11815 function getDistanceMetricForAxis(axis) {
11816 const useX = axis.indexOf('x') !== -1;
11817 const useY = axis.indexOf('y') !== -1;
11818 return function(pt1, pt2) {
11819 const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
11820 const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
11821 return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
11822 };
11823 }
11824 function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {
11825 const items = [];
11826 if (!includeInvisible && !chart.isPointInArea(position)) {
11827 return items;
11828 }
11829 const evaluationFunc = function(element, datasetIndex, index) {
11830 if (!includeInvisible && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(element, chart.chartArea, 0)) {
11831 return;
11832 }
11833 if (element.inRange(position.x, position.y, useFinalPosition)) {
11834 items.push({
11835 element,
11836 datasetIndex,
11837 index
11838 });
11839 }
11840 };
11841 evaluateInteractionItems(chart, axis, position, evaluationFunc, true);
11842 return items;
11843 }
11844 function getNearestRadialItems(chart, position, axis, useFinalPosition) {
11845 let items = [];
11846 function evaluationFunc(element, datasetIndex, index) {
11847 const { startAngle , endAngle } = element.getProps([
11848 'startAngle',
11849 'endAngle'
11850 ], useFinalPosition);
11851 const { angle } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(element, {
11852 x: position.x,
11853 y: position.y
11854 });
11855 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle)) {
11856 items.push({
11857 element,
11858 datasetIndex,
11859 index
11860 });
11861 }
11862 }
11863 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11864 return items;
11865 }
11866 function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11867 let items = [];
11868 const distanceMetric = getDistanceMetricForAxis(axis);
11869 let minDistance = Number.POSITIVE_INFINITY;
11870 function evaluationFunc(element, datasetIndex, index) {
11871 const inRange = element.inRange(position.x, position.y, useFinalPosition);
11872 if (intersect && !inRange) {
11873 return;
11874 }
11875 const center = element.getCenterPoint(useFinalPosition);
11876 const pointInArea = !!includeInvisible || chart.isPointInArea(center);
11877 if (!pointInArea && !inRange) {
11878 return;
11879 }
11880 const distance = distanceMetric(position, center);
11881 if (distance < minDistance) {
11882 items = [
11883 {
11884 element,
11885 datasetIndex,
11886 index
11887 }
11888 ];
11889 minDistance = distance;
11890 } else if (distance === minDistance) {
11891 items.push({
11892 element,
11893 datasetIndex,
11894 index
11895 });
11896 }
11897 }
11898 evaluateInteractionItems(chart, axis, position, evaluationFunc);
11899 return items;
11900 }
11901 function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
11902 if (!includeInvisible && !chart.isPointInArea(position)) {
11903 return [];
11904 }
11905 return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);
11906 }
11907 function getAxisItems(chart, position, axis, intersect, useFinalPosition) {
11908 const items = [];
11909 const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
11910 let intersectsItem = false;
11911 evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{
11912 if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {
11913 items.push({
11914 element,
11915 datasetIndex,
11916 index
11917 });
11918 intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);
11919 }
11920 });
11921 if (intersect && !intersectsItem) {
11922 return [];
11923 }
11924 return items;
11925 }
11926 var Interaction = {
11927 evaluateInteractionItems,
11928 modes: {
11929 index (chart, e, options, useFinalPosition) {
11930 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11931 const axis = options.axis || 'x';
11932 const includeInvisible = options.includeInvisible || false;
11933 const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11934 const elements = [];
11935 if (!items.length) {
11936 return [];
11937 }
11938 chart.getSortedVisibleDatasetMetas().forEach((meta)=>{
11939 const index = items[0].index;
11940 const element = meta.data[index];
11941 if (element && !element.skip) {
11942 elements.push({
11943 element,
11944 datasetIndex: meta.index,
11945 index
11946 });
11947 }
11948 });
11949 return elements;
11950 },
11951 dataset (chart, e, options, useFinalPosition) {
11952 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11953 const axis = options.axis || 'xy';
11954 const includeInvisible = options.includeInvisible || false;
11955 let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
11956 if (items.length > 0) {
11957 const datasetIndex = items[0].datasetIndex;
11958 const data = chart.getDatasetMeta(datasetIndex).data;
11959 items = [];
11960 for(let i = 0; i < data.length; ++i){
11961 items.push({
11962 element: data[i],
11963 datasetIndex,
11964 index: i
11965 });
11966 }
11967 }
11968 return items;
11969 },
11970 point (chart, e, options, useFinalPosition) {
11971 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11972 const axis = options.axis || 'xy';
11973 const includeInvisible = options.includeInvisible || false;
11974 return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);
11975 },
11976 nearest (chart, e, options, useFinalPosition) {
11977 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11978 const axis = options.axis || 'xy';
11979 const includeInvisible = options.includeInvisible || false;
11980 return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);
11981 },
11982 x (chart, e, options, useFinalPosition) {
11983 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11984 return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition);
11985 },
11986 y (chart, e, options, useFinalPosition) {
11987 const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart);
11988 return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition);
11989 }
11990 }
11991 };
11992
11993 const STATIC_POSITIONS = [
11994 'left',
11995 'top',
11996 'right',
11997 'bottom'
11998 ];
11999 function filterByPosition(array, position) {
12000 return array.filter((v)=>v.pos === position);
12001 }
12002 function filterDynamicPositionByAxis(array, axis) {
12003 return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
12004 }
12005 function sortByWeight(array, reverse) {
12006 return array.sort((a, b)=>{
12007 const v0 = reverse ? b : a;
12008 const v1 = reverse ? a : b;
12009 return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;
12010 });
12011 }
12012 function wrapBoxes(boxes) {
12013 const layoutBoxes = [];
12014 let i, ilen, box, pos, stack, stackWeight;
12015 for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){
12016 box = boxes[i];
12017 ({ position: pos , options: { stack , stackWeight =1 } } = box);
12018 layoutBoxes.push({
12019 index: i,
12020 box,
12021 pos,
12022 horizontal: box.isHorizontal(),
12023 weight: box.weight,
12024 stack: stack && pos + stack,
12025 stackWeight
12026 });
12027 }
12028 return layoutBoxes;
12029 }
12030 function buildStacks(layouts) {
12031 const stacks = {};
12032 for (const wrap of layouts){
12033 const { stack , pos , stackWeight } = wrap;
12034 if (!stack || !STATIC_POSITIONS.includes(pos)) {
12035 continue;
12036 }
12037 const _stack = stacks[stack] || (stacks[stack] = {
12038 count: 0,
12039 placed: 0,
12040 weight: 0,
12041 size: 0
12042 });
12043 _stack.count++;
12044 _stack.weight += stackWeight;
12045 }
12046 return stacks;
12047 }
12048 function setLayoutDims(layouts, params) {
12049 const stacks = buildStacks(layouts);
12050 const { vBoxMaxWidth , hBoxMaxHeight } = params;
12051 let i, ilen, layout;
12052 for(i = 0, ilen = layouts.length; i < ilen; ++i){
12053 layout = layouts[i];
12054 const { fullSize } = layout.box;
12055 const stack = stacks[layout.stack];
12056 const factor = stack && layout.stackWeight / stack.weight;
12057 if (layout.horizontal) {
12058 layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
12059 layout.height = hBoxMaxHeight;
12060 } else {
12061 layout.width = vBoxMaxWidth;
12062 layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
12063 }
12064 }
12065 return stacks;
12066 }
12067 function buildLayoutBoxes(boxes) {
12068 const layoutBoxes = wrapBoxes(boxes);
12069 const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true);
12070 const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
12071 const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
12072 const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
12073 const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
12074 const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
12075 const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
12076 return {
12077 fullSize,
12078 leftAndTop: left.concat(top),
12079 rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
12080 chartArea: filterByPosition(layoutBoxes, 'chartArea'),
12081 vertical: left.concat(right).concat(centerVertical),
12082 horizontal: top.concat(bottom).concat(centerHorizontal)
12083 };
12084 }
12085 function getCombinedMax(maxPadding, chartArea, a, b) {
12086 return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
12087 }
12088 function updateMaxPadding(maxPadding, boxPadding) {
12089 maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
12090 maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
12091 maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
12092 maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
12093 }
12094 function updateDims(chartArea, params, layout, stacks) {
12095 const { pos , box } = layout;
12096 const maxPadding = chartArea.maxPadding;
12097 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(pos)) {
12098 if (layout.size) {
12099 chartArea[pos] -= layout.size;
12100 }
12101 const stack = stacks[layout.stack] || {
12102 size: 0,
12103 count: 1
12104 };
12105 stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
12106 layout.size = stack.size / stack.count;
12107 chartArea[pos] += layout.size;
12108 }
12109 if (box.getPadding) {
12110 updateMaxPadding(maxPadding, box.getPadding());
12111 }
12112 const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
12113 const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
12114 const widthChanged = newWidth !== chartArea.w;
12115 const heightChanged = newHeight !== chartArea.h;
12116 chartArea.w = newWidth;
12117 chartArea.h = newHeight;
12118 return layout.horizontal ? {
12119 same: widthChanged,
12120 other: heightChanged
12121 } : {
12122 same: heightChanged,
12123 other: widthChanged
12124 };
12125 }
12126 function handleMaxPadding(chartArea) {
12127 const maxPadding = chartArea.maxPadding;
12128 function updatePos(pos) {
12129 const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
12130 chartArea[pos] += change;
12131 return change;
12132 }
12133 chartArea.y += updatePos('top');
12134 chartArea.x += updatePos('left');
12135 updatePos('right');
12136 updatePos('bottom');
12137 }
12138 function getMargins(horizontal, chartArea) {
12139 const maxPadding = chartArea.maxPadding;
12140 function marginForPositions(positions) {
12141 const margin = {
12142 left: 0,
12143 top: 0,
12144 right: 0,
12145 bottom: 0
12146 };
12147 positions.forEach((pos)=>{
12148 margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
12149 });
12150 return margin;
12151 }
12152 return horizontal ? marginForPositions([
12153 'left',
12154 'right'
12155 ]) : marginForPositions([
12156 'top',
12157 'bottom'
12158 ]);
12159 }
12160 function fitBoxes(boxes, chartArea, params, stacks) {
12161 const refitBoxes = [];
12162 let i, ilen, layout, box, refit, changed;
12163 for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){
12164 layout = boxes[i];
12165 box = layout.box;
12166 box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));
12167 const { same , other } = updateDims(chartArea, params, layout, stacks);
12168 refit |= same && refitBoxes.length;
12169 changed = changed || other;
12170 if (!box.fullSize) {
12171 refitBoxes.push(layout);
12172 }
12173 }
12174 return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
12175 }
12176 function setBoxDims(box, left, top, width, height) {
12177 box.top = top;
12178 box.left = left;
12179 box.right = left + width;
12180 box.bottom = top + height;
12181 box.width = width;
12182 box.height = height;
12183 }
12184 function placeBoxes(boxes, chartArea, params, stacks) {
12185 const userPadding = params.padding;
12186 let { x , y } = chartArea;
12187 for (const layout of boxes){
12188 const box = layout.box;
12189 const stack = stacks[layout.stack] || {
12190 count: 1,
12191 placed: 0,
12192 weight: 1
12193 };
12194 const weight = layout.stackWeight / stack.weight || 1;
12195 if (layout.horizontal) {
12196 const width = chartArea.w * weight;
12197 const height = stack.size || box.height;
12198 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12199 y = stack.start;
12200 }
12201 if (box.fullSize) {
12202 setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);
12203 } else {
12204 setBoxDims(box, chartArea.left + stack.placed, y, width, height);
12205 }
12206 stack.start = y;
12207 stack.placed += width;
12208 y = box.bottom;
12209 } else {
12210 const height = chartArea.h * weight;
12211 const width = stack.size || box.width;
12212 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) {
12213 x = stack.start;
12214 }
12215 if (box.fullSize) {
12216 setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
12217 } else {
12218 setBoxDims(box, x, chartArea.top + stack.placed, width, height);
12219 }
12220 stack.start = x;
12221 stack.placed += height;
12222 x = box.right;
12223 }
12224 }
12225 chartArea.x = x;
12226 chartArea.y = y;
12227 }
12228 var layouts = {
12229 addBox (chart, item) {
12230 if (!chart.boxes) {
12231 chart.boxes = [];
12232 }
12233 item.fullSize = item.fullSize || false;
12234 item.position = item.position || 'top';
12235 item.weight = item.weight || 0;
12236 item._layers = item._layers || function() {
12237 return [
12238 {
12239 z: 0,
12240 draw (chartArea) {
12241 item.draw(chartArea);
12242 }
12243 }
12244 ];
12245 };
12246 chart.boxes.push(item);
12247 },
12248 removeBox (chart, layoutItem) {
12249 const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
12250 if (index !== -1) {
12251 chart.boxes.splice(index, 1);
12252 }
12253 },
12254 configure (chart, item, options) {
12255 item.fullSize = options.fullSize;
12256 item.position = options.position;
12257 item.weight = options.weight;
12258 },
12259 update (chart, width, height, minPadding) {
12260 if (!chart) {
12261 return;
12262 }
12263 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(chart.options.layout.padding);
12264 const availableWidth = Math.max(width - padding.width, 0);
12265 const availableHeight = Math.max(height - padding.height, 0);
12266 const boxes = buildLayoutBoxes(chart.boxes);
12267 const verticalBoxes = boxes.vertical;
12268 const horizontalBoxes = boxes.horizontal;
12269 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(chart.boxes, (box)=>{
12270 if (typeof box.beforeLayout === 'function') {
12271 box.beforeLayout();
12272 }
12273 });
12274 const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
12275 const params = Object.freeze({
12276 outerWidth: width,
12277 outerHeight: height,
12278 padding,
12279 availableWidth,
12280 availableHeight,
12281 vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
12282 hBoxMaxHeight: availableHeight / 2
12283 });
12284 const maxPadding = Object.assign({}, padding);
12285 updateMaxPadding(maxPadding, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(minPadding));
12286 const chartArea = Object.assign({
12287 maxPadding,
12288 w: availableWidth,
12289 h: availableHeight,
12290 x: padding.left,
12291 y: padding.top
12292 }, padding);
12293 const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
12294 fitBoxes(boxes.fullSize, chartArea, params, stacks);
12295 fitBoxes(verticalBoxes, chartArea, params, stacks);
12296 if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
12297 fitBoxes(verticalBoxes, chartArea, params, stacks);
12298 }
12299 handleMaxPadding(chartArea);
12300 placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
12301 chartArea.x += chartArea.w;
12302 chartArea.y += chartArea.h;
12303 placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
12304 chart.chartArea = {
12305 left: chartArea.left,
12306 top: chartArea.top,
12307 right: chartArea.left + chartArea.w,
12308 bottom: chartArea.top + chartArea.h,
12309 height: chartArea.h,
12310 width: chartArea.w
12311 };
12312 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(boxes.chartArea, (layout)=>{
12313 const box = layout.box;
12314 Object.assign(box, chart.chartArea);
12315 box.update(chartArea.w, chartArea.h, {
12316 left: 0,
12317 top: 0,
12318 right: 0,
12319 bottom: 0
12320 });
12321 });
12322 }
12323 };
12324
12325 class BasePlatform {
12326 acquireContext(canvas, aspectRatio) {}
12327 releaseContext(context) {
12328 return false;
12329 }
12330 addEventListener(chart, type, listener) {}
12331 removeEventListener(chart, type, listener) {}
12332 getDevicePixelRatio() {
12333 return 1;
12334 }
12335 getMaximumSize(element, width, height, aspectRatio) {
12336 width = Math.max(0, width || element.width);
12337 height = height || element.height;
12338 return {
12339 width,
12340 height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
12341 };
12342 }
12343 isAttached(canvas) {
12344 return true;
12345 }
12346 updateConfig(config) {
12347 }
12348 }
12349
12350 class BasicPlatform extends BasePlatform {
12351 acquireContext(item) {
12352 return item && item.getContext && item.getContext('2d') || null;
12353 }
12354 updateConfig(config) {
12355 config.options.animation = false;
12356 }
12357 }
12358
12359 const EXPANDO_KEY = '$chartjs';
12360 const EVENT_TYPES = {
12361 touchstart: 'mousedown',
12362 touchmove: 'mousemove',
12363 touchend: 'mouseup',
12364 pointerenter: 'mouseenter',
12365 pointerdown: 'mousedown',
12366 pointermove: 'mousemove',
12367 pointerup: 'mouseup',
12368 pointerleave: 'mouseout',
12369 pointerout: 'mouseout'
12370 };
12371 const isNullOrEmpty = (value)=>value === null || value === '';
12372 function initCanvas(canvas, aspectRatio) {
12373 const style = canvas.style;
12374 const renderHeight = canvas.getAttribute('height');
12375 const renderWidth = canvas.getAttribute('width');
12376 canvas[EXPANDO_KEY] = {
12377 initial: {
12378 height: renderHeight,
12379 width: renderWidth,
12380 style: {
12381 display: style.display,
12382 height: style.height,
12383 width: style.width
12384 }
12385 }
12386 };
12387 style.display = style.display || 'block';
12388 style.boxSizing = style.boxSizing || 'border-box';
12389 if (isNullOrEmpty(renderWidth)) {
12390 const displayWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'width');
12391 if (displayWidth !== undefined) {
12392 canvas.width = displayWidth;
12393 }
12394 }
12395 if (isNullOrEmpty(renderHeight)) {
12396 if (canvas.style.height === '') {
12397 canvas.height = canvas.width / (aspectRatio || 2);
12398 } else {
12399 const displayHeight = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'height');
12400 if (displayHeight !== undefined) {
12401 canvas.height = displayHeight;
12402 }
12403 }
12404 }
12405 return canvas;
12406 }
12407 const eventListenerOptions = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.K ? {
12408 passive: true
12409 } : false;
12410 function addListener(node, type, listener) {
12411 if (node) {
12412 node.addEventListener(type, listener, eventListenerOptions);
12413 }
12414 }
12415 function removeListener(chart, type, listener) {
12416 if (chart && chart.canvas) {
12417 chart.canvas.removeEventListener(type, listener, eventListenerOptions);
12418 }
12419 }
12420 function fromNativeEvent(event, chart) {
12421 const type = EVENT_TYPES[event.type] || event.type;
12422 const { x , y } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(event, chart);
12423 return {
12424 type,
12425 chart,
12426 native: event,
12427 x: x !== undefined ? x : null,
12428 y: y !== undefined ? y : null
12429 };
12430 }
12431 function nodeListContains(nodeList, canvas) {
12432 for (const node of nodeList){
12433 if (node === canvas || node.contains(canvas)) {
12434 return true;
12435 }
12436 }
12437 }
12438 function createAttachObserver(chart, type, listener) {
12439 const canvas = chart.canvas;
12440 const observer = new MutationObserver((entries)=>{
12441 let trigger = false;
12442 for (const entry of entries){
12443 trigger = trigger || nodeListContains(entry.addedNodes, canvas);
12444 trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
12445 }
12446 if (trigger) {
12447 listener();
12448 }
12449 });
12450 observer.observe(document, {
12451 childList: true,
12452 subtree: true
12453 });
12454 return observer;
12455 }
12456 function createDetachObserver(chart, type, listener) {
12457 const canvas = chart.canvas;
12458 const observer = new MutationObserver((entries)=>{
12459 let trigger = false;
12460 for (const entry of entries){
12461 trigger = trigger || nodeListContains(entry.removedNodes, canvas);
12462 trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
12463 }
12464 if (trigger) {
12465 listener();
12466 }
12467 });
12468 observer.observe(document, {
12469 childList: true,
12470 subtree: true
12471 });
12472 return observer;
12473 }
12474 const drpListeningCharts = new Map();
12475 let oldDevicePixelRatio = 0;
12476 function onWindowResize() {
12477 const dpr = window.devicePixelRatio;
12478 if (dpr === oldDevicePixelRatio) {
12479 return;
12480 }
12481 oldDevicePixelRatio = dpr;
12482 drpListeningCharts.forEach((resize, chart)=>{
12483 if (chart.currentDevicePixelRatio !== dpr) {
12484 resize();
12485 }
12486 });
12487 }
12488 function listenDevicePixelRatioChanges(chart, resize) {
12489 if (!drpListeningCharts.size) {
12490 window.addEventListener('resize', onWindowResize);
12491 }
12492 drpListeningCharts.set(chart, resize);
12493 }
12494 function unlistenDevicePixelRatioChanges(chart) {
12495 drpListeningCharts.delete(chart);
12496 if (!drpListeningCharts.size) {
12497 window.removeEventListener('resize', onWindowResize);
12498 }
12499 }
12500 function createResizeObserver(chart, type, listener) {
12501 const canvas = chart.canvas;
12502 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12503 if (!container) {
12504 return;
12505 }
12506 const resize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((width, height)=>{
12507 const w = container.clientWidth;
12508 listener(width, height);
12509 if (w < container.clientWidth) {
12510 listener();
12511 }
12512 }, window);
12513 const observer = new ResizeObserver((entries)=>{
12514 const entry = entries[0];
12515 const width = entry.contentRect.width;
12516 const height = entry.contentRect.height;
12517 if (width === 0 && height === 0) {
12518 return;
12519 }
12520 resize(width, height);
12521 });
12522 observer.observe(container);
12523 listenDevicePixelRatioChanges(chart, resize);
12524 return observer;
12525 }
12526 function releaseObserver(chart, type, observer) {
12527 if (observer) {
12528 observer.disconnect();
12529 }
12530 if (type === 'resize') {
12531 unlistenDevicePixelRatioChanges(chart);
12532 }
12533 }
12534 function createProxyAndListen(chart, type, listener) {
12535 const canvas = chart.canvas;
12536 const proxy = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((event)=>{
12537 if (chart.ctx !== null) {
12538 listener(fromNativeEvent(event, chart));
12539 }
12540 }, chart);
12541 addListener(canvas, type, proxy);
12542 return proxy;
12543 }
12544 class DomPlatform extends BasePlatform {
12545 acquireContext(canvas, aspectRatio) {
12546 const context = canvas && canvas.getContext && canvas.getContext('2d');
12547 if (context && context.canvas === canvas) {
12548 initCanvas(canvas, aspectRatio);
12549 return context;
12550 }
12551 return null;
12552 }
12553 releaseContext(context) {
12554 const canvas = context.canvas;
12555 if (!canvas[EXPANDO_KEY]) {
12556 return false;
12557 }
12558 const initial = canvas[EXPANDO_KEY].initial;
12559 [
12560 'height',
12561 'width'
12562 ].forEach((prop)=>{
12563 const value = initial[prop];
12564 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
12565 canvas.removeAttribute(prop);
12566 } else {
12567 canvas.setAttribute(prop, value);
12568 }
12569 });
12570 const style = initial.style || {};
12571 Object.keys(style).forEach((key)=>{
12572 canvas.style[key] = style[key];
12573 });
12574 canvas.width = canvas.width;
12575 delete canvas[EXPANDO_KEY];
12576 return true;
12577 }
12578 addEventListener(chart, type, listener) {
12579 this.removeEventListener(chart, type);
12580 const proxies = chart.$proxies || (chart.$proxies = {});
12581 const handlers = {
12582 attach: createAttachObserver,
12583 detach: createDetachObserver,
12584 resize: createResizeObserver
12585 };
12586 const handler = handlers[type] || createProxyAndListen;
12587 proxies[type] = handler(chart, type, listener);
12588 }
12589 removeEventListener(chart, type) {
12590 const proxies = chart.$proxies || (chart.$proxies = {});
12591 const proxy = proxies[type];
12592 if (!proxy) {
12593 return;
12594 }
12595 const handlers = {
12596 attach: releaseObserver,
12597 detach: releaseObserver,
12598 resize: releaseObserver
12599 };
12600 const handler = handlers[type] || removeListener;
12601 handler(chart, type, proxy);
12602 proxies[type] = undefined;
12603 }
12604 getDevicePixelRatio() {
12605 return window.devicePixelRatio;
12606 }
12607 getMaximumSize(canvas, width, height, aspectRatio) {
12608 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.G)(canvas, width, height, aspectRatio);
12609 }
12610 isAttached(canvas) {
12611 const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas);
12612 return !!(container && container.isConnected);
12613 }
12614 }
12615
12616 function _detectPlatform(canvas) {
12617 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
12618 return BasicPlatform;
12619 }
12620 return DomPlatform;
12621 }
12622
12623 class Element {
12624 static defaults = {};
12625 static defaultRoutes = undefined;
12626 x;
12627 y;
12628 active = false;
12629 options;
12630 $animations;
12631 tooltipPosition(useFinalPosition) {
12632 const { x , y } = this.getProps([
12633 'x',
12634 'y'
12635 ], useFinalPosition);
12636 return {
12637 x,
12638 y
12639 };
12640 }
12641 hasValue() {
12642 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);
12643 }
12644 getProps(props, final) {
12645 const anims = this.$animations;
12646 if (!final || !anims) {
12647 // let's not create an object, if not needed
12648 return this;
12649 }
12650 const ret = {};
12651 props.forEach((prop)=>{
12652 ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
12653 });
12654 return ret;
12655 }
12656 }
12657
12658 function autoSkip(scale, ticks) {
12659 const tickOpts = scale.options.ticks;
12660 const determinedMaxTicks = determineMaxTicks(scale);
12661 const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);
12662 const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
12663 const numMajorIndices = majorIndices.length;
12664 const first = majorIndices[0];
12665 const last = majorIndices[numMajorIndices - 1];
12666 const newTicks = [];
12667 if (numMajorIndices > ticksLimit) {
12668 skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
12669 return newTicks;
12670 }
12671 const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
12672 if (numMajorIndices > 0) {
12673 let i, ilen;
12674 const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
12675 skip(ticks, newTicks, spacing, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
12676 for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){
12677 skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
12678 }
12679 skip(ticks, newTicks, spacing, last, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
12680 return newTicks;
12681 }
12682 skip(ticks, newTicks, spacing);
12683 return newTicks;
12684 }
12685 function determineMaxTicks(scale) {
12686 const offset = scale.options.offset;
12687 const tickLength = scale._tickSize();
12688 const maxScale = scale._length / tickLength + (offset ? 0 : 1);
12689 const maxChart = scale._maxLength / tickLength;
12690 return Math.floor(Math.min(maxScale, maxChart));
12691 }
12692 function calculateSpacing(majorIndices, ticks, ticksLimit) {
12693 const evenMajorSpacing = getEvenSpacing(majorIndices);
12694 const spacing = ticks.length / ticksLimit;
12695 if (!evenMajorSpacing) {
12696 return Math.max(spacing, 1);
12697 }
12698 const factors = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.N)(evenMajorSpacing);
12699 for(let i = 0, ilen = factors.length - 1; i < ilen; i++){
12700 const factor = factors[i];
12701 if (factor > spacing) {
12702 return factor;
12703 }
12704 }
12705 return Math.max(spacing, 1);
12706 }
12707 function getMajorIndices(ticks) {
12708 const result = [];
12709 let i, ilen;
12710 for(i = 0, ilen = ticks.length; i < ilen; i++){
12711 if (ticks[i].major) {
12712 result.push(i);
12713 }
12714 }
12715 return result;
12716 }
12717 function skipMajors(ticks, newTicks, majorIndices, spacing) {
12718 let count = 0;
12719 let next = majorIndices[0];
12720 let i;
12721 spacing = Math.ceil(spacing);
12722 for(i = 0; i < ticks.length; i++){
12723 if (i === next) {
12724 newTicks.push(ticks[i]);
12725 count++;
12726 next = majorIndices[count * spacing];
12727 }
12728 }
12729 }
12730 function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
12731 const start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorStart, 0);
12732 const end = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorEnd, ticks.length), ticks.length);
12733 let count = 0;
12734 let length, i, next;
12735 spacing = Math.ceil(spacing);
12736 if (majorEnd) {
12737 length = majorEnd - majorStart;
12738 spacing = length / Math.floor(length / spacing);
12739 }
12740 next = start;
12741 while(next < 0){
12742 count++;
12743 next = Math.round(start + count * spacing);
12744 }
12745 for(i = Math.max(start, 0); i < end; i++){
12746 if (i === next) {
12747 newTicks.push(ticks[i]);
12748 count++;
12749 next = Math.round(start + count * spacing);
12750 }
12751 }
12752 }
12753 function getEvenSpacing(arr) {
12754 const len = arr.length;
12755 let i, diff;
12756 if (len < 2) {
12757 return false;
12758 }
12759 for(diff = arr[0], i = 1; i < len; ++i){
12760 if (arr[i] - arr[i - 1] !== diff) {
12761 return false;
12762 }
12763 }
12764 return diff;
12765 }
12766
12767 const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align;
12768 const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
12769 const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength);
12770 function sample(arr, numItems) {
12771 const result = [];
12772 const increment = arr.length / numItems;
12773 const len = arr.length;
12774 let i = 0;
12775 for(; i < len; i += increment){
12776 result.push(arr[Math.floor(i)]);
12777 }
12778 return result;
12779 }
12780 function getPixelForGridLine(scale, index, offsetGridLines) {
12781 const length = scale.ticks.length;
12782 const validIndex = Math.min(index, length - 1);
12783 const start = scale._startPixel;
12784 const end = scale._endPixel;
12785 const epsilon = 1e-6;
12786 let lineValue = scale.getPixelForTick(validIndex);
12787 let offset;
12788 if (offsetGridLines) {
12789 if (length === 1) {
12790 offset = Math.max(lineValue - start, end - lineValue);
12791 } else if (index === 0) {
12792 offset = (scale.getPixelForTick(1) - lineValue) / 2;
12793 } else {
12794 offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
12795 }
12796 lineValue += validIndex < index ? offset : -offset;
12797 if (lineValue < start - epsilon || lineValue > end + epsilon) {
12798 return;
12799 }
12800 }
12801 return lineValue;
12802 }
12803 function garbageCollect(caches, length) {
12804 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(caches, (cache)=>{
12805 const gc = cache.gc;
12806 const gcLen = gc.length / 2;
12807 let i;
12808 if (gcLen > length) {
12809 for(i = 0; i < gcLen; ++i){
12810 delete cache.data[gc[i]];
12811 }
12812 gc.splice(0, gcLen);
12813 }
12814 });
12815 }
12816 function getTickMarkLength(options) {
12817 return options.drawTicks ? options.tickLength : 0;
12818 }
12819 function getTitleHeight(options, fallback) {
12820 if (!options.display) {
12821 return 0;
12822 }
12823 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.font, fallback);
12824 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
12825 const lines = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(options.text) ? options.text.length : 1;
12826 return lines * font.lineHeight + padding.height;
12827 }
12828 function createScaleContext(parent, scale) {
12829 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12830 scale,
12831 type: 'scale'
12832 });
12833 }
12834 function createTickContext(parent, index, tick) {
12835 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
12836 tick,
12837 index,
12838 type: 'tick'
12839 });
12840 }
12841 function titleAlign(align, position, reverse) {
12842 let ret = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(align);
12843 if (reverse && position !== 'right' || !reverse && position === 'right') {
12844 ret = reverseAlign(ret);
12845 }
12846 return ret;
12847 }
12848 function titleArgs(scale, offset, position, align) {
12849 const { top , left , bottom , right , chart } = scale;
12850 const { chartArea , scales } = chart;
12851 let rotation = 0;
12852 let maxWidth, titleX, titleY;
12853 const height = bottom - top;
12854 const width = right - left;
12855 if (scale.isHorizontal()) {
12856 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
12857 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12858 const positionAxisID = Object.keys(position)[0];
12859 const value = position[positionAxisID];
12860 titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
12861 } else if (position === 'center') {
12862 titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
12863 } else {
12864 titleY = offsetFromEdge(scale, position, offset);
12865 }
12866 maxWidth = right - left;
12867 } else {
12868 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
12869 const positionAxisID = Object.keys(position)[0];
12870 const value = position[positionAxisID];
12871 titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
12872 } else if (position === 'center') {
12873 titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
12874 } else {
12875 titleX = offsetFromEdge(scale, position, offset);
12876 }
12877 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
12878 rotation = position === 'left' ? -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H;
12879 }
12880 return {
12881 titleX,
12882 titleY,
12883 maxWidth,
12884 rotation
12885 };
12886 }
12887 class Scale extends Element {
12888 constructor(cfg){
12889 super();
12890 this.id = cfg.id;
12891 this.type = cfg.type;
12892 this.options = undefined;
12893 this.ctx = cfg.ctx;
12894 this.chart = cfg.chart;
12895 this.top = undefined;
12896 this.bottom = undefined;
12897 this.left = undefined;
12898 this.right = undefined;
12899 this.width = undefined;
12900 this.height = undefined;
12901 this._margins = {
12902 left: 0,
12903 right: 0,
12904 top: 0,
12905 bottom: 0
12906 };
12907 this.maxWidth = undefined;
12908 this.maxHeight = undefined;
12909 this.paddingTop = undefined;
12910 this.paddingBottom = undefined;
12911 this.paddingLeft = undefined;
12912 this.paddingRight = undefined;
12913 this.axis = undefined;
12914 this.labelRotation = undefined;
12915 this.min = undefined;
12916 this.max = undefined;
12917 this._range = undefined;
12918 this.ticks = [];
12919 this._gridLineItems = null;
12920 this._labelItems = null;
12921 this._labelSizes = null;
12922 this._length = 0;
12923 this._maxLength = 0;
12924 this._longestTextCache = {};
12925 this._startPixel = undefined;
12926 this._endPixel = undefined;
12927 this._reversePixels = false;
12928 this._userMax = undefined;
12929 this._userMin = undefined;
12930 this._suggestedMax = undefined;
12931 this._suggestedMin = undefined;
12932 this._ticksLength = 0;
12933 this._borderValue = 0;
12934 this._cache = {};
12935 this._dataLimitsCached = false;
12936 this.$context = undefined;
12937 }
12938 init(options) {
12939 this.options = options.setContext(this.getContext());
12940 this.axis = options.axis;
12941 this._userMin = this.parse(options.min);
12942 this._userMax = this.parse(options.max);
12943 this._suggestedMin = this.parse(options.suggestedMin);
12944 this._suggestedMax = this.parse(options.suggestedMax);
12945 }
12946 parse(raw, index) {
12947 return raw;
12948 }
12949 getUserBounds() {
12950 let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this;
12951 _userMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, Number.POSITIVE_INFINITY);
12952 _userMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, Number.NEGATIVE_INFINITY);
12953 _suggestedMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMin, Number.POSITIVE_INFINITY);
12954 _suggestedMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMax, Number.NEGATIVE_INFINITY);
12955 return {
12956 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, _suggestedMin),
12957 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, _suggestedMax),
12958 minDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMin),
12959 maxDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMax)
12960 };
12961 }
12962 getMinMax(canStack) {
12963 let { min , max , minDefined , maxDefined } = this.getUserBounds();
12964 let range;
12965 if (minDefined && maxDefined) {
12966 return {
12967 min,
12968 max
12969 };
12970 }
12971 const metas = this.getMatchingVisibleMetas();
12972 for(let i = 0, ilen = metas.length; i < ilen; ++i){
12973 range = metas[i].controller.getMinMax(this, canStack);
12974 if (!minDefined) {
12975 min = Math.min(min, range.min);
12976 }
12977 if (!maxDefined) {
12978 max = Math.max(max, range.max);
12979 }
12980 }
12981 min = maxDefined && min > max ? max : min;
12982 max = minDefined && min > max ? min : max;
12983 return {
12984 min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, min)),
12985 max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, max))
12986 };
12987 }
12988 getPadding() {
12989 return {
12990 left: this.paddingLeft || 0,
12991 top: this.paddingTop || 0,
12992 right: this.paddingRight || 0,
12993 bottom: this.paddingBottom || 0
12994 };
12995 }
12996 getTicks() {
12997 return this.ticks;
12998 }
12999 getLabels() {
13000 const data = this.chart.data;
13001 return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
13002 }
13003 getLabelItems(chartArea = this.chart.chartArea) {
13004 const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
13005 return items;
13006 }
13007 beforeLayout() {
13008 this._cache = {};
13009 this._dataLimitsCached = false;
13010 }
13011 beforeUpdate() {
13012 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeUpdate, [
13013 this
13014 ]);
13015 }
13016 update(maxWidth, maxHeight, margins) {
13017 const { beginAtZero , grace , ticks: tickOpts } = this.options;
13018 const sampleSize = tickOpts.sampleSize;
13019 this.beforeUpdate();
13020 this.maxWidth = maxWidth;
13021 this.maxHeight = maxHeight;
13022 this._margins = margins = Object.assign({
13023 left: 0,
13024 right: 0,
13025 top: 0,
13026 bottom: 0
13027 }, margins);
13028 this.ticks = null;
13029 this._labelSizes = null;
13030 this._gridLineItems = null;
13031 this._labelItems = null;
13032 this.beforeSetDimensions();
13033 this.setDimensions();
13034 this.afterSetDimensions();
13035 this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;
13036 if (!this._dataLimitsCached) {
13037 this.beforeDataLimits();
13038 this.determineDataLimits();
13039 this.afterDataLimits();
13040 this._range = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.R)(this, grace, beginAtZero);
13041 this._dataLimitsCached = true;
13042 }
13043 this.beforeBuildTicks();
13044 this.ticks = this.buildTicks() || [];
13045 this.afterBuildTicks();
13046 const samplingEnabled = sampleSize < this.ticks.length;
13047 this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
13048 this.configure();
13049 this.beforeCalculateLabelRotation();
13050 this.calculateLabelRotation();
13051 this.afterCalculateLabelRotation();
13052 if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
13053 this.ticks = autoSkip(this, this.ticks);
13054 this._labelSizes = null;
13055 this.afterAutoSkip();
13056 }
13057 if (samplingEnabled) {
13058 this._convertTicksToLabels(this.ticks);
13059 }
13060 this.beforeFit();
13061 this.fit();
13062 this.afterFit();
13063 this.afterUpdate();
13064 }
13065 configure() {
13066 let reversePixels = this.options.reverse;
13067 let startPixel, endPixel;
13068 if (this.isHorizontal()) {
13069 startPixel = this.left;
13070 endPixel = this.right;
13071 } else {
13072 startPixel = this.top;
13073 endPixel = this.bottom;
13074 reversePixels = !reversePixels;
13075 }
13076 this._startPixel = startPixel;
13077 this._endPixel = endPixel;
13078 this._reversePixels = reversePixels;
13079 this._length = endPixel - startPixel;
13080 this._alignToPixels = this.options.alignToPixels;
13081 }
13082 afterUpdate() {
13083 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterUpdate, [
13084 this
13085 ]);
13086 }
13087 beforeSetDimensions() {
13088 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeSetDimensions, [
13089 this
13090 ]);
13091 }
13092 setDimensions() {
13093 if (this.isHorizontal()) {
13094 this.width = this.maxWidth;
13095 this.left = 0;
13096 this.right = this.width;
13097 } else {
13098 this.height = this.maxHeight;
13099 this.top = 0;
13100 this.bottom = this.height;
13101 }
13102 this.paddingLeft = 0;
13103 this.paddingTop = 0;
13104 this.paddingRight = 0;
13105 this.paddingBottom = 0;
13106 }
13107 afterSetDimensions() {
13108 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterSetDimensions, [
13109 this
13110 ]);
13111 }
13112 _callHooks(name) {
13113 this.chart.notifyPlugins(name, this.getContext());
13114 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options[name], [
13115 this
13116 ]);
13117 }
13118 beforeDataLimits() {
13119 this._callHooks('beforeDataLimits');
13120 }
13121 determineDataLimits() {}
13122 afterDataLimits() {
13123 this._callHooks('afterDataLimits');
13124 }
13125 beforeBuildTicks() {
13126 this._callHooks('beforeBuildTicks');
13127 }
13128 buildTicks() {
13129 return [];
13130 }
13131 afterBuildTicks() {
13132 this._callHooks('afterBuildTicks');
13133 }
13134 beforeTickToLabelConversion() {
13135 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeTickToLabelConversion, [
13136 this
13137 ]);
13138 }
13139 generateTickLabels(ticks) {
13140 const tickOpts = this.options.ticks;
13141 let i, ilen, tick;
13142 for(i = 0, ilen = ticks.length; i < ilen; i++){
13143 tick = ticks[i];
13144 tick.label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(tickOpts.callback, [
13145 tick.value,
13146 i,
13147 ticks
13148 ], this);
13149 }
13150 }
13151 afterTickToLabelConversion() {
13152 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterTickToLabelConversion, [
13153 this
13154 ]);
13155 }
13156 beforeCalculateLabelRotation() {
13157 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeCalculateLabelRotation, [
13158 this
13159 ]);
13160 }
13161 calculateLabelRotation() {
13162 const options = this.options;
13163 const tickOpts = options.ticks;
13164 const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);
13165 const minRotation = tickOpts.minRotation || 0;
13166 const maxRotation = tickOpts.maxRotation;
13167 let labelRotation = minRotation;
13168 let tickWidth, maxHeight, maxLabelDiagonal;
13169 if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
13170 this.labelRotation = minRotation;
13171 return;
13172 }
13173 const labelSizes = this._getLabelSizes();
13174 const maxLabelWidth = labelSizes.widest.width;
13175 const maxLabelHeight = labelSizes.highest.height;
13176 const maxWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(this.chart.width - maxLabelWidth, 0, this.maxWidth);
13177 tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
13178 if (maxLabelWidth + 6 > tickWidth) {
13179 tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
13180 maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
13181 maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
13182 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))));
13183 labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
13184 }
13185 this.labelRotation = labelRotation;
13186 }
13187 afterCalculateLabelRotation() {
13188 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterCalculateLabelRotation, [
13189 this
13190 ]);
13191 }
13192 afterAutoSkip() {}
13193 beforeFit() {
13194 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeFit, [
13195 this
13196 ]);
13197 }
13198 fit() {
13199 const minSize = {
13200 width: 0,
13201 height: 0
13202 };
13203 const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this;
13204 const display = this._isVisible();
13205 const isHorizontal = this.isHorizontal();
13206 if (display) {
13207 const titleHeight = getTitleHeight(titleOpts, chart.options.font);
13208 if (isHorizontal) {
13209 minSize.width = this.maxWidth;
13210 minSize.height = getTickMarkLength(gridOpts) + titleHeight;
13211 } else {
13212 minSize.height = this.maxHeight;
13213 minSize.width = getTickMarkLength(gridOpts) + titleHeight;
13214 }
13215 if (tickOpts.display && this.ticks.length) {
13216 const { first , last , widest , highest } = this._getLabelSizes();
13217 const tickPadding = tickOpts.padding * 2;
13218 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13219 const cos = Math.cos(angleRadians);
13220 const sin = Math.sin(angleRadians);
13221 if (isHorizontal) {
13222 const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
13223 minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
13224 } else {
13225 const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
13226 minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
13227 }
13228 this._calculatePadding(first, last, sin, cos);
13229 }
13230 }
13231 this._handleMargins();
13232 if (isHorizontal) {
13233 this.width = this._length = chart.width - this._margins.left - this._margins.right;
13234 this.height = minSize.height;
13235 } else {
13236 this.width = minSize.width;
13237 this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
13238 }
13239 }
13240 _calculatePadding(first, last, sin, cos) {
13241 const { ticks: { align , padding } , position } = this.options;
13242 const isRotated = this.labelRotation !== 0;
13243 const labelsBelowTicks = position !== 'top' && this.axis === 'x';
13244 if (this.isHorizontal()) {
13245 const offsetLeft = this.getPixelForTick(0) - this.left;
13246 const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
13247 let paddingLeft = 0;
13248 let paddingRight = 0;
13249 if (isRotated) {
13250 if (labelsBelowTicks) {
13251 paddingLeft = cos * first.width;
13252 paddingRight = sin * last.height;
13253 } else {
13254 paddingLeft = sin * first.height;
13255 paddingRight = cos * last.width;
13256 }
13257 } else if (align === 'start') {
13258 paddingRight = last.width;
13259 } else if (align === 'end') {
13260 paddingLeft = first.width;
13261 } else if (align !== 'inner') {
13262 paddingLeft = first.width / 2;
13263 paddingRight = last.width / 2;
13264 }
13265 this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
13266 this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
13267 } else {
13268 let paddingTop = last.height / 2;
13269 let paddingBottom = first.height / 2;
13270 if (align === 'start') {
13271 paddingTop = 0;
13272 paddingBottom = first.height;
13273 } else if (align === 'end') {
13274 paddingTop = last.height;
13275 paddingBottom = 0;
13276 }
13277 this.paddingTop = paddingTop + padding;
13278 this.paddingBottom = paddingBottom + padding;
13279 }
13280 }
13281 _handleMargins() {
13282 if (this._margins) {
13283 this._margins.left = Math.max(this.paddingLeft, this._margins.left);
13284 this._margins.top = Math.max(this.paddingTop, this._margins.top);
13285 this._margins.right = Math.max(this.paddingRight, this._margins.right);
13286 this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
13287 }
13288 }
13289 afterFit() {
13290 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterFit, [
13291 this
13292 ]);
13293 }
13294 isHorizontal() {
13295 const { axis , position } = this.options;
13296 return position === 'top' || position === 'bottom' || axis === 'x';
13297 }
13298 isFullSize() {
13299 return this.options.fullSize;
13300 }
13301 _convertTicksToLabels(ticks) {
13302 this.beforeTickToLabelConversion();
13303 this.generateTickLabels(ticks);
13304 let i, ilen;
13305 for(i = 0, ilen = ticks.length; i < ilen; i++){
13306 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(ticks[i].label)) {
13307 ticks.splice(i, 1);
13308 ilen--;
13309 i--;
13310 }
13311 }
13312 this.afterTickToLabelConversion();
13313 }
13314 _getLabelSizes() {
13315 let labelSizes = this._labelSizes;
13316 if (!labelSizes) {
13317 const sampleSize = this.options.ticks.sampleSize;
13318 let ticks = this.ticks;
13319 if (sampleSize < ticks.length) {
13320 ticks = sample(ticks, sampleSize);
13321 }
13322 this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);
13323 }
13324 return labelSizes;
13325 }
13326 _computeLabelSizes(ticks, length, maxTicksLimit) {
13327 const { ctx , _longestTextCache: caches } = this;
13328 const widths = [];
13329 const heights = [];
13330 const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));
13331 let widestLabelSize = 0;
13332 let highestLabelSize = 0;
13333 let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
13334 for(i = 0; i < length; i += increment){
13335 label = ticks[i].label;
13336 tickFont = this._resolveTickFontOptions(i);
13337 ctx.font = fontString = tickFont.string;
13338 cache = caches[fontString] = caches[fontString] || {
13339 data: {},
13340 gc: []
13341 };
13342 lineHeight = tickFont.lineHeight;
13343 width = height = 0;
13344 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(label) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13345 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, label);
13346 height = lineHeight;
13347 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) {
13348 for(j = 0, jlen = label.length; j < jlen; ++j){
13349 nestedLabel = label[j];
13350 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(nestedLabel) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(nestedLabel)) {
13351 width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, nestedLabel);
13352 height += lineHeight;
13353 }
13354 }
13355 }
13356 widths.push(width);
13357 heights.push(height);
13358 widestLabelSize = Math.max(width, widestLabelSize);
13359 highestLabelSize = Math.max(height, highestLabelSize);
13360 }
13361 garbageCollect(caches, length);
13362 const widest = widths.indexOf(widestLabelSize);
13363 const highest = heights.indexOf(highestLabelSize);
13364 const valueAt = (idx)=>({
13365 width: widths[idx] || 0,
13366 height: heights[idx] || 0
13367 });
13368 return {
13369 first: valueAt(0),
13370 last: valueAt(length - 1),
13371 widest: valueAt(widest),
13372 highest: valueAt(highest),
13373 widths,
13374 heights
13375 };
13376 }
13377 getLabelForValue(value) {
13378 return value;
13379 }
13380 getPixelForValue(value, index) {
13381 return NaN;
13382 }
13383 getValueForPixel(pixel) {}
13384 getPixelForTick(index) {
13385 const ticks = this.ticks;
13386 if (index < 0 || index > ticks.length - 1) {
13387 return null;
13388 }
13389 return this.getPixelForValue(ticks[index].value);
13390 }
13391 getPixelForDecimal(decimal) {
13392 if (this._reversePixels) {
13393 decimal = 1 - decimal;
13394 }
13395 const pixel = this._startPixel + decimal * this._length;
13396 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);
13397 }
13398 getDecimalForPixel(pixel) {
13399 const decimal = (pixel - this._startPixel) / this._length;
13400 return this._reversePixels ? 1 - decimal : decimal;
13401 }
13402 getBasePixel() {
13403 return this.getPixelForValue(this.getBaseValue());
13404 }
13405 getBaseValue() {
13406 const { min , max } = this;
13407 return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;
13408 }
13409 getContext(index) {
13410 const ticks = this.ticks || [];
13411 if (index >= 0 && index < ticks.length) {
13412 const tick = ticks[index];
13413 return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));
13414 }
13415 return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));
13416 }
13417 _tickSize() {
13418 const optionTicks = this.options.ticks;
13419 const rot = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13420 const cos = Math.abs(Math.cos(rot));
13421 const sin = Math.abs(Math.sin(rot));
13422 const labelSizes = this._getLabelSizes();
13423 const padding = optionTicks.autoSkipPadding || 0;
13424 const w = labelSizes ? labelSizes.widest.width + padding : 0;
13425 const h = labelSizes ? labelSizes.highest.height + padding : 0;
13426 return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin;
13427 }
13428 _isVisible() {
13429 const display = this.options.display;
13430 if (display !== 'auto') {
13431 return !!display;
13432 }
13433 return this.getMatchingVisibleMetas().length > 0;
13434 }
13435 _computeGridLineItems(chartArea) {
13436 const axis = this.axis;
13437 const chart = this.chart;
13438 const options = this.options;
13439 const { grid , position , border } = options;
13440 const offset = grid.offset;
13441 const isHorizontal = this.isHorizontal();
13442 const ticks = this.ticks;
13443 const ticksLength = ticks.length + (offset ? 1 : 0);
13444 const tl = getTickMarkLength(grid);
13445 const items = [];
13446 const borderOpts = border.setContext(this.getContext());
13447 const axisWidth = borderOpts.display ? borderOpts.width : 0;
13448 const axisHalfWidth = axisWidth / 2;
13449 const alignBorderValue = function(pixel) {
13450 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, pixel, axisWidth);
13451 };
13452 let borderValue, i, lineValue, alignedLineValue;
13453 let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
13454 if (position === 'top') {
13455 borderValue = alignBorderValue(this.bottom);
13456 ty1 = this.bottom - tl;
13457 ty2 = borderValue - axisHalfWidth;
13458 y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
13459 y2 = chartArea.bottom;
13460 } else if (position === 'bottom') {
13461 borderValue = alignBorderValue(this.top);
13462 y1 = chartArea.top;
13463 y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
13464 ty1 = borderValue + axisHalfWidth;
13465 ty2 = this.top + tl;
13466 } else if (position === 'left') {
13467 borderValue = alignBorderValue(this.right);
13468 tx1 = this.right - tl;
13469 tx2 = borderValue - axisHalfWidth;
13470 x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
13471 x2 = chartArea.right;
13472 } else if (position === 'right') {
13473 borderValue = alignBorderValue(this.left);
13474 x1 = chartArea.left;
13475 x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
13476 tx1 = borderValue + axisHalfWidth;
13477 tx2 = this.left + tl;
13478 } else if (axis === 'x') {
13479 if (position === 'center') {
13480 borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
13481 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13482 const positionAxisID = Object.keys(position)[0];
13483 const value = position[positionAxisID];
13484 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13485 }
13486 y1 = chartArea.top;
13487 y2 = chartArea.bottom;
13488 ty1 = borderValue + axisHalfWidth;
13489 ty2 = ty1 + tl;
13490 } else if (axis === 'y') {
13491 if (position === 'center') {
13492 borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
13493 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13494 const positionAxisID = Object.keys(position)[0];
13495 const value = position[positionAxisID];
13496 borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
13497 }
13498 tx1 = borderValue - axisHalfWidth;
13499 tx2 = tx1 - tl;
13500 x1 = chartArea.left;
13501 x2 = chartArea.right;
13502 }
13503 const limit = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.maxTicksLimit, ticksLength);
13504 const step = Math.max(1, Math.ceil(ticksLength / limit));
13505 for(i = 0; i < ticksLength; i += step){
13506 const context = this.getContext(i);
13507 const optsAtIndex = grid.setContext(context);
13508 const optsAtIndexBorder = border.setContext(context);
13509 const lineWidth = optsAtIndex.lineWidth;
13510 const lineColor = optsAtIndex.color;
13511 const borderDash = optsAtIndexBorder.dash || [];
13512 const borderDashOffset = optsAtIndexBorder.dashOffset;
13513 const tickWidth = optsAtIndex.tickWidth;
13514 const tickColor = optsAtIndex.tickColor;
13515 const tickBorderDash = optsAtIndex.tickBorderDash || [];
13516 const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
13517 lineValue = getPixelForGridLine(this, i, offset);
13518 if (lineValue === undefined) {
13519 continue;
13520 }
13521 alignedLineValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, lineValue, lineWidth);
13522 if (isHorizontal) {
13523 tx1 = tx2 = x1 = x2 = alignedLineValue;
13524 } else {
13525 ty1 = ty2 = y1 = y2 = alignedLineValue;
13526 }
13527 items.push({
13528 tx1,
13529 ty1,
13530 tx2,
13531 ty2,
13532 x1,
13533 y1,
13534 x2,
13535 y2,
13536 width: lineWidth,
13537 color: lineColor,
13538 borderDash,
13539 borderDashOffset,
13540 tickWidth,
13541 tickColor,
13542 tickBorderDash,
13543 tickBorderDashOffset
13544 });
13545 }
13546 this._ticksLength = ticksLength;
13547 this._borderValue = borderValue;
13548 return items;
13549 }
13550 _computeLabelItems(chartArea) {
13551 const axis = this.axis;
13552 const options = this.options;
13553 const { position , ticks: optionTicks } = options;
13554 const isHorizontal = this.isHorizontal();
13555 const ticks = this.ticks;
13556 const { align , crossAlign , padding , mirror } = optionTicks;
13557 const tl = getTickMarkLength(options.grid);
13558 const tickAndPadding = tl + padding;
13559 const hTickAndPadding = mirror ? -padding : tickAndPadding;
13560 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13561 const items = [];
13562 let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
13563 let textBaseline = 'middle';
13564 if (position === 'top') {
13565 y = this.bottom - hTickAndPadding;
13566 textAlign = this._getXAxisLabelAlignment();
13567 } else if (position === 'bottom') {
13568 y = this.top + hTickAndPadding;
13569 textAlign = this._getXAxisLabelAlignment();
13570 } else if (position === 'left') {
13571 const ret = this._getYAxisLabelAlignment(tl);
13572 textAlign = ret.textAlign;
13573 x = ret.x;
13574 } else if (position === 'right') {
13575 const ret = this._getYAxisLabelAlignment(tl);
13576 textAlign = ret.textAlign;
13577 x = ret.x;
13578 } else if (axis === 'x') {
13579 if (position === 'center') {
13580 y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;
13581 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13582 const positionAxisID = Object.keys(position)[0];
13583 const value = position[positionAxisID];
13584 y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
13585 }
13586 textAlign = this._getXAxisLabelAlignment();
13587 } else if (axis === 'y') {
13588 if (position === 'center') {
13589 x = (chartArea.left + chartArea.right) / 2 - tickAndPadding;
13590 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13591 const positionAxisID = Object.keys(position)[0];
13592 const value = position[positionAxisID];
13593 x = this.chart.scales[positionAxisID].getPixelForValue(value);
13594 }
13595 textAlign = this._getYAxisLabelAlignment(tl).textAlign;
13596 }
13597 if (axis === 'y') {
13598 if (align === 'start') {
13599 textBaseline = 'top';
13600 } else if (align === 'end') {
13601 textBaseline = 'bottom';
13602 }
13603 }
13604 const labelSizes = this._getLabelSizes();
13605 for(i = 0, ilen = ticks.length; i < ilen; ++i){
13606 tick = ticks[i];
13607 label = tick.label;
13608 const optsAtIndex = optionTicks.setContext(this.getContext(i));
13609 pixel = this.getPixelForTick(i) + optionTicks.labelOffset;
13610 font = this._resolveTickFontOptions(i);
13611 lineHeight = font.lineHeight;
13612 lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label.length : 1;
13613 const halfCount = lineCount / 2;
13614 const color = optsAtIndex.color;
13615 const strokeColor = optsAtIndex.textStrokeColor;
13616 const strokeWidth = optsAtIndex.textStrokeWidth;
13617 let tickTextAlign = textAlign;
13618 if (isHorizontal) {
13619 x = pixel;
13620 if (textAlign === 'inner') {
13621 if (i === ilen - 1) {
13622 tickTextAlign = !this.options.reverse ? 'right' : 'left';
13623 } else if (i === 0) {
13624 tickTextAlign = !this.options.reverse ? 'left' : 'right';
13625 } else {
13626 tickTextAlign = 'center';
13627 }
13628 }
13629 if (position === 'top') {
13630 if (crossAlign === 'near' || rotation !== 0) {
13631 textOffset = -lineCount * lineHeight + lineHeight / 2;
13632 } else if (crossAlign === 'center') {
13633 textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
13634 } else {
13635 textOffset = -labelSizes.highest.height + lineHeight / 2;
13636 }
13637 } else {
13638 if (crossAlign === 'near' || rotation !== 0) {
13639 textOffset = lineHeight / 2;
13640 } else if (crossAlign === 'center') {
13641 textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
13642 } else {
13643 textOffset = labelSizes.highest.height - lineCount * lineHeight;
13644 }
13645 }
13646 if (mirror) {
13647 textOffset *= -1;
13648 }
13649 if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {
13650 x += lineHeight / 2 * Math.sin(rotation);
13651 }
13652 } else {
13653 y = pixel;
13654 textOffset = (1 - lineCount) * lineHeight / 2;
13655 }
13656 let backdrop;
13657 if (optsAtIndex.showLabelBackdrop) {
13658 const labelPadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
13659 const height = labelSizes.heights[i];
13660 const width = labelSizes.widths[i];
13661 let top = textOffset - labelPadding.top;
13662 let left = 0 - labelPadding.left;
13663 switch(textBaseline){
13664 case 'middle':
13665 top -= height / 2;
13666 break;
13667 case 'bottom':
13668 top -= height;
13669 break;
13670 }
13671 switch(textAlign){
13672 case 'center':
13673 left -= width / 2;
13674 break;
13675 case 'right':
13676 left -= width;
13677 break;
13678 case 'inner':
13679 if (i === ilen - 1) {
13680 left -= width;
13681 } else if (i > 0) {
13682 left -= width / 2;
13683 }
13684 break;
13685 }
13686 backdrop = {
13687 left,
13688 top,
13689 width: width + labelPadding.width,
13690 height: height + labelPadding.height,
13691 color: optsAtIndex.backdropColor
13692 };
13693 }
13694 items.push({
13695 label,
13696 font,
13697 textOffset,
13698 options: {
13699 rotation,
13700 color,
13701 strokeColor,
13702 strokeWidth,
13703 textAlign: tickTextAlign,
13704 textBaseline,
13705 translation: [
13706 x,
13707 y
13708 ],
13709 backdrop
13710 }
13711 });
13712 }
13713 return items;
13714 }
13715 _getXAxisLabelAlignment() {
13716 const { position , ticks } = this.options;
13717 const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation);
13718 if (rotation) {
13719 return position === 'top' ? 'left' : 'right';
13720 }
13721 let align = 'center';
13722 if (ticks.align === 'start') {
13723 align = 'left';
13724 } else if (ticks.align === 'end') {
13725 align = 'right';
13726 } else if (ticks.align === 'inner') {
13727 align = 'inner';
13728 }
13729 return align;
13730 }
13731 _getYAxisLabelAlignment(tl) {
13732 const { position , ticks: { crossAlign , mirror , padding } } = this.options;
13733 const labelSizes = this._getLabelSizes();
13734 const tickAndPadding = tl + padding;
13735 const widest = labelSizes.widest.width;
13736 let textAlign;
13737 let x;
13738 if (position === 'left') {
13739 if (mirror) {
13740 x = this.right + padding;
13741 if (crossAlign === 'near') {
13742 textAlign = 'left';
13743 } else if (crossAlign === 'center') {
13744 textAlign = 'center';
13745 x += widest / 2;
13746 } else {
13747 textAlign = 'right';
13748 x += widest;
13749 }
13750 } else {
13751 x = this.right - tickAndPadding;
13752 if (crossAlign === 'near') {
13753 textAlign = 'right';
13754 } else if (crossAlign === 'center') {
13755 textAlign = 'center';
13756 x -= widest / 2;
13757 } else {
13758 textAlign = 'left';
13759 x = this.left;
13760 }
13761 }
13762 } else if (position === 'right') {
13763 if (mirror) {
13764 x = this.left + padding;
13765 if (crossAlign === 'near') {
13766 textAlign = 'right';
13767 } else if (crossAlign === 'center') {
13768 textAlign = 'center';
13769 x -= widest / 2;
13770 } else {
13771 textAlign = 'left';
13772 x -= widest;
13773 }
13774 } else {
13775 x = this.left + tickAndPadding;
13776 if (crossAlign === 'near') {
13777 textAlign = 'left';
13778 } else if (crossAlign === 'center') {
13779 textAlign = 'center';
13780 x += widest / 2;
13781 } else {
13782 textAlign = 'right';
13783 x = this.right;
13784 }
13785 }
13786 } else {
13787 textAlign = 'right';
13788 }
13789 return {
13790 textAlign,
13791 x
13792 };
13793 }
13794 _computeLabelArea() {
13795 if (this.options.ticks.mirror) {
13796 return;
13797 }
13798 const chart = this.chart;
13799 const position = this.options.position;
13800 if (position === 'left' || position === 'right') {
13801 return {
13802 top: 0,
13803 left: this.left,
13804 bottom: chart.height,
13805 right: this.right
13806 };
13807 }
13808 if (position === 'top' || position === 'bottom') {
13809 return {
13810 top: this.top,
13811 left: 0,
13812 bottom: this.bottom,
13813 right: chart.width
13814 };
13815 }
13816 }
13817 drawBackground() {
13818 const { ctx , options: { backgroundColor } , left , top , width , height } = this;
13819 if (backgroundColor) {
13820 ctx.save();
13821 ctx.fillStyle = backgroundColor;
13822 ctx.fillRect(left, top, width, height);
13823 ctx.restore();
13824 }
13825 }
13826 getLineWidthForValue(value) {
13827 const grid = this.options.grid;
13828 if (!this._isVisible() || !grid.display) {
13829 return 0;
13830 }
13831 const ticks = this.ticks;
13832 const index = ticks.findIndex((t)=>t.value === value);
13833 if (index >= 0) {
13834 const opts = grid.setContext(this.getContext(index));
13835 return opts.lineWidth;
13836 }
13837 return 0;
13838 }
13839 drawGrid(chartArea) {
13840 const grid = this.options.grid;
13841 const ctx = this.ctx;
13842 const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
13843 let i, ilen;
13844 const drawLine = (p1, p2, style)=>{
13845 if (!style.width || !style.color) {
13846 return;
13847 }
13848 ctx.save();
13849 ctx.lineWidth = style.width;
13850 ctx.strokeStyle = style.color;
13851 ctx.setLineDash(style.borderDash || []);
13852 ctx.lineDashOffset = style.borderDashOffset;
13853 ctx.beginPath();
13854 ctx.moveTo(p1.x, p1.y);
13855 ctx.lineTo(p2.x, p2.y);
13856 ctx.stroke();
13857 ctx.restore();
13858 };
13859 if (grid.display) {
13860 for(i = 0, ilen = items.length; i < ilen; ++i){
13861 const item = items[i];
13862 if (grid.drawOnChartArea) {
13863 drawLine({
13864 x: item.x1,
13865 y: item.y1
13866 }, {
13867 x: item.x2,
13868 y: item.y2
13869 }, item);
13870 }
13871 if (grid.drawTicks) {
13872 drawLine({
13873 x: item.tx1,
13874 y: item.ty1
13875 }, {
13876 x: item.tx2,
13877 y: item.ty2
13878 }, {
13879 color: item.tickColor,
13880 width: item.tickWidth,
13881 borderDash: item.tickBorderDash,
13882 borderDashOffset: item.tickBorderDashOffset
13883 });
13884 }
13885 }
13886 }
13887 }
13888 drawBorder() {
13889 const { chart , ctx , options: { border , grid } } = this;
13890 const borderOpts = border.setContext(this.getContext());
13891 const axisWidth = border.display ? borderOpts.width : 0;
13892 if (!axisWidth) {
13893 return;
13894 }
13895 const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
13896 const borderValue = this._borderValue;
13897 let x1, x2, y1, y2;
13898 if (this.isHorizontal()) {
13899 x1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.left, axisWidth) - axisWidth / 2;
13900 x2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.right, lastLineWidth) + lastLineWidth / 2;
13901 y1 = y2 = borderValue;
13902 } else {
13903 y1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.top, axisWidth) - axisWidth / 2;
13904 y2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
13905 x1 = x2 = borderValue;
13906 }
13907 ctx.save();
13908 ctx.lineWidth = borderOpts.width;
13909 ctx.strokeStyle = borderOpts.color;
13910 ctx.beginPath();
13911 ctx.moveTo(x1, y1);
13912 ctx.lineTo(x2, y2);
13913 ctx.stroke();
13914 ctx.restore();
13915 }
13916 drawLabels(chartArea) {
13917 const optionTicks = this.options.ticks;
13918 if (!optionTicks.display) {
13919 return;
13920 }
13921 const ctx = this.ctx;
13922 const area = this._computeLabelArea();
13923 if (area) {
13924 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
13925 }
13926 const items = this.getLabelItems(chartArea);
13927 for (const item of items){
13928 const renderTextOptions = item.options;
13929 const tickFont = item.font;
13930 const label = item.label;
13931 const y = item.textOffset;
13932 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, label, 0, y, tickFont, renderTextOptions);
13933 }
13934 if (area) {
13935 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
13936 }
13937 }
13938 drawTitle() {
13939 const { ctx , options: { position , title , reverse } } = this;
13940 if (!title.display) {
13941 return;
13942 }
13943 const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(title.font);
13944 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(title.padding);
13945 const align = title.align;
13946 let offset = font.lineHeight / 2;
13947 if (position === 'bottom' || position === 'center' || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) {
13948 offset += padding.bottom;
13949 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(title.text)) {
13950 offset += font.lineHeight * (title.text.length - 1);
13951 }
13952 } else {
13953 offset += padding.top;
13954 }
13955 const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align);
13956 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, title.text, 0, 0, font, {
13957 color: title.color,
13958 maxWidth,
13959 rotation,
13960 textAlign: titleAlign(align, position, reverse),
13961 textBaseline: 'middle',
13962 translation: [
13963 titleX,
13964 titleY
13965 ]
13966 });
13967 }
13968 draw(chartArea) {
13969 if (!this._isVisible()) {
13970 return;
13971 }
13972 this.drawBackground();
13973 this.drawGrid(chartArea);
13974 this.drawBorder();
13975 this.drawTitle();
13976 this.drawLabels(chartArea);
13977 }
13978 _layers() {
13979 const opts = this.options;
13980 const tz = opts.ticks && opts.ticks.z || 0;
13981 const gz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.grid && opts.grid.z, -1);
13982 const bz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.border && opts.border.z, 0);
13983 if (!this._isVisible() || this.draw !== Scale.prototype.draw) {
13984 return [
13985 {
13986 z: tz,
13987 draw: (chartArea)=>{
13988 this.draw(chartArea);
13989 }
13990 }
13991 ];
13992 }
13993 return [
13994 {
13995 z: gz,
13996 draw: (chartArea)=>{
13997 this.drawBackground();
13998 this.drawGrid(chartArea);
13999 this.drawTitle();
14000 }
14001 },
14002 {
14003 z: bz,
14004 draw: ()=>{
14005 this.drawBorder();
14006 }
14007 },
14008 {
14009 z: tz,
14010 draw: (chartArea)=>{
14011 this.drawLabels(chartArea);
14012 }
14013 }
14014 ];
14015 }
14016 getMatchingVisibleMetas(type) {
14017 const metas = this.chart.getSortedVisibleDatasetMetas();
14018 const axisID = this.axis + 'AxisID';
14019 const result = [];
14020 let i, ilen;
14021 for(i = 0, ilen = metas.length; i < ilen; ++i){
14022 const meta = metas[i];
14023 if (meta[axisID] === this.id && (!type || meta.type === type)) {
14024 result.push(meta);
14025 }
14026 }
14027 return result;
14028 }
14029 _resolveTickFontOptions(index) {
14030 const opts = this.options.ticks.setContext(this.getContext(index));
14031 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
14032 }
14033 _maxDigits() {
14034 const fontSize = this._resolveTickFontOptions(0).lineHeight;
14035 return (this.isHorizontal() ? this.width : this.height) / fontSize;
14036 }
14037 }
14038
14039 class TypedRegistry {
14040 constructor(type, scope, override){
14041 this.type = type;
14042 this.scope = scope;
14043 this.override = override;
14044 this.items = Object.create(null);
14045 }
14046 isForType(type) {
14047 return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
14048 }
14049 register(item) {
14050 const proto = Object.getPrototypeOf(item);
14051 let parentScope;
14052 if (isIChartComponent(proto)) {
14053 parentScope = this.register(proto);
14054 }
14055 const items = this.items;
14056 const id = item.id;
14057 const scope = this.scope + '.' + id;
14058 if (!id) {
14059 throw new Error('class does not have id: ' + item);
14060 }
14061 if (id in items) {
14062 return scope;
14063 }
14064 items[id] = item;
14065 registerDefaults(item, scope, parentScope);
14066 if (this.override) {
14067 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.override(item.id, item.overrides);
14068 }
14069 return scope;
14070 }
14071 get(id) {
14072 return this.items[id];
14073 }
14074 unregister(item) {
14075 const items = this.items;
14076 const id = item.id;
14077 const scope = this.scope;
14078 if (id in items) {
14079 delete items[id];
14080 }
14081 if (scope && id in _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope]) {
14082 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope][id];
14083 if (this.override) {
14084 delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[id];
14085 }
14086 }
14087 }
14088 }
14089 function registerDefaults(item, scope, parentScope) {
14090 const itemDefaults = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a4)(Object.create(null), [
14091 parentScope ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(parentScope) : {},
14092 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(scope),
14093 item.defaults
14094 ]);
14095 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.set(scope, itemDefaults);
14096 if (item.defaultRoutes) {
14097 routeDefaults(scope, item.defaultRoutes);
14098 }
14099 if (item.descriptors) {
14100 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.describe(scope, item.descriptors);
14101 }
14102 }
14103 function routeDefaults(scope, routes) {
14104 Object.keys(routes).forEach((property)=>{
14105 const propertyParts = property.split('.');
14106 const sourceName = propertyParts.pop();
14107 const sourceScope = [
14108 scope
14109 ].concat(propertyParts).join('.');
14110 const parts = routes[property].split('.');
14111 const targetName = parts.pop();
14112 const targetScope = parts.join('.');
14113 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.route(sourceScope, sourceName, targetScope, targetName);
14114 });
14115 }
14116 function isIChartComponent(proto) {
14117 return 'id' in proto && 'defaults' in proto;
14118 }
14119
14120 class Registry {
14121 constructor(){
14122 this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
14123 this.elements = new TypedRegistry(Element, 'elements');
14124 this.plugins = new TypedRegistry(Object, 'plugins');
14125 this.scales = new TypedRegistry(Scale, 'scales');
14126 this._typedRegistries = [
14127 this.controllers,
14128 this.scales,
14129 this.elements
14130 ];
14131 }
14132 add(...args) {
14133 this._each('register', args);
14134 }
14135 remove(...args) {
14136 this._each('unregister', args);
14137 }
14138 addControllers(...args) {
14139 this._each('register', args, this.controllers);
14140 }
14141 addElements(...args) {
14142 this._each('register', args, this.elements);
14143 }
14144 addPlugins(...args) {
14145 this._each('register', args, this.plugins);
14146 }
14147 addScales(...args) {
14148 this._each('register', args, this.scales);
14149 }
14150 getController(id) {
14151 return this._get(id, this.controllers, 'controller');
14152 }
14153 getElement(id) {
14154 return this._get(id, this.elements, 'element');
14155 }
14156 getPlugin(id) {
14157 return this._get(id, this.plugins, 'plugin');
14158 }
14159 getScale(id) {
14160 return this._get(id, this.scales, 'scale');
14161 }
14162 removeControllers(...args) {
14163 this._each('unregister', args, this.controllers);
14164 }
14165 removeElements(...args) {
14166 this._each('unregister', args, this.elements);
14167 }
14168 removePlugins(...args) {
14169 this._each('unregister', args, this.plugins);
14170 }
14171 removeScales(...args) {
14172 this._each('unregister', args, this.scales);
14173 }
14174 _each(method, args, typedRegistry) {
14175 [
14176 ...args
14177 ].forEach((arg)=>{
14178 const reg = typedRegistry || this._getRegistryForType(arg);
14179 if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {
14180 this._exec(method, reg, arg);
14181 } else {
14182 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(arg, (item)=>{
14183 const itemReg = typedRegistry || this._getRegistryForType(item);
14184 this._exec(method, itemReg, item);
14185 });
14186 }
14187 });
14188 }
14189 _exec(method, registry, component) {
14190 const camelMethod = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a5)(method);
14191 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['before' + camelMethod], [], component);
14192 registry[method](component);
14193 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['after' + camelMethod], [], component);
14194 }
14195 _getRegistryForType(type) {
14196 for(let i = 0; i < this._typedRegistries.length; i++){
14197 const reg = this._typedRegistries[i];
14198 if (reg.isForType(type)) {
14199 return reg;
14200 }
14201 }
14202 return this.plugins;
14203 }
14204 _get(id, typedRegistry, type) {
14205 const item = typedRegistry.get(id);
14206 if (item === undefined) {
14207 throw new Error('"' + id + '" is not a registered ' + type + '.');
14208 }
14209 return item;
14210 }
14211 }
14212 var registry = /* #__PURE__ */ new Registry();
14213
14214 class PluginService {
14215 constructor(){
14216 this._init = undefined;
14217 }
14218 notify(chart, hook, args, filter) {
14219 if (hook === 'beforeInit') {
14220 this._init = this._createDescriptors(chart, true);
14221 this._notify(this._init, chart, 'install');
14222 }
14223 if (this._init === undefined) {
14224 return;
14225 }
14226 const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
14227 const result = this._notify(descriptors, chart, hook, args);
14228 if (hook === 'afterDestroy') {
14229 this._notify(descriptors, chart, 'stop');
14230 this._notify(this._init, chart, 'uninstall');
14231 this._init = undefined;
14232 }
14233 return result;
14234 }
14235 _notify(descriptors, chart, hook, args) {
14236 args = args || {};
14237 for (const descriptor of descriptors){
14238 const plugin = descriptor.plugin;
14239 const method = plugin[hook];
14240 const params = [
14241 chart,
14242 args,
14243 descriptor.options
14244 ];
14245 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(method, params, plugin) === false && args.cancelable) {
14246 return false;
14247 }
14248 }
14249 return true;
14250 }
14251 invalidate() {
14252 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(this._cache)) {
14253 this._oldCache = this._cache;
14254 this._cache = undefined;
14255 }
14256 }
14257 _descriptors(chart) {
14258 if (this._cache) {
14259 return this._cache;
14260 }
14261 const descriptors = this._cache = this._createDescriptors(chart);
14262 this._notifyStateChanges(chart);
14263 return descriptors;
14264 }
14265 _createDescriptors(chart, all) {
14266 const config = chart && chart.config;
14267 const options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(config.options && config.options.plugins, {});
14268 const plugins = allPlugins(config);
14269 return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
14270 }
14271 _notifyStateChanges(chart) {
14272 const previousDescriptors = this._oldCache || [];
14273 const descriptors = this._cache;
14274 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id));
14275 this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
14276 this._notify(diff(descriptors, previousDescriptors), chart, 'start');
14277 }
14278 }
14279 function allPlugins(config) {
14280 const localIds = {};
14281 const plugins = [];
14282 const keys = Object.keys(registry.plugins.items);
14283 for(let i = 0; i < keys.length; i++){
14284 plugins.push(registry.getPlugin(keys[i]));
14285 }
14286 const local = config.plugins || [];
14287 for(let i = 0; i < local.length; i++){
14288 const plugin = local[i];
14289 if (plugins.indexOf(plugin) === -1) {
14290 plugins.push(plugin);
14291 localIds[plugin.id] = true;
14292 }
14293 }
14294 return {
14295 plugins,
14296 localIds
14297 };
14298 }
14299 function getOpts(options, all) {
14300 if (!all && options === false) {
14301 return null;
14302 }
14303 if (options === true) {
14304 return {};
14305 }
14306 return options;
14307 }
14308 function createDescriptors(chart, { plugins , localIds }, options, all) {
14309 const result = [];
14310 const context = chart.getContext();
14311 for (const plugin of plugins){
14312 const id = plugin.id;
14313 const opts = getOpts(options[id], all);
14314 if (opts === null) {
14315 continue;
14316 }
14317 result.push({
14318 plugin,
14319 options: pluginOpts(chart.config, {
14320 plugin,
14321 local: localIds[id]
14322 }, opts, context)
14323 });
14324 }
14325 return result;
14326 }
14327 function pluginOpts(config, { plugin , local }, opts, context) {
14328 const keys = config.pluginScopeKeys(plugin);
14329 const scopes = config.getOptionScopes(opts, keys);
14330 if (local && plugin.defaults) {
14331 scopes.push(plugin.defaults);
14332 }
14333 return config.createResolver(scopes, context, [
14334 ''
14335 ], {
14336 scriptable: false,
14337 indexable: false,
14338 allKeys: true
14339 });
14340 }
14341
14342 function getIndexAxis(type, options) {
14343 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {};
14344 const datasetOptions = (options.datasets || {})[type] || {};
14345 return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
14346 }
14347 function getAxisFromDefaultScaleID(id, indexAxis) {
14348 let axis = id;
14349 if (id === '_index_') {
14350 axis = indexAxis;
14351 } else if (id === '_value_') {
14352 axis = indexAxis === 'x' ? 'y' : 'x';
14353 }
14354 return axis;
14355 }
14356 function getDefaultScaleIDFromAxis(axis, indexAxis) {
14357 return axis === indexAxis ? '_index_' : '_value_';
14358 }
14359 function idMatchesAxis(id) {
14360 if (id === 'x' || id === 'y' || id === 'r') {
14361 return id;
14362 }
14363 }
14364 function axisFromPosition(position) {
14365 if (position === 'top' || position === 'bottom') {
14366 return 'x';
14367 }
14368 if (position === 'left' || position === 'right') {
14369 return 'y';
14370 }
14371 }
14372 function determineAxis(id, ...scaleOptions) {
14373 if (idMatchesAxis(id)) {
14374 return id;
14375 }
14376 for (const opts of scaleOptions){
14377 const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());
14378 if (axis) {
14379 return axis;
14380 }
14381 }
14382 throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
14383 }
14384 function getAxisFromDataset(id, axis, dataset) {
14385 if (dataset[axis + 'AxisID'] === id) {
14386 return {
14387 axis
14388 };
14389 }
14390 }
14391 function retrieveAxisFromDatasets(id, config) {
14392 if (config.data && config.data.datasets) {
14393 const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id);
14394 if (boundDs.length) {
14395 return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);
14396 }
14397 }
14398 return {};
14399 }
14400 function mergeScaleConfig(config, options) {
14401 const chartDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[config.type] || {
14402 scales: {}
14403 };
14404 const configScales = options.scales || {};
14405 const chartIndexAxis = getIndexAxis(config.type, options);
14406 const scales = Object.create(null);
14407 Object.keys(configScales).forEach((id)=>{
14408 const scaleConf = configScales[id];
14409 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(scaleConf)) {
14410 return console.error(`Invalid scale configuration for scale: ${id}`);
14411 }
14412 if (scaleConf._proxy) {
14413 return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
14414 }
14415 const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scaleConf.type]);
14416 const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
14417 const defaultScaleOptions = chartDefaults.scales || {};
14418 scales[id] = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(Object.create(null), [
14419 {
14420 axis
14421 },
14422 scaleConf,
14423 defaultScaleOptions[axis],
14424 defaultScaleOptions[defaultId]
14425 ]);
14426 });
14427 config.data.datasets.forEach((dataset)=>{
14428 const type = dataset.type || config.type;
14429 const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
14430 const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {};
14431 const defaultScaleOptions = datasetDefaults.scales || {};
14432 Object.keys(defaultScaleOptions).forEach((defaultID)=>{
14433 const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
14434 const id = dataset[axis + 'AxisID'] || axis;
14435 scales[id] = scales[id] || Object.create(null);
14436 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scales[id], [
14437 {
14438 axis
14439 },
14440 configScales[id],
14441 defaultScaleOptions[defaultID]
14442 ]);
14443 });
14444 });
14445 Object.keys(scales).forEach((key)=>{
14446 const scale = scales[key];
14447 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scale, [
14448 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scale.type],
14449 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scale
14450 ]);
14451 });
14452 return scales;
14453 }
14454 function initOptions(config) {
14455 const options = config.options || (config.options = {});
14456 options.plugins = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.plugins, {});
14457 options.scales = mergeScaleConfig(config, options);
14458 }
14459 function initData(data) {
14460 data = data || {};
14461 data.datasets = data.datasets || [];
14462 data.labels = data.labels || [];
14463 return data;
14464 }
14465 function initConfig(config) {
14466 config = config || {};
14467 config.data = initData(config.data);
14468 initOptions(config);
14469 return config;
14470 }
14471 const keyCache = new Map();
14472 const keysCached = new Set();
14473 function cachedKeys(cacheKey, generate) {
14474 let keys = keyCache.get(cacheKey);
14475 if (!keys) {
14476 keys = generate();
14477 keyCache.set(cacheKey, keys);
14478 keysCached.add(keys);
14479 }
14480 return keys;
14481 }
14482 const addIfFound = (set, obj, key)=>{
14483 const opts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, key);
14484 if (opts !== undefined) {
14485 set.add(opts);
14486 }
14487 };
14488 class Config {
14489 constructor(config){
14490 this._config = initConfig(config);
14491 this._scopeCache = new Map();
14492 this._resolverCache = new Map();
14493 }
14494 get platform() {
14495 return this._config.platform;
14496 }
14497 get type() {
14498 return this._config.type;
14499 }
14500 set type(type) {
14501 this._config.type = type;
14502 }
14503 get data() {
14504 return this._config.data;
14505 }
14506 set data(data) {
14507 this._config.data = initData(data);
14508 }
14509 get options() {
14510 return this._config.options;
14511 }
14512 set options(options) {
14513 this._config.options = options;
14514 }
14515 get plugins() {
14516 return this._config.plugins;
14517 }
14518 update() {
14519 const config = this._config;
14520 this.clearCache();
14521 initOptions(config);
14522 }
14523 clearCache() {
14524 this._scopeCache.clear();
14525 this._resolverCache.clear();
14526 }
14527 datasetScopeKeys(datasetType) {
14528 return cachedKeys(datasetType, ()=>[
14529 [
14530 `datasets.${datasetType}`,
14531 ''
14532 ]
14533 ]);
14534 }
14535 datasetAnimationScopeKeys(datasetType, transition) {
14536 return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[
14537 [
14538 `datasets.${datasetType}.transitions.${transition}`,
14539 `transitions.${transition}`
14540 ],
14541 [
14542 `datasets.${datasetType}`,
14543 ''
14544 ]
14545 ]);
14546 }
14547 datasetElementScopeKeys(datasetType, elementType) {
14548 return cachedKeys(`${datasetType}-${elementType}`, ()=>[
14549 [
14550 `datasets.${datasetType}.elements.${elementType}`,
14551 `datasets.${datasetType}`,
14552 `elements.${elementType}`,
14553 ''
14554 ]
14555 ]);
14556 }
14557 pluginScopeKeys(plugin) {
14558 const id = plugin.id;
14559 const type = this.type;
14560 return cachedKeys(`${type}-plugin-${id}`, ()=>[
14561 [
14562 `plugins.${id}`,
14563 ...plugin.additionalOptionScopes || []
14564 ]
14565 ]);
14566 }
14567 _cachedScopes(mainScope, resetCache) {
14568 const _scopeCache = this._scopeCache;
14569 let cache = _scopeCache.get(mainScope);
14570 if (!cache || resetCache) {
14571 cache = new Map();
14572 _scopeCache.set(mainScope, cache);
14573 }
14574 return cache;
14575 }
14576 getOptionScopes(mainScope, keyLists, resetCache) {
14577 const { options , type } = this;
14578 const cache = this._cachedScopes(mainScope, resetCache);
14579 const cached = cache.get(keyLists);
14580 if (cached) {
14581 return cached;
14582 }
14583 const scopes = new Set();
14584 keyLists.forEach((keys)=>{
14585 if (mainScope) {
14586 scopes.add(mainScope);
14587 keys.forEach((key)=>addIfFound(scopes, mainScope, key));
14588 }
14589 keys.forEach((key)=>addIfFound(scopes, options, key));
14590 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, key));
14591 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, key));
14592 keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6, key));
14593 });
14594 const array = Array.from(scopes);
14595 if (array.length === 0) {
14596 array.push(Object.create(null));
14597 }
14598 if (keysCached.has(keyLists)) {
14599 cache.set(keyLists, array);
14600 }
14601 return array;
14602 }
14603 chartOptionScopes() {
14604 const { options , type } = this;
14605 return [
14606 options,
14607 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {},
14608 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {},
14609 {
14610 type
14611 },
14612 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d,
14613 _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6
14614 ];
14615 }
14616 resolveNamedOptions(scopes, names, context, prefixes = [
14617 ''
14618 ]) {
14619 const result = {
14620 $shared: true
14621 };
14622 const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);
14623 let options = resolver;
14624 if (needContext(resolver, names)) {
14625 result.$shared = false;
14626 context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(context) ? context() : context;
14627 const subResolver = this.createResolver(scopes, context, subPrefixes);
14628 options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, subResolver);
14629 }
14630 for (const prop of names){
14631 result[prop] = options[prop];
14632 }
14633 return result;
14634 }
14635 createResolver(scopes, context, prefixes = [
14636 ''
14637 ], descriptorDefaults) {
14638 const { resolver } = getResolver(this._resolverCache, scopes, prefixes);
14639 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;
14640 }
14641 }
14642 function getResolver(resolverCache, scopes, prefixes) {
14643 let cache = resolverCache.get(scopes);
14644 if (!cache) {
14645 cache = new Map();
14646 resolverCache.set(scopes, cache);
14647 }
14648 const cacheKey = prefixes.join();
14649 let cached = cache.get(cacheKey);
14650 if (!cached) {
14651 const resolver = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a9)(scopes, prefixes);
14652 cached = {
14653 resolver,
14654 subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover'))
14655 };
14656 cache.set(cacheKey, cached);
14657 }
14658 return cached;
14659 }
14660 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]));
14661 function needContext(proxy, names) {
14662 const { isScriptable , isIndexable } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aa)(proxy);
14663 for (const prop of names){
14664 const scriptable = isScriptable(prop);
14665 const indexable = isIndexable(prop);
14666 const value = (indexable || scriptable) && proxy[prop];
14667 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)) {
14668 return true;
14669 }
14670 }
14671 return false;
14672 }
14673
14674 var version = "4.5.1";
14675
14676 const KNOWN_POSITIONS = [
14677 'top',
14678 'bottom',
14679 'left',
14680 'right',
14681 'chartArea'
14682 ];
14683 function positionIsHorizontal(position, axis) {
14684 return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x';
14685 }
14686 function compare2Level(l1, l2) {
14687 return function(a, b) {
14688 return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1];
14689 };
14690 }
14691 function onAnimationsComplete(context) {
14692 const chart = context.chart;
14693 const animationOptions = chart.options.animation;
14694 chart.notifyPlugins('afterRender');
14695 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onComplete, [
14696 context
14697 ], chart);
14698 }
14699 function onAnimationProgress(context) {
14700 const chart = context.chart;
14701 const animationOptions = chart.options.animation;
14702 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onProgress, [
14703 context
14704 ], chart);
14705 }
14706 function getCanvas(item) {
14707 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() && typeof item === 'string') {
14708 item = document.getElementById(item);
14709 } else if (item && item.length) {
14710 item = item[0];
14711 }
14712 if (item && item.canvas) {
14713 item = item.canvas;
14714 }
14715 return item;
14716 }
14717 const instances = {};
14718 const getChart = (key)=>{
14719 const canvas = getCanvas(key);
14720 return Object.values(instances).filter((c)=>c.canvas === canvas).pop();
14721 };
14722 function moveNumericKeys(obj, start, move) {
14723 const keys = Object.keys(obj);
14724 for (const key of keys){
14725 const intKey = +key;
14726 if (intKey >= start) {
14727 const value = obj[key];
14728 delete obj[key];
14729 if (move > 0 || intKey > start) {
14730 obj[intKey + move] = value;
14731 }
14732 }
14733 }
14734 }
14735 function determineLastEvent(e, lastEvent, inChartArea, isClick) {
14736 if (!inChartArea || e.type === 'mouseout') {
14737 return null;
14738 }
14739 if (isClick) {
14740 return lastEvent;
14741 }
14742 return e;
14743 }
14744 class Chart {
14745 static defaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d;
14746 static instances = instances;
14747 static overrides = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3;
14748 static registry = registry;
14749 static version = version;
14750 static getChart = getChart;
14751 static register(...items) {
14752 registry.add(...items);
14753 invalidatePlugins();
14754 }
14755 static unregister(...items) {
14756 registry.remove(...items);
14757 invalidatePlugins();
14758 }
14759 constructor(item, userConfig){
14760 const config = this.config = new Config(userConfig);
14761 const initialCanvas = getCanvas(item);
14762 const existingChart = getChart(initialCanvas);
14763 if (existingChart) {
14764 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.');
14765 }
14766 const options = config.createResolver(config.chartOptionScopes(), this.getContext());
14767 this.platform = new (config.platform || _detectPlatform(initialCanvas))();
14768 this.platform.updateConfig(config);
14769 const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
14770 const canvas = context && context.canvas;
14771 const height = canvas && canvas.height;
14772 const width = canvas && canvas.width;
14773 this.id = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ac)();
14774 this.ctx = context;
14775 this.canvas = canvas;
14776 this.width = width;
14777 this.height = height;
14778 this._options = options;
14779 this._aspectRatio = this.aspectRatio;
14780 this._layers = [];
14781 this._metasets = [];
14782 this._stacks = undefined;
14783 this.boxes = [];
14784 this.currentDevicePixelRatio = undefined;
14785 this.chartArea = undefined;
14786 this._active = [];
14787 this._lastEvent = undefined;
14788 this._listeners = {};
14789 this._responsiveListeners = undefined;
14790 this._sortedMetasets = [];
14791 this.scales = {};
14792 this._plugins = new PluginService();
14793 this.$proxies = {};
14794 this._hiddenIndices = {};
14795 this.attached = false;
14796 this._animationsDisabled = undefined;
14797 this.$context = undefined;
14798 this._doResize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ad)((mode)=>this.update(mode), options.resizeDelay || 0);
14799 this._dataChanges = [];
14800 instances[this.id] = this;
14801 if (!context || !canvas) {
14802 console.error("Failed to create chart: can't acquire context from the given item");
14803 return;
14804 }
14805 animator.listen(this, 'complete', onAnimationsComplete);
14806 animator.listen(this, 'progress', onAnimationProgress);
14807 this._initialize();
14808 if (this.attached) {
14809 this.update();
14810 }
14811 }
14812 get aspectRatio() {
14813 const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this;
14814 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(aspectRatio)) {
14815 return aspectRatio;
14816 }
14817 if (maintainAspectRatio && _aspectRatio) {
14818 return _aspectRatio;
14819 }
14820 return height ? width / height : null;
14821 }
14822 get data() {
14823 return this.config.data;
14824 }
14825 set data(data) {
14826 this.config.data = data;
14827 }
14828 get options() {
14829 return this._options;
14830 }
14831 set options(options) {
14832 this.config.options = options;
14833 }
14834 get registry() {
14835 return registry;
14836 }
14837 _initialize() {
14838 this.notifyPlugins('beforeInit');
14839 if (this.options.responsive) {
14840 this.resize();
14841 } else {
14842 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, this.options.devicePixelRatio);
14843 }
14844 this.bindEvents();
14845 this.notifyPlugins('afterInit');
14846 return this;
14847 }
14848 clear() {
14849 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(this.canvas, this.ctx);
14850 return this;
14851 }
14852 stop() {
14853 animator.stop(this);
14854 return this;
14855 }
14856 resize(width, height) {
14857 if (!animator.running(this)) {
14858 this._resize(width, height);
14859 } else {
14860 this._resizeBeforeDraw = {
14861 width,
14862 height
14863 };
14864 }
14865 }
14866 _resize(width, height) {
14867 const options = this.options;
14868 const canvas = this.canvas;
14869 const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
14870 const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
14871 const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
14872 const mode = this.width ? 'resize' : 'attach';
14873 this.width = newSize.width;
14874 this.height = newSize.height;
14875 this._aspectRatio = this.aspectRatio;
14876 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, newRatio, true)) {
14877 return;
14878 }
14879 this.notifyPlugins('resize', {
14880 size: newSize
14881 });
14882 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onResize, [
14883 this,
14884 newSize
14885 ], this);
14886 if (this.attached) {
14887 if (this._doResize(mode)) {
14888 this.render();
14889 }
14890 }
14891 }
14892 ensureScalesHaveIDs() {
14893 const options = this.options;
14894 const scalesOptions = options.scales || {};
14895 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scalesOptions, (axisOptions, axisID)=>{
14896 axisOptions.id = axisID;
14897 });
14898 }
14899 buildOrUpdateScales() {
14900 const options = this.options;
14901 const scaleOpts = options.scales;
14902 const scales = this.scales;
14903 const updated = Object.keys(scales).reduce((obj, id)=>{
14904 obj[id] = false;
14905 return obj;
14906 }, {});
14907 let items = [];
14908 if (scaleOpts) {
14909 items = items.concat(Object.keys(scaleOpts).map((id)=>{
14910 const scaleOptions = scaleOpts[id];
14911 const axis = determineAxis(id, scaleOptions);
14912 const isRadial = axis === 'r';
14913 const isHorizontal = axis === 'x';
14914 return {
14915 options: scaleOptions,
14916 dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
14917 dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
14918 };
14919 }));
14920 }
14921 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(items, (item)=>{
14922 const scaleOptions = item.options;
14923 const id = scaleOptions.id;
14924 const axis = determineAxis(id, scaleOptions);
14925 const scaleType = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(scaleOptions.type, item.dtype);
14926 if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
14927 scaleOptions.position = item.dposition;
14928 }
14929 updated[id] = true;
14930 let scale = null;
14931 if (id in scales && scales[id].type === scaleType) {
14932 scale = scales[id];
14933 } else {
14934 const scaleClass = registry.getScale(scaleType);
14935 scale = new scaleClass({
14936 id,
14937 type: scaleType,
14938 ctx: this.ctx,
14939 chart: this
14940 });
14941 scales[scale.id] = scale;
14942 }
14943 scale.init(scaleOptions, options);
14944 });
14945 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(updated, (hasUpdated, id)=>{
14946 if (!hasUpdated) {
14947 delete scales[id];
14948 }
14949 });
14950 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scales, (scale)=>{
14951 layouts.configure(this, scale, scale.options);
14952 layouts.addBox(this, scale);
14953 });
14954 }
14955 _updateMetasets() {
14956 const metasets = this._metasets;
14957 const numData = this.data.datasets.length;
14958 const numMeta = metasets.length;
14959 metasets.sort((a, b)=>a.index - b.index);
14960 if (numMeta > numData) {
14961 for(let i = numData; i < numMeta; ++i){
14962 this._destroyDatasetMeta(i);
14963 }
14964 metasets.splice(numData, numMeta - numData);
14965 }
14966 this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
14967 }
14968 _removeUnreferencedMetasets() {
14969 const { _metasets: metasets , data: { datasets } } = this;
14970 if (metasets.length > datasets.length) {
14971 delete this._stacks;
14972 }
14973 metasets.forEach((meta, index)=>{
14974 if (datasets.filter((x)=>x === meta._dataset).length === 0) {
14975 this._destroyDatasetMeta(index);
14976 }
14977 });
14978 }
14979 buildOrUpdateControllers() {
14980 const newControllers = [];
14981 const datasets = this.data.datasets;
14982 let i, ilen;
14983 this._removeUnreferencedMetasets();
14984 for(i = 0, ilen = datasets.length; i < ilen; i++){
14985 const dataset = datasets[i];
14986 let meta = this.getDatasetMeta(i);
14987 const type = dataset.type || this.config.type;
14988 if (meta.type && meta.type !== type) {
14989 this._destroyDatasetMeta(i);
14990 meta = this.getDatasetMeta(i);
14991 }
14992 meta.type = type;
14993 meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
14994 meta.order = dataset.order || 0;
14995 meta.index = i;
14996 meta.label = '' + dataset.label;
14997 meta.visible = this.isDatasetVisible(i);
14998 if (meta.controller) {
14999 meta.controller.updateIndex(i);
15000 meta.controller.linkScales();
15001 } else {
15002 const ControllerClass = registry.getController(type);
15003 const { datasetElementType , dataElementType } = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type];
15004 Object.assign(ControllerClass, {
15005 dataElementType: registry.getElement(dataElementType),
15006 datasetElementType: datasetElementType && registry.getElement(datasetElementType)
15007 });
15008 meta.controller = new ControllerClass(this, i);
15009 newControllers.push(meta.controller);
15010 }
15011 }
15012 this._updateMetasets();
15013 return newControllers;
15014 }
15015 _resetElements() {
15016 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.data.datasets, (dataset, datasetIndex)=>{
15017 this.getDatasetMeta(datasetIndex).controller.reset();
15018 }, this);
15019 }
15020 reset() {
15021 this._resetElements();
15022 this.notifyPlugins('reset');
15023 }
15024 update(mode) {
15025 const config = this.config;
15026 config.update();
15027 const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
15028 const animsDisabled = this._animationsDisabled = !options.animation;
15029 this._updateScales();
15030 this._checkEventBindings();
15031 this._updateHiddenIndices();
15032 this._plugins.invalidate();
15033 if (this.notifyPlugins('beforeUpdate', {
15034 mode,
15035 cancelable: true
15036 }) === false) {
15037 return;
15038 }
15039 const newControllers = this.buildOrUpdateControllers();
15040 this.notifyPlugins('beforeElementsUpdate');
15041 let minPadding = 0;
15042 for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){
15043 const { controller } = this.getDatasetMeta(i);
15044 const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
15045 controller.buildOrUpdateElements(reset);
15046 minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
15047 }
15048 minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
15049 this._updateLayout(minPadding);
15050 if (!animsDisabled) {
15051 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(newControllers, (controller)=>{
15052 controller.reset();
15053 });
15054 }
15055 this._updateDatasets(mode);
15056 this.notifyPlugins('afterUpdate', {
15057 mode
15058 });
15059 this._layers.sort(compare2Level('z', '_idx'));
15060 const { _active , _lastEvent } = this;
15061 if (_lastEvent) {
15062 this._eventHandler(_lastEvent, true);
15063 } else if (_active.length) {
15064 this._updateHoverStyles(_active, _active, true);
15065 }
15066 this.render();
15067 }
15068 _updateScales() {
15069 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.scales, (scale)=>{
15070 layouts.removeBox(this, scale);
15071 });
15072 this.ensureScalesHaveIDs();
15073 this.buildOrUpdateScales();
15074 }
15075 _checkEventBindings() {
15076 const options = this.options;
15077 const existingEvents = new Set(Object.keys(this._listeners));
15078 const newEvents = new Set(options.events);
15079 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
15080 this.unbindEvents();
15081 this.bindEvents();
15082 }
15083 }
15084 _updateHiddenIndices() {
15085 const { _hiddenIndices } = this;
15086 const changes = this._getUniformDataChanges() || [];
15087 for (const { method , start , count } of changes){
15088 const move = method === '_removeElements' ? -count : count;
15089 moveNumericKeys(_hiddenIndices, start, move);
15090 }
15091 }
15092 _getUniformDataChanges() {
15093 const _dataChanges = this._dataChanges;
15094 if (!_dataChanges || !_dataChanges.length) {
15095 return;
15096 }
15097 this._dataChanges = [];
15098 const datasetCount = this.data.datasets.length;
15099 const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(',')));
15100 const changeSet = makeSet(0);
15101 for(let i = 1; i < datasetCount; i++){
15102 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(changeSet, makeSet(i))) {
15103 return;
15104 }
15105 }
15106 return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({
15107 method: a[1],
15108 start: +a[2],
15109 count: +a[3]
15110 }));
15111 }
15112 _updateLayout(minPadding) {
15113 if (this.notifyPlugins('beforeLayout', {
15114 cancelable: true
15115 }) === false) {
15116 return;
15117 }
15118 layouts.update(this, this.width, this.height, minPadding);
15119 const area = this.chartArea;
15120 const noArea = area.width <= 0 || area.height <= 0;
15121 this._layers = [];
15122 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.boxes, (box)=>{
15123 if (noArea && box.position === 'chartArea') {
15124 return;
15125 }
15126 if (box.configure) {
15127 box.configure();
15128 }
15129 this._layers.push(...box._layers());
15130 }, this);
15131 this._layers.forEach((item, index)=>{
15132 item._idx = index;
15133 });
15134 this.notifyPlugins('afterLayout');
15135 }
15136 _updateDatasets(mode) {
15137 if (this.notifyPlugins('beforeDatasetsUpdate', {
15138 mode,
15139 cancelable: true
15140 }) === false) {
15141 return;
15142 }
15143 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15144 this.getDatasetMeta(i).controller.configure();
15145 }
15146 for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15147 this._updateDataset(i, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(mode) ? mode({
15148 datasetIndex: i
15149 }) : mode);
15150 }
15151 this.notifyPlugins('afterDatasetsUpdate', {
15152 mode
15153 });
15154 }
15155 _updateDataset(index, mode) {
15156 const meta = this.getDatasetMeta(index);
15157 const args = {
15158 meta,
15159 index,
15160 mode,
15161 cancelable: true
15162 };
15163 if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {
15164 return;
15165 }
15166 meta.controller._update(mode);
15167 args.cancelable = false;
15168 this.notifyPlugins('afterDatasetUpdate', args);
15169 }
15170 render() {
15171 if (this.notifyPlugins('beforeRender', {
15172 cancelable: true
15173 }) === false) {
15174 return;
15175 }
15176 if (animator.has(this)) {
15177 if (this.attached && !animator.running(this)) {
15178 animator.start(this);
15179 }
15180 } else {
15181 this.draw();
15182 onAnimationsComplete({
15183 chart: this
15184 });
15185 }
15186 }
15187 draw() {
15188 let i;
15189 if (this._resizeBeforeDraw) {
15190 const { width , height } = this._resizeBeforeDraw;
15191 this._resizeBeforeDraw = null;
15192 this._resize(width, height);
15193 }
15194 this.clear();
15195 if (this.width <= 0 || this.height <= 0) {
15196 return;
15197 }
15198 if (this.notifyPlugins('beforeDraw', {
15199 cancelable: true
15200 }) === false) {
15201 return;
15202 }
15203 const layers = this._layers;
15204 for(i = 0; i < layers.length && layers[i].z <= 0; ++i){
15205 layers[i].draw(this.chartArea);
15206 }
15207 this._drawDatasets();
15208 for(; i < layers.length; ++i){
15209 layers[i].draw(this.chartArea);
15210 }
15211 this.notifyPlugins('afterDraw');
15212 }
15213 _getSortedDatasetMetas(filterVisible) {
15214 const metasets = this._sortedMetasets;
15215 const result = [];
15216 let i, ilen;
15217 for(i = 0, ilen = metasets.length; i < ilen; ++i){
15218 const meta = metasets[i];
15219 if (!filterVisible || meta.visible) {
15220 result.push(meta);
15221 }
15222 }
15223 return result;
15224 }
15225 getSortedVisibleDatasetMetas() {
15226 return this._getSortedDatasetMetas(true);
15227 }
15228 _drawDatasets() {
15229 if (this.notifyPlugins('beforeDatasetsDraw', {
15230 cancelable: true
15231 }) === false) {
15232 return;
15233 }
15234 const metasets = this.getSortedVisibleDatasetMetas();
15235 for(let i = metasets.length - 1; i >= 0; --i){
15236 this._drawDataset(metasets[i]);
15237 }
15238 this.notifyPlugins('afterDatasetsDraw');
15239 }
15240 _drawDataset(meta) {
15241 const ctx = this.ctx;
15242 const args = {
15243 meta,
15244 index: meta.index,
15245 cancelable: true
15246 };
15247 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(this, meta);
15248 if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
15249 return;
15250 }
15251 if (clip) {
15252 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, clip);
15253 }
15254 meta.controller.draw();
15255 if (clip) {
15256 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
15257 }
15258 args.cancelable = false;
15259 this.notifyPlugins('afterDatasetDraw', args);
15260 }
15261 isPointInArea(point) {
15262 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(point, this.chartArea, this._minPadding);
15263 }
15264 getElementsAtEventForMode(e, mode, options, useFinalPosition) {
15265 const method = Interaction.modes[mode];
15266 if (typeof method === 'function') {
15267 return method(this, e, options, useFinalPosition);
15268 }
15269 return [];
15270 }
15271 getDatasetMeta(datasetIndex) {
15272 const dataset = this.data.datasets[datasetIndex];
15273 const metasets = this._metasets;
15274 let meta = metasets.filter((x)=>x && x._dataset === dataset).pop();
15275 if (!meta) {
15276 meta = {
15277 type: null,
15278 data: [],
15279 dataset: null,
15280 controller: null,
15281 hidden: null,
15282 xAxisID: null,
15283 yAxisID: null,
15284 order: dataset && dataset.order || 0,
15285 index: datasetIndex,
15286 _dataset: dataset,
15287 _parsed: [],
15288 _sorted: false
15289 };
15290 metasets.push(meta);
15291 }
15292 return meta;
15293 }
15294 getContext() {
15295 return this.$context || (this.$context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(null, {
15296 chart: this,
15297 type: 'chart'
15298 }));
15299 }
15300 getVisibleDatasetCount() {
15301 return this.getSortedVisibleDatasetMetas().length;
15302 }
15303 isDatasetVisible(datasetIndex) {
15304 const dataset = this.data.datasets[datasetIndex];
15305 if (!dataset) {
15306 return false;
15307 }
15308 const meta = this.getDatasetMeta(datasetIndex);
15309 return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
15310 }
15311 setDatasetVisibility(datasetIndex, visible) {
15312 const meta = this.getDatasetMeta(datasetIndex);
15313 meta.hidden = !visible;
15314 }
15315 toggleDataVisibility(index) {
15316 this._hiddenIndices[index] = !this._hiddenIndices[index];
15317 }
15318 getDataVisibility(index) {
15319 return !this._hiddenIndices[index];
15320 }
15321 _updateVisibility(datasetIndex, dataIndex, visible) {
15322 const mode = visible ? 'show' : 'hide';
15323 const meta = this.getDatasetMeta(datasetIndex);
15324 const anims = meta.controller._resolveAnimations(undefined, mode);
15325 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(dataIndex)) {
15326 meta.data[dataIndex].hidden = !visible;
15327 this.update();
15328 } else {
15329 this.setDatasetVisibility(datasetIndex, visible);
15330 anims.update(meta, {
15331 visible
15332 });
15333 this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined);
15334 }
15335 }
15336 hide(datasetIndex, dataIndex) {
15337 this._updateVisibility(datasetIndex, dataIndex, false);
15338 }
15339 show(datasetIndex, dataIndex) {
15340 this._updateVisibility(datasetIndex, dataIndex, true);
15341 }
15342 _destroyDatasetMeta(datasetIndex) {
15343 const meta = this._metasets[datasetIndex];
15344 if (meta && meta.controller) {
15345 meta.controller._destroy();
15346 }
15347 delete this._metasets[datasetIndex];
15348 }
15349 _stop() {
15350 let i, ilen;
15351 this.stop();
15352 animator.remove(this);
15353 for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){
15354 this._destroyDatasetMeta(i);
15355 }
15356 }
15357 destroy() {
15358 this.notifyPlugins('beforeDestroy');
15359 const { canvas , ctx } = this;
15360 this._stop();
15361 this.config.clearCache();
15362 if (canvas) {
15363 this.unbindEvents();
15364 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(canvas, ctx);
15365 this.platform.releaseContext(ctx);
15366 this.canvas = null;
15367 this.ctx = null;
15368 }
15369 delete instances[this.id];
15370 this.notifyPlugins('afterDestroy');
15371 }
15372 toBase64Image(...args) {
15373 return this.canvas.toDataURL(...args);
15374 }
15375 bindEvents() {
15376 this.bindUserEvents();
15377 if (this.options.responsive) {
15378 this.bindResponsiveEvents();
15379 } else {
15380 this.attached = true;
15381 }
15382 }
15383 bindUserEvents() {
15384 const listeners = this._listeners;
15385 const platform = this.platform;
15386 const _add = (type, listener)=>{
15387 platform.addEventListener(this, type, listener);
15388 listeners[type] = listener;
15389 };
15390 const listener = (e, x, y)=>{
15391 e.offsetX = x;
15392 e.offsetY = y;
15393 this._eventHandler(e);
15394 };
15395 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.options.events, (type)=>_add(type, listener));
15396 }
15397 bindResponsiveEvents() {
15398 if (!this._responsiveListeners) {
15399 this._responsiveListeners = {};
15400 }
15401 const listeners = this._responsiveListeners;
15402 const platform = this.platform;
15403 const _add = (type, listener)=>{
15404 platform.addEventListener(this, type, listener);
15405 listeners[type] = listener;
15406 };
15407 const _remove = (type, listener)=>{
15408 if (listeners[type]) {
15409 platform.removeEventListener(this, type, listener);
15410 delete listeners[type];
15411 }
15412 };
15413 const listener = (width, height)=>{
15414 if (this.canvas) {
15415 this.resize(width, height);
15416 }
15417 };
15418 let detached;
15419 const attached = ()=>{
15420 _remove('attach', attached);
15421 this.attached = true;
15422 this.resize();
15423 _add('resize', listener);
15424 _add('detach', detached);
15425 };
15426 detached = ()=>{
15427 this.attached = false;
15428 _remove('resize', listener);
15429 this._stop();
15430 this._resize(0, 0);
15431 _add('attach', attached);
15432 };
15433 if (platform.isAttached(this.canvas)) {
15434 attached();
15435 } else {
15436 detached();
15437 }
15438 }
15439 unbindEvents() {
15440 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._listeners, (listener, type)=>{
15441 this.platform.removeEventListener(this, type, listener);
15442 });
15443 this._listeners = {};
15444 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._responsiveListeners, (listener, type)=>{
15445 this.platform.removeEventListener(this, type, listener);
15446 });
15447 this._responsiveListeners = undefined;
15448 }
15449 updateHoverStyle(items, mode, enabled) {
15450 const prefix = enabled ? 'set' : 'remove';
15451 let meta, item, i, ilen;
15452 if (mode === 'dataset') {
15453 meta = this.getDatasetMeta(items[0].datasetIndex);
15454 meta.controller['_' + prefix + 'DatasetHoverStyle']();
15455 }
15456 for(i = 0, ilen = items.length; i < ilen; ++i){
15457 item = items[i];
15458 const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
15459 if (controller) {
15460 controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
15461 }
15462 }
15463 }
15464 getActiveElements() {
15465 return this._active || [];
15466 }
15467 setActiveElements(activeElements) {
15468 const lastActive = this._active || [];
15469 const active = activeElements.map(({ datasetIndex , index })=>{
15470 const meta = this.getDatasetMeta(datasetIndex);
15471 if (!meta) {
15472 throw new Error('No dataset found at index ' + datasetIndex);
15473 }
15474 return {
15475 datasetIndex,
15476 element: meta.data[index],
15477 index
15478 };
15479 });
15480 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15481 if (changed) {
15482 this._active = active;
15483 this._lastEvent = null;
15484 this._updateHoverStyles(active, lastActive);
15485 }
15486 }
15487 notifyPlugins(hook, args, filter) {
15488 return this._plugins.notify(this, hook, args, filter);
15489 }
15490 isPluginEnabled(pluginId) {
15491 return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1;
15492 }
15493 _updateHoverStyles(active, lastActive, replay) {
15494 const hoverOptions = this.options.hover;
15495 const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index));
15496 const deactivated = diff(lastActive, active);
15497 const activated = replay ? active : diff(active, lastActive);
15498 if (deactivated.length) {
15499 this.updateHoverStyle(deactivated, hoverOptions.mode, false);
15500 }
15501 if (activated.length && hoverOptions.mode) {
15502 this.updateHoverStyle(activated, hoverOptions.mode, true);
15503 }
15504 }
15505 _eventHandler(e, replay) {
15506 const args = {
15507 event: e,
15508 replay,
15509 cancelable: true,
15510 inChartArea: this.isPointInArea(e)
15511 };
15512 const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type);
15513 if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
15514 return;
15515 }
15516 const changed = this._handleEvent(e, replay, args.inChartArea);
15517 args.cancelable = false;
15518 this.notifyPlugins('afterEvent', args, eventFilter);
15519 if (changed || args.changed) {
15520 this.render();
15521 }
15522 return this;
15523 }
15524 _handleEvent(e, replay, inChartArea) {
15525 const { _active: lastActive = [] , options } = this;
15526 const useFinalPosition = replay;
15527 const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
15528 const isClick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aj)(e);
15529 const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
15530 if (inChartArea) {
15531 this._lastEvent = null;
15532 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onHover, [
15533 e,
15534 active,
15535 this
15536 ], this);
15537 if (isClick) {
15538 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onClick, [
15539 e,
15540 active,
15541 this
15542 ], this);
15543 }
15544 }
15545 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive);
15546 if (changed || replay) {
15547 this._active = active;
15548 this._updateHoverStyles(active, lastActive, replay);
15549 }
15550 this._lastEvent = lastEvent;
15551 return changed;
15552 }
15553 _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
15554 if (e.type === 'mouseout') {
15555 return [];
15556 }
15557 if (!inChartArea) {
15558 return lastActive;
15559 }
15560 const hoverOptions = this.options.hover;
15561 return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
15562 }
15563 }
15564 function invalidatePlugins() {
15565 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(Chart.instances, (chart)=>chart._plugins.invalidate());
15566 }
15567
15568 function clipSelf(ctx, element, endAngle) {
15569 const { startAngle , x , y , outerRadius , innerRadius , options } = element;
15570 const { borderWidth , borderJoinStyle } = options;
15571 const outerAngleClip = Math.min(borderWidth / outerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15572 ctx.beginPath();
15573 ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2);
15574 if (innerRadius > 0) {
15575 const innerAngleClip = Math.min(borderWidth / innerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15576 ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true);
15577 } else {
15578 const clipWidth = Math.min(borderWidth / 2, outerRadius * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle));
15579 if (borderJoinStyle === 'round') {
15580 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);
15581 } else if (borderJoinStyle === 'bevel') {
15582 const r = 2 * clipWidth * clipWidth;
15583 const endX = -r * Math.cos(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15584 const endY = -r * Math.sin(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15585 const startX = r * Math.cos(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x;
15586 const startY = r * Math.sin(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y;
15587 ctx.lineTo(endX, endY);
15588 ctx.lineTo(startX, startY);
15589 }
15590 }
15591 ctx.closePath();
15592 ctx.moveTo(0, 0);
15593 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
15594 ctx.clip('evenodd');
15595 }
15596 function clipArc(ctx, element, endAngle) {
15597 const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element;
15598 let angleMargin = pixelMargin / outerRadius;
15599 // Draw an inner border by clipping the arc and drawing a double-width border
15600 // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
15601 ctx.beginPath();
15602 ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
15603 if (innerRadius > pixelMargin) {
15604 angleMargin = pixelMargin / innerRadius;
15605 ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
15606 } else {
15607 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);
15608 }
15609 ctx.closePath();
15610 ctx.clip();
15611 }
15612 function toRadiusCorners(value) {
15613 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.am)(value, [
15614 'outerStart',
15615 'outerEnd',
15616 'innerStart',
15617 'innerEnd'
15618 ]);
15619 }
15620 /**
15621 * Parse border radius from the provided options
15622 */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
15623 const o = toRadiusCorners(arc.options.borderRadius);
15624 const halfThickness = (outerRadius - innerRadius) / 2;
15625 const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
15626 // Outer limits are complicated. We want to compute the available angular distance at
15627 // a radius of outerRadius - borderRadius because for small angular distances, this term limits.
15628 // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners.
15629 //
15630 // If the borderRadius is large, that value can become negative.
15631 // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius
15632 // we know that the thickness term will dominate and compute the limits at that point
15633 const computeOuterLimit = (val)=>{
15634 const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
15635 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(val, 0, Math.min(halfThickness, outerArcLimit));
15636 };
15637 return {
15638 outerStart: computeOuterLimit(o.outerStart),
15639 outerEnd: computeOuterLimit(o.outerEnd),
15640 innerStart: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerStart, 0, innerLimit),
15641 innerEnd: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerEnd, 0, innerLimit)
15642 };
15643 }
15644 /**
15645 * Convert (r, 𝜃) to (x, y)
15646 */ function rThetaToXY(r, theta, x, y) {
15647 return {
15648 x: x + r * Math.cos(theta),
15649 y: y + r * Math.sin(theta)
15650 };
15651 }
15652 /**
15653 * Path the arc, respecting border radius by separating into left and right halves.
15654 *
15655 * Start End
15656 *
15657 * 1--->a--->2 Outer
15658 * / \
15659 * 8 3
15660 * | |
15661 * | |
15662 * 7 4
15663 * \ /
15664 * 6<---b<---5 Inner
15665 */ function pathArc(ctx, element, offset, spacing, end, circular) {
15666 const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element;
15667 const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
15668 const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
15669 let spacingOffset = 0;
15670 const alpha = end - start;
15671 if (spacing) {
15672 // When spacing is present, it is the same for all items
15673 // So we adjust the start and end angle of the arc such that
15674 // the distance is the same as it would be without the spacing
15675 const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
15676 const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
15677 const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
15678 const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha;
15679 spacingOffset = (alpha - adjustedAngle) / 2;
15680 }
15681 const beta = Math.max(0.001, alpha * outerRadius - offset / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P) / outerRadius;
15682 const angleOffset = (alpha - beta) / 2;
15683 const startAngle = start + angleOffset + spacingOffset;
15684 const endAngle = end - angleOffset - spacingOffset;
15685 const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
15686 const outerStartAdjustedRadius = outerRadius - outerStart;
15687 const outerEndAdjustedRadius = outerRadius - outerEnd;
15688 const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
15689 const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
15690 const innerStartAdjustedRadius = innerRadius + innerStart;
15691 const innerEndAdjustedRadius = innerRadius + innerEnd;
15692 const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
15693 const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
15694 ctx.beginPath();
15695 if (circular) {
15696 // The first arc segments from point 1 to point a to point 2
15697 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;
15698 ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);
15699 ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);
15700 // The corner segment from point 2 to point 3
15701 if (outerEnd > 0) {
15702 const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
15703 ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15704 }
15705 // The line from point 3 to point 4
15706 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
15707 ctx.lineTo(p4.x, p4.y);
15708 // The corner segment from point 4 to point 5
15709 if (innerEnd > 0) {
15710 const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
15711 ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, innerEndAdjustedAngle + Math.PI);
15712 }
15713 // The inner arc from point 5 to point b to point 6
15714 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;
15715 ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);
15716 ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);
15717 // The corner segment from point 6 to point 7
15718 if (innerStart > 0) {
15719 const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
15720 ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H);
15721 }
15722 // The line from point 7 to point 8
15723 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
15724 ctx.lineTo(p8.x, p8.y);
15725 // The corner segment from point 8 to point 1
15726 if (outerStart > 0) {
15727 const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
15728 ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, outerStartAdjustedAngle);
15729 }
15730 } else {
15731 ctx.moveTo(x, y);
15732 const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;
15733 const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;
15734 ctx.lineTo(outerStartX, outerStartY);
15735 const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;
15736 const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;
15737 ctx.lineTo(outerEndX, outerEndY);
15738 }
15739 ctx.closePath();
15740 }
15741 function drawArc(ctx, element, offset, spacing, circular) {
15742 const { fullCircles , startAngle , circumference } = element;
15743 let endAngle = element.endAngle;
15744 if (fullCircles) {
15745 pathArc(ctx, element, offset, spacing, endAngle, circular);
15746 for(let i = 0; i < fullCircles; ++i){
15747 ctx.fill();
15748 }
15749 if (!isNaN(circumference)) {
15750 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15751 }
15752 }
15753 pathArc(ctx, element, offset, spacing, endAngle, circular);
15754 ctx.fill();
15755 return endAngle;
15756 }
15757 function drawBorder(ctx, element, offset, spacing, circular) {
15758 const { fullCircles , startAngle , circumference , options } = element;
15759 const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options;
15760 const inner = options.borderAlign === 'inner';
15761 if (!borderWidth) {
15762 return;
15763 }
15764 ctx.setLineDash(borderDash || []);
15765 ctx.lineDashOffset = borderDashOffset;
15766 if (inner) {
15767 ctx.lineWidth = borderWidth * 2;
15768 ctx.lineJoin = borderJoinStyle || 'round';
15769 } else {
15770 ctx.lineWidth = borderWidth;
15771 ctx.lineJoin = borderJoinStyle || 'bevel';
15772 }
15773 let endAngle = element.endAngle;
15774 if (fullCircles) {
15775 pathArc(ctx, element, offset, spacing, endAngle, circular);
15776 for(let i = 0; i < fullCircles; ++i){
15777 ctx.stroke();
15778 }
15779 if (!isNaN(circumference)) {
15780 endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
15781 }
15782 }
15783 if (inner) {
15784 clipArc(ctx, element, endAngle);
15785 }
15786 if (options.selfJoin && endAngle - startAngle >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P && borderRadius === 0 && borderJoinStyle !== 'miter') {
15787 clipSelf(ctx, element, endAngle);
15788 }
15789 if (!fullCircles) {
15790 pathArc(ctx, element, offset, spacing, endAngle, circular);
15791 ctx.stroke();
15792 }
15793 }
15794 class ArcElement extends Element {
15795 static id = 'arc';
15796 static defaults = {
15797 borderAlign: 'center',
15798 borderColor: '#fff',
15799 borderDash: [],
15800 borderDashOffset: 0,
15801 borderJoinStyle: undefined,
15802 borderRadius: 0,
15803 borderWidth: 2,
15804 offset: 0,
15805 spacing: 0,
15806 angle: undefined,
15807 circular: true,
15808 selfJoin: false
15809 };
15810 static defaultRoutes = {
15811 backgroundColor: 'backgroundColor'
15812 };
15813 static descriptors = {
15814 _scriptable: true,
15815 _indexable: (name)=>name !== 'borderDash'
15816 };
15817 circumference;
15818 endAngle;
15819 fullCircles;
15820 innerRadius;
15821 outerRadius;
15822 pixelMargin;
15823 startAngle;
15824 constructor(cfg){
15825 super();
15826 this.options = undefined;
15827 this.circumference = undefined;
15828 this.startAngle = undefined;
15829 this.endAngle = undefined;
15830 this.innerRadius = undefined;
15831 this.outerRadius = undefined;
15832 this.pixelMargin = 0;
15833 this.fullCircles = 0;
15834 if (cfg) {
15835 Object.assign(this, cfg);
15836 }
15837 }
15838 inRange(chartX, chartY, useFinalPosition) {
15839 const point = this.getProps([
15840 'x',
15841 'y'
15842 ], useFinalPosition);
15843 const { angle , distance } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(point, {
15844 x: chartX,
15845 y: chartY
15846 });
15847 const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([
15848 'startAngle',
15849 'endAngle',
15850 'innerRadius',
15851 'outerRadius',
15852 'circumference'
15853 ], useFinalPosition);
15854 const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;
15855 const _circumference = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(circumference, endAngle - startAngle);
15856 const nonZeroBetween = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle) && startAngle !== endAngle;
15857 const betweenAngles = _circumference >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || nonZeroBetween;
15858 const withinRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(distance, innerRadius + rAdjust, outerRadius + rAdjust);
15859 return betweenAngles && withinRadius;
15860 }
15861 getCenterPoint(useFinalPosition) {
15862 const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([
15863 'x',
15864 'y',
15865 'startAngle',
15866 'endAngle',
15867 'innerRadius',
15868 'outerRadius'
15869 ], useFinalPosition);
15870 const { offset , spacing } = this.options;
15871 const halfAngle = (startAngle + endAngle) / 2;
15872 const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
15873 return {
15874 x: x + Math.cos(halfAngle) * halfRadius,
15875 y: y + Math.sin(halfAngle) * halfRadius
15876 };
15877 }
15878 tooltipPosition(useFinalPosition) {
15879 return this.getCenterPoint(useFinalPosition);
15880 }
15881 draw(ctx) {
15882 const { options , circumference } = this;
15883 const offset = (options.offset || 0) / 4;
15884 const spacing = (options.spacing || 0) / 2;
15885 const circular = options.circular;
15886 this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0;
15887 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;
15888 if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
15889 return;
15890 }
15891 ctx.save();
15892 const halfAngle = (this.startAngle + this.endAngle) / 2;
15893 ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
15894 const fix = 1 - Math.sin(Math.min(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, circumference || 0));
15895 const radiusOffset = offset * fix;
15896 ctx.fillStyle = options.backgroundColor;
15897 ctx.strokeStyle = options.borderColor;
15898 drawArc(ctx, this, radiusOffset, spacing, circular);
15899 drawBorder(ctx, this, radiusOffset, spacing, circular);
15900 ctx.restore();
15901 }
15902 }
15903
15904 function setStyle(ctx, options, style = options) {
15905 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderCapStyle, options.borderCapStyle);
15906 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDash, options.borderDash));
15907 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDashOffset, options.borderDashOffset);
15908 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderJoinStyle, options.borderJoinStyle);
15909 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderWidth, options.borderWidth);
15910 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderColor, options.borderColor);
15911 }
15912 function lineTo(ctx, previous, target) {
15913 ctx.lineTo(target.x, target.y);
15914 }
15915 function getLineMethod(options) {
15916 if (options.stepped) {
15917 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.at;
15918 }
15919 if (options.tension || options.cubicInterpolationMode === 'monotone') {
15920 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.au;
15921 }
15922 return lineTo;
15923 }
15924 function pathVars(points, segment, params = {}) {
15925 const count = points.length;
15926 const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params;
15927 const { start: segmentStart , end: segmentEnd } = segment;
15928 const start = Math.max(paramsStart, segmentStart);
15929 const end = Math.min(paramsEnd, segmentEnd);
15930 const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;
15931 return {
15932 count,
15933 start,
15934 loop: segment.loop,
15935 ilen: end < start && !outside ? count + end - start : end - start
15936 };
15937 }
15938 function pathSegment(ctx, line, segment, params) {
15939 const { points , options } = line;
15940 const { count , start , loop , ilen } = pathVars(points, segment, params);
15941 const lineMethod = getLineMethod(options);
15942 let { move =true , reverse } = params || {};
15943 let i, point, prev;
15944 for(i = 0; i <= ilen; ++i){
15945 point = points[(start + (reverse ? ilen - i : i)) % count];
15946 if (point.skip) {
15947 continue;
15948 } else if (move) {
15949 ctx.moveTo(point.x, point.y);
15950 move = false;
15951 } else {
15952 lineMethod(ctx, prev, point, reverse, options.stepped);
15953 }
15954 prev = point;
15955 }
15956 if (loop) {
15957 point = points[(start + (reverse ? ilen : 0)) % count];
15958 lineMethod(ctx, prev, point, reverse, options.stepped);
15959 }
15960 return !!loop;
15961 }
15962 function fastPathSegment(ctx, line, segment, params) {
15963 const points = line.points;
15964 const { count , start , ilen } = pathVars(points, segment, params);
15965 const { move =true , reverse } = params || {};
15966 let avgX = 0;
15967 let countX = 0;
15968 let i, point, prevX, minY, maxY, lastY;
15969 const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count;
15970 const drawX = ()=>{
15971 if (minY !== maxY) {
15972 ctx.lineTo(avgX, maxY);
15973 ctx.lineTo(avgX, minY);
15974 ctx.lineTo(avgX, lastY);
15975 }
15976 };
15977 if (move) {
15978 point = points[pointIndex(0)];
15979 ctx.moveTo(point.x, point.y);
15980 }
15981 for(i = 0; i <= ilen; ++i){
15982 point = points[pointIndex(i)];
15983 if (point.skip) {
15984 continue;
15985 }
15986 const x = point.x;
15987 const y = point.y;
15988 const truncX = x | 0;
15989 if (truncX === prevX) {
15990 if (y < minY) {
15991 minY = y;
15992 } else if (y > maxY) {
15993 maxY = y;
15994 }
15995 avgX = (countX * avgX + x) / ++countX;
15996 } else {
15997 drawX();
15998 ctx.lineTo(x, y);
15999 prevX = truncX;
16000 countX = 0;
16001 minY = maxY = y;
16002 }
16003 lastY = y;
16004 }
16005 drawX();
16006 }
16007 function _getSegmentMethod(line) {
16008 const opts = line.options;
16009 const borderDash = opts.borderDash && opts.borderDash.length;
16010 const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;
16011 return useFastPath ? fastPathSegment : pathSegment;
16012 }
16013 function _getInterpolationMethod(options) {
16014 if (options.stepped) {
16015 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aq;
16016 }
16017 if (options.tension || options.cubicInterpolationMode === 'monotone') {
16018 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ar;
16019 }
16020 return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.as;
16021 }
16022 function strokePathWithCache(ctx, line, start, count) {
16023 let path = line._path;
16024 if (!path) {
16025 path = line._path = new Path2D();
16026 if (line.path(path, start, count)) {
16027 path.closePath();
16028 }
16029 }
16030 setStyle(ctx, line.options);
16031 ctx.stroke(path);
16032 }
16033 function strokePathDirect(ctx, line, start, count) {
16034 const { segments , options } = line;
16035 const segmentMethod = _getSegmentMethod(line);
16036 for (const segment of segments){
16037 setStyle(ctx, options, segment.style);
16038 ctx.beginPath();
16039 if (segmentMethod(ctx, line, segment, {
16040 start,
16041 end: start + count - 1
16042 })) {
16043 ctx.closePath();
16044 }
16045 ctx.stroke();
16046 }
16047 }
16048 const usePath2D = typeof Path2D === 'function';
16049 function draw(ctx, line, start, count) {
16050 if (usePath2D && !line.options.segment) {
16051 strokePathWithCache(ctx, line, start, count);
16052 } else {
16053 strokePathDirect(ctx, line, start, count);
16054 }
16055 }
16056 class LineElement extends Element {
16057 static id = 'line';
16058 static defaults = {
16059 borderCapStyle: 'butt',
16060 borderDash: [],
16061 borderDashOffset: 0,
16062 borderJoinStyle: 'miter',
16063 borderWidth: 3,
16064 capBezierPoints: true,
16065 cubicInterpolationMode: 'default',
16066 fill: false,
16067 spanGaps: false,
16068 stepped: false,
16069 tension: 0
16070 };
16071 static defaultRoutes = {
16072 backgroundColor: 'backgroundColor',
16073 borderColor: 'borderColor'
16074 };
16075 static descriptors = {
16076 _scriptable: true,
16077 _indexable: (name)=>name !== 'borderDash' && name !== 'fill'
16078 };
16079 constructor(cfg){
16080 super();
16081 this.animated = true;
16082 this.options = undefined;
16083 this._chart = undefined;
16084 this._loop = undefined;
16085 this._fullLoop = undefined;
16086 this._path = undefined;
16087 this._points = undefined;
16088 this._segments = undefined;
16089 this._decimated = false;
16090 this._pointsUpdated = false;
16091 this._datasetIndex = undefined;
16092 if (cfg) {
16093 Object.assign(this, cfg);
16094 }
16095 }
16096 updateControlPoints(chartArea, indexAxis) {
16097 const options = this.options;
16098 if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {
16099 const loop = options.spanGaps ? this._loop : this._fullLoop;
16100 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.an)(this._points, options, chartArea, loop, indexAxis);
16101 this._pointsUpdated = true;
16102 }
16103 }
16104 set points(points) {
16105 this._points = points;
16106 delete this._segments;
16107 delete this._path;
16108 this._pointsUpdated = false;
16109 }
16110 get points() {
16111 return this._points;
16112 }
16113 get segments() {
16114 return this._segments || (this._segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ao)(this, this.options.segment));
16115 }
16116 first() {
16117 const segments = this.segments;
16118 const points = this.points;
16119 return segments.length && points[segments[0].start];
16120 }
16121 last() {
16122 const segments = this.segments;
16123 const points = this.points;
16124 const count = segments.length;
16125 return count && points[segments[count - 1].end];
16126 }
16127 interpolate(point, property) {
16128 const options = this.options;
16129 const value = point[property];
16130 const points = this.points;
16131 const segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(this, {
16132 property,
16133 start: value,
16134 end: value
16135 });
16136 if (!segments.length) {
16137 return;
16138 }
16139 const result = [];
16140 const _interpolate = _getInterpolationMethod(options);
16141 let i, ilen;
16142 for(i = 0, ilen = segments.length; i < ilen; ++i){
16143 const { start , end } = segments[i];
16144 const p1 = points[start];
16145 const p2 = points[end];
16146 if (p1 === p2) {
16147 result.push(p1);
16148 continue;
16149 }
16150 const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
16151 const interpolated = _interpolate(p1, p2, t, options.stepped);
16152 interpolated[property] = point[property];
16153 result.push(interpolated);
16154 }
16155 return result.length === 1 ? result[0] : result;
16156 }
16157 pathSegment(ctx, segment, params) {
16158 const segmentMethod = _getSegmentMethod(this);
16159 return segmentMethod(ctx, this, segment, params);
16160 }
16161 path(ctx, start, count) {
16162 const segments = this.segments;
16163 const segmentMethod = _getSegmentMethod(this);
16164 let loop = this._loop;
16165 start = start || 0;
16166 count = count || this.points.length - start;
16167 for (const segment of segments){
16168 loop &= segmentMethod(ctx, this, segment, {
16169 start,
16170 end: start + count - 1
16171 });
16172 }
16173 return !!loop;
16174 }
16175 draw(ctx, chartArea, start, count) {
16176 const options = this.options || {};
16177 const points = this.points || [];
16178 if (points.length && options.borderWidth) {
16179 ctx.save();
16180 draw(ctx, this, start, count);
16181 ctx.restore();
16182 }
16183 if (this.animated) {
16184 this._pointsUpdated = false;
16185 this._path = undefined;
16186 }
16187 }
16188 }
16189
16190 function inRange$1(el, pos, axis, useFinalPosition) {
16191 const options = el.options;
16192 const { [axis]: value } = el.getProps([
16193 axis
16194 ], useFinalPosition);
16195 return Math.abs(pos - value) < options.radius + options.hitRadius;
16196 }
16197 class PointElement extends Element {
16198 static id = 'point';
16199 parsed;
16200 skip;
16201 stop;
16202 /**
16203 * @type {any}
16204 */ static defaults = {
16205 borderWidth: 1,
16206 hitRadius: 1,
16207 hoverBorderWidth: 1,
16208 hoverRadius: 4,
16209 pointStyle: 'circle',
16210 radius: 3,
16211 rotation: 0
16212 };
16213 /**
16214 * @type {any}
16215 */ static defaultRoutes = {
16216 backgroundColor: 'backgroundColor',
16217 borderColor: 'borderColor'
16218 };
16219 constructor(cfg){
16220 super();
16221 this.options = undefined;
16222 this.parsed = undefined;
16223 this.skip = undefined;
16224 this.stop = undefined;
16225 if (cfg) {
16226 Object.assign(this, cfg);
16227 }
16228 }
16229 inRange(mouseX, mouseY, useFinalPosition) {
16230 const options = this.options;
16231 const { x , y } = this.getProps([
16232 'x',
16233 'y'
16234 ], useFinalPosition);
16235 return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2);
16236 }
16237 inXRange(mouseX, useFinalPosition) {
16238 return inRange$1(this, mouseX, 'x', useFinalPosition);
16239 }
16240 inYRange(mouseY, useFinalPosition) {
16241 return inRange$1(this, mouseY, 'y', useFinalPosition);
16242 }
16243 getCenterPoint(useFinalPosition) {
16244 const { x , y } = this.getProps([
16245 'x',
16246 'y'
16247 ], useFinalPosition);
16248 return {
16249 x,
16250 y
16251 };
16252 }
16253 size(options) {
16254 options = options || this.options || {};
16255 let radius = options.radius || 0;
16256 radius = Math.max(radius, radius && options.hoverRadius || 0);
16257 const borderWidth = radius && options.borderWidth || 0;
16258 return (radius + borderWidth) * 2;
16259 }
16260 draw(ctx, area) {
16261 const options = this.options;
16262 if (this.skip || options.radius < 0.1 || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(this, area, this.size(options) / 2)) {
16263 return;
16264 }
16265 ctx.strokeStyle = options.borderColor;
16266 ctx.lineWidth = options.borderWidth;
16267 ctx.fillStyle = options.backgroundColor;
16268 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, options, this.x, this.y);
16269 }
16270 getRange() {
16271 const options = this.options || {};
16272 // @ts-expect-error Fallbacks should never be hit in practice
16273 return options.radius + options.hitRadius;
16274 }
16275 }
16276
16277 function getBarBounds(bar, useFinalPosition) {
16278 const { x , y , base , width , height } = bar.getProps([
16279 'x',
16280 'y',
16281 'base',
16282 'width',
16283 'height'
16284 ], useFinalPosition);
16285 let left, right, top, bottom, half;
16286 if (bar.horizontal) {
16287 half = height / 2;
16288 left = Math.min(x, base);
16289 right = Math.max(x, base);
16290 top = y - half;
16291 bottom = y + half;
16292 } else {
16293 half = width / 2;
16294 left = x - half;
16295 right = x + half;
16296 top = Math.min(y, base);
16297 bottom = Math.max(y, base);
16298 }
16299 return {
16300 left,
16301 top,
16302 right,
16303 bottom
16304 };
16305 }
16306 function skipOrLimit(skip, value, min, max) {
16307 return skip ? 0 : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(value, min, max);
16308 }
16309 function parseBorderWidth(bar, maxW, maxH) {
16310 const value = bar.options.borderWidth;
16311 const skip = bar.borderSkipped;
16312 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ax)(value);
16313 return {
16314 t: skipOrLimit(skip.top, o.top, 0, maxH),
16315 r: skipOrLimit(skip.right, o.right, 0, maxW),
16316 b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
16317 l: skipOrLimit(skip.left, o.left, 0, maxW)
16318 };
16319 }
16320 function parseBorderRadius(bar, maxW, maxH) {
16321 const { enableBorderRadius } = bar.getProps([
16322 'enableBorderRadius'
16323 ]);
16324 const value = bar.options.borderRadius;
16325 const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(value);
16326 const maxR = Math.min(maxW, maxH);
16327 const skip = bar.borderSkipped;
16328 const enableBorder = enableBorderRadius || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value);
16329 return {
16330 topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
16331 topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
16332 bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
16333 bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
16334 };
16335 }
16336 function boundingRects(bar) {
16337 const bounds = getBarBounds(bar);
16338 const width = bounds.right - bounds.left;
16339 const height = bounds.bottom - bounds.top;
16340 const border = parseBorderWidth(bar, width / 2, height / 2);
16341 const radius = parseBorderRadius(bar, width / 2, height / 2);
16342 return {
16343 outer: {
16344 x: bounds.left,
16345 y: bounds.top,
16346 w: width,
16347 h: height,
16348 radius
16349 },
16350 inner: {
16351 x: bounds.left + border.l,
16352 y: bounds.top + border.t,
16353 w: width - border.l - border.r,
16354 h: height - border.t - border.b,
16355 radius: {
16356 topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
16357 topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
16358 bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
16359 bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))
16360 }
16361 }
16362 };
16363 }
16364 function inRange(bar, x, y, useFinalPosition) {
16365 const skipX = x === null;
16366 const skipY = y === null;
16367 const skipBoth = skipX && skipY;
16368 const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
16369 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));
16370 }
16371 function hasRadius(radius) {
16372 return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
16373 }
16374 function addNormalRectPath(ctx, rect) {
16375 ctx.rect(rect.x, rect.y, rect.w, rect.h);
16376 }
16377 function inflateRect(rect, amount, refRect = {}) {
16378 const x = rect.x !== refRect.x ? -amount : 0;
16379 const y = rect.y !== refRect.y ? -amount : 0;
16380 const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;
16381 const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;
16382 return {
16383 x: rect.x + x,
16384 y: rect.y + y,
16385 w: rect.w + w,
16386 h: rect.h + h,
16387 radius: rect.radius
16388 };
16389 }
16390 class BarElement extends Element {
16391 static id = 'bar';
16392 static defaults = {
16393 borderSkipped: 'start',
16394 borderWidth: 0,
16395 borderRadius: 0,
16396 inflateAmount: 'auto',
16397 pointStyle: undefined
16398 };
16399 static defaultRoutes = {
16400 backgroundColor: 'backgroundColor',
16401 borderColor: 'borderColor'
16402 };
16403 constructor(cfg){
16404 super();
16405 this.options = undefined;
16406 this.horizontal = undefined;
16407 this.base = undefined;
16408 this.width = undefined;
16409 this.height = undefined;
16410 this.inflateAmount = undefined;
16411 if (cfg) {
16412 Object.assign(this, cfg);
16413 }
16414 }
16415 draw(ctx) {
16416 const { inflateAmount , options: { borderColor , backgroundColor } } = this;
16417 const { inner , outer } = boundingRects(this);
16418 const addRectPath = hasRadius(outer.radius) ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw : addNormalRectPath;
16419 ctx.save();
16420 if (outer.w !== inner.w || outer.h !== inner.h) {
16421 ctx.beginPath();
16422 addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
16423 ctx.clip();
16424 addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
16425 ctx.fillStyle = borderColor;
16426 ctx.fill('evenodd');
16427 }
16428 ctx.beginPath();
16429 addRectPath(ctx, inflateRect(inner, inflateAmount));
16430 ctx.fillStyle = backgroundColor;
16431 ctx.fill();
16432 ctx.restore();
16433 }
16434 inRange(mouseX, mouseY, useFinalPosition) {
16435 return inRange(this, mouseX, mouseY, useFinalPosition);
16436 }
16437 inXRange(mouseX, useFinalPosition) {
16438 return inRange(this, mouseX, null, useFinalPosition);
16439 }
16440 inYRange(mouseY, useFinalPosition) {
16441 return inRange(this, null, mouseY, useFinalPosition);
16442 }
16443 getCenterPoint(useFinalPosition) {
16444 const { x , y , base , horizontal } = this.getProps([
16445 'x',
16446 'y',
16447 'base',
16448 'horizontal'
16449 ], useFinalPosition);
16450 return {
16451 x: horizontal ? (x + base) / 2 : x,
16452 y: horizontal ? y : (y + base) / 2
16453 };
16454 }
16455 getRange(axis) {
16456 return axis === 'x' ? this.width / 2 : this.height / 2;
16457 }
16458 }
16459
16460 var elements = /*#__PURE__*/Object.freeze({
16461 __proto__: null,
16462 ArcElement: ArcElement,
16463 BarElement: BarElement,
16464 LineElement: LineElement,
16465 PointElement: PointElement
16466 });
16467
16468 const BORDER_COLORS = [
16469 'rgb(54, 162, 235)',
16470 'rgb(255, 99, 132)',
16471 'rgb(255, 159, 64)',
16472 'rgb(255, 205, 86)',
16473 'rgb(75, 192, 192)',
16474 'rgb(153, 102, 255)',
16475 'rgb(201, 203, 207)' // grey
16476 ];
16477 // Border colors with 50% transparency
16478 const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)'));
16479 function getBorderColor(i) {
16480 return BORDER_COLORS[i % BORDER_COLORS.length];
16481 }
16482 function getBackgroundColor(i) {
16483 return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length];
16484 }
16485 function colorizeDefaultDataset(dataset, i) {
16486 dataset.borderColor = getBorderColor(i);
16487 dataset.backgroundColor = getBackgroundColor(i);
16488 return ++i;
16489 }
16490 function colorizeDoughnutDataset(dataset, i) {
16491 dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++));
16492 return i;
16493 }
16494 function colorizePolarAreaDataset(dataset, i) {
16495 dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++));
16496 return i;
16497 }
16498 function getColorizer(chart) {
16499 let i = 0;
16500 return (dataset, datasetIndex)=>{
16501 const controller = chart.getDatasetMeta(datasetIndex).controller;
16502 if (controller instanceof DoughnutController) {
16503 i = colorizeDoughnutDataset(dataset, i);
16504 } else if (controller instanceof PolarAreaController) {
16505 i = colorizePolarAreaDataset(dataset, i);
16506 } else if (controller) {
16507 i = colorizeDefaultDataset(dataset, i);
16508 }
16509 };
16510 }
16511 function containsColorsDefinitions(descriptors) {
16512 let k;
16513 for(k in descriptors){
16514 if (descriptors[k].borderColor || descriptors[k].backgroundColor) {
16515 return true;
16516 }
16517 }
16518 return false;
16519 }
16520 function containsColorsDefinition(descriptor) {
16521 return descriptor && (descriptor.borderColor || descriptor.backgroundColor);
16522 }
16523 function containsDefaultColorsDefenitions() {
16524 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)';
16525 }
16526 var plugin_colors = {
16527 id: 'colors',
16528 defaults: {
16529 enabled: true,
16530 forceOverride: false
16531 },
16532 beforeLayout (chart, _args, options) {
16533 if (!options.enabled) {
16534 return;
16535 }
16536 const { data: { datasets } , options: chartOptions } = chart.config;
16537 const { elements } = chartOptions;
16538 const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions();
16539 if (!options.forceOverride && containsColorDefenition) {
16540 return;
16541 }
16542 const colorizer = getColorizer(chart);
16543 datasets.forEach(colorizer);
16544 }
16545 };
16546
16547 function lttbDecimation(data, start, count, availableWidth, options) {
16548 const samples = options.samples || availableWidth;
16549 if (samples >= count) {
16550 return data.slice(start, start + count);
16551 }
16552 const decimated = [];
16553 const bucketWidth = (count - 2) / (samples - 2);
16554 let sampledIndex = 0;
16555 const endIndex = start + count - 1;
16556 let a = start;
16557 let i, maxAreaPoint, maxArea, area, nextA;
16558 decimated[sampledIndex++] = data[a];
16559 for(i = 0; i < samples - 2; i++){
16560 let avgX = 0;
16561 let avgY = 0;
16562 let j;
16563 const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;
16564 const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;
16565 const avgRangeLength = avgRangeEnd - avgRangeStart;
16566 for(j = avgRangeStart; j < avgRangeEnd; j++){
16567 avgX += data[j].x;
16568 avgY += data[j].y;
16569 }
16570 avgX /= avgRangeLength;
16571 avgY /= avgRangeLength;
16572 const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;
16573 const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;
16574 const { x: pointAx , y: pointAy } = data[a];
16575 maxArea = area = -1;
16576 for(j = rangeOffs; j < rangeTo; j++){
16577 area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy));
16578 if (area > maxArea) {
16579 maxArea = area;
16580 maxAreaPoint = data[j];
16581 nextA = j;
16582 }
16583 }
16584 decimated[sampledIndex++] = maxAreaPoint;
16585 a = nextA;
16586 }
16587 decimated[sampledIndex++] = data[endIndex];
16588 return decimated;
16589 }
16590 function minMaxDecimation(data, start, count, availableWidth) {
16591 let avgX = 0;
16592 let countX = 0;
16593 let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
16594 const decimated = [];
16595 const endIndex = start + count - 1;
16596 const xMin = data[start].x;
16597 const xMax = data[endIndex].x;
16598 const dx = xMax - xMin;
16599 for(i = start; i < start + count; ++i){
16600 point = data[i];
16601 x = (point.x - xMin) / dx * availableWidth;
16602 y = point.y;
16603 const truncX = x | 0;
16604 if (truncX === prevX) {
16605 if (y < minY) {
16606 minY = y;
16607 minIndex = i;
16608 } else if (y > maxY) {
16609 maxY = y;
16610 maxIndex = i;
16611 }
16612 avgX = (countX * avgX + point.x) / ++countX;
16613 } else {
16614 const lastIndex = i - 1;
16615 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(minIndex) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(maxIndex)) {
16616 const intermediateIndex1 = Math.min(minIndex, maxIndex);
16617 const intermediateIndex2 = Math.max(minIndex, maxIndex);
16618 if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
16619 decimated.push({
16620 ...data[intermediateIndex1],
16621 x: avgX
16622 });
16623 }
16624 if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
16625 decimated.push({
16626 ...data[intermediateIndex2],
16627 x: avgX
16628 });
16629 }
16630 }
16631 if (i > 0 && lastIndex !== startIndex) {
16632 decimated.push(data[lastIndex]);
16633 }
16634 decimated.push(point);
16635 prevX = truncX;
16636 countX = 0;
16637 minY = maxY = y;
16638 minIndex = maxIndex = startIndex = i;
16639 }
16640 }
16641 return decimated;
16642 }
16643 function cleanDecimatedDataset(dataset) {
16644 if (dataset._decimated) {
16645 const data = dataset._data;
16646 delete dataset._decimated;
16647 delete dataset._data;
16648 Object.defineProperty(dataset, 'data', {
16649 configurable: true,
16650 enumerable: true,
16651 writable: true,
16652 value: data
16653 });
16654 }
16655 }
16656 function cleanDecimatedData(chart) {
16657 chart.data.datasets.forEach((dataset)=>{
16658 cleanDecimatedDataset(dataset);
16659 });
16660 }
16661 function getStartAndCountOfVisiblePointsSimplified(meta, points) {
16662 const pointCount = points.length;
16663 let start = 0;
16664 let count;
16665 const { iScale } = meta;
16666 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
16667 if (minDefined) {
16668 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);
16669 }
16670 if (maxDefined) {
16671 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;
16672 } else {
16673 count = pointCount - start;
16674 }
16675 return {
16676 start,
16677 count
16678 };
16679 }
16680 var plugin_decimation = {
16681 id: 'decimation',
16682 defaults: {
16683 algorithm: 'min-max',
16684 enabled: false
16685 },
16686 beforeElementsUpdate: (chart, args, options)=>{
16687 if (!options.enabled) {
16688 cleanDecimatedData(chart);
16689 return;
16690 }
16691 const availableWidth = chart.width;
16692 chart.data.datasets.forEach((dataset, datasetIndex)=>{
16693 const { _data , indexAxis } = dataset;
16694 const meta = chart.getDatasetMeta(datasetIndex);
16695 const data = _data || dataset.data;
16696 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([
16697 indexAxis,
16698 chart.options.indexAxis
16699 ]) === 'y') {
16700 return;
16701 }
16702 if (!meta.controller.supportsDecimation) {
16703 return;
16704 }
16705 const xAxis = chart.scales[meta.xAxisID];
16706 if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
16707 return;
16708 }
16709 if (chart.options.parsing) {
16710 return;
16711 }
16712 let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data);
16713 const threshold = options.threshold || 4 * availableWidth;
16714 if (count <= threshold) {
16715 cleanDecimatedDataset(dataset);
16716 return;
16717 }
16718 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(_data)) {
16719 dataset._data = data;
16720 delete dataset.data;
16721 Object.defineProperty(dataset, 'data', {
16722 configurable: true,
16723 enumerable: true,
16724 get: function() {
16725 return this._decimated;
16726 },
16727 set: function(d) {
16728 this._data = d;
16729 }
16730 });
16731 }
16732 let decimated;
16733 switch(options.algorithm){
16734 case 'lttb':
16735 decimated = lttbDecimation(data, start, count, availableWidth, options);
16736 break;
16737 case 'min-max':
16738 decimated = minMaxDecimation(data, start, count, availableWidth);
16739 break;
16740 default:
16741 throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
16742 }
16743 dataset._decimated = decimated;
16744 });
16745 },
16746 destroy (chart) {
16747 cleanDecimatedData(chart);
16748 }
16749 };
16750
16751 function _segments(line, target, property) {
16752 const segments = line.segments;
16753 const points = line.points;
16754 const tpoints = target.points;
16755 const parts = [];
16756 for (const segment of segments){
16757 let { start , end } = segment;
16758 end = _findSegmentEnd(start, end, points);
16759 const bounds = _getBounds(property, points[start], points[end], segment.loop);
16760 if (!target.segments) {
16761 parts.push({
16762 source: segment,
16763 target: bounds,
16764 start: points[start],
16765 end: points[end]
16766 });
16767 continue;
16768 }
16769 const targetSegments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(target, bounds);
16770 for (const tgt of targetSegments){
16771 const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);
16772 const fillSources = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.az)(segment, points, subBounds);
16773 for (const fillSource of fillSources){
16774 parts.push({
16775 source: fillSource,
16776 target: tgt,
16777 start: {
16778 [property]: _getEdge(bounds, subBounds, 'start', Math.max)
16779 },
16780 end: {
16781 [property]: _getEdge(bounds, subBounds, 'end', Math.min)
16782 }
16783 });
16784 }
16785 }
16786 }
16787 return parts;
16788 }
16789 function _getBounds(property, first, last, loop) {
16790 if (loop) {
16791 return;
16792 }
16793 let start = first[property];
16794 let end = last[property];
16795 if (property === 'angle') {
16796 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(start);
16797 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(end);
16798 }
16799 return {
16800 property,
16801 start,
16802 end
16803 };
16804 }
16805 function _pointsFromSegments(boundary, line) {
16806 const { x =null , y =null } = boundary || {};
16807 const linePoints = line.points;
16808 const points = [];
16809 line.segments.forEach(({ start , end })=>{
16810 end = _findSegmentEnd(start, end, linePoints);
16811 const first = linePoints[start];
16812 const last = linePoints[end];
16813 if (y !== null) {
16814 points.push({
16815 x: first.x,
16816 y
16817 });
16818 points.push({
16819 x: last.x,
16820 y
16821 });
16822 } else if (x !== null) {
16823 points.push({
16824 x,
16825 y: first.y
16826 });
16827 points.push({
16828 x,
16829 y: last.y
16830 });
16831 }
16832 });
16833 return points;
16834 }
16835 function _findSegmentEnd(start, end, points) {
16836 for(; end > start; end--){
16837 const point = points[end];
16838 if (!isNaN(point.x) && !isNaN(point.y)) {
16839 break;
16840 }
16841 }
16842 return end;
16843 }
16844 function _getEdge(a, b, prop, fn) {
16845 if (a && b) {
16846 return fn(a[prop], b[prop]);
16847 }
16848 return a ? a[prop] : b ? b[prop] : 0;
16849 }
16850
16851 function _createBoundaryLine(boundary, line) {
16852 let points = [];
16853 let _loop = false;
16854 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(boundary)) {
16855 _loop = true;
16856 points = boundary;
16857 } else {
16858 points = _pointsFromSegments(boundary, line);
16859 }
16860 return points.length ? new LineElement({
16861 points,
16862 options: {
16863 tension: 0
16864 },
16865 _loop,
16866 _fullLoop: _loop
16867 }) : null;
16868 }
16869 function _shouldApplyFill(source) {
16870 return source && source.fill !== false;
16871 }
16872
16873 function _resolveTarget(sources, index, propagate) {
16874 const source = sources[index];
16875 let fill = source.fill;
16876 const visited = [
16877 index
16878 ];
16879 let target;
16880 if (!propagate) {
16881 return fill;
16882 }
16883 while(fill !== false && visited.indexOf(fill) === -1){
16884 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
16885 return fill;
16886 }
16887 target = sources[fill];
16888 if (!target) {
16889 return false;
16890 }
16891 if (target.visible) {
16892 return fill;
16893 }
16894 visited.push(fill);
16895 fill = target.fill;
16896 }
16897 return false;
16898 }
16899 function _decodeFill(line, index, count) {
16900 const fill = parseFillOption(line);
16901 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16902 return isNaN(fill.value) ? false : fill;
16903 }
16904 let target = parseFloat(fill);
16905 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(target) && Math.floor(target) === target) {
16906 return decodeTargetIndex(fill[0], index, target, count);
16907 }
16908 return [
16909 'origin',
16910 'start',
16911 'end',
16912 'stack',
16913 'shape'
16914 ].indexOf(fill) >= 0 && fill;
16915 }
16916 function decodeTargetIndex(firstCh, index, target, count) {
16917 if (firstCh === '-' || firstCh === '+') {
16918 target = index + target;
16919 }
16920 if (target === index || target < 0 || target >= count) {
16921 return false;
16922 }
16923 return target;
16924 }
16925 function _getTargetPixel(fill, scale) {
16926 let pixel = null;
16927 if (fill === 'start') {
16928 pixel = scale.bottom;
16929 } else if (fill === 'end') {
16930 pixel = scale.top;
16931 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16932 pixel = scale.getPixelForValue(fill.value);
16933 } else if (scale.getBasePixel) {
16934 pixel = scale.getBasePixel();
16935 }
16936 return pixel;
16937 }
16938 function _getTargetValue(fill, scale, startValue) {
16939 let value;
16940 if (fill === 'start') {
16941 value = startValue;
16942 } else if (fill === 'end') {
16943 value = scale.options.reverse ? scale.min : scale.max;
16944 } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) {
16945 value = fill.value;
16946 } else {
16947 value = scale.getBaseValue();
16948 }
16949 return value;
16950 }
16951 function parseFillOption(line) {
16952 const options = line.options;
16953 const fillOption = options.fill;
16954 let fill = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(fillOption && fillOption.target, fillOption);
16955 if (fill === undefined) {
16956 fill = !!options.backgroundColor;
16957 }
16958 if (fill === false || fill === null) {
16959 return false;
16960 }
16961 if (fill === true) {
16962 return 'origin';
16963 }
16964 return fill;
16965 }
16966
16967 function _buildStackLine(source) {
16968 const { scale , index , line } = source;
16969 const points = [];
16970 const segments = line.segments;
16971 const sourcePoints = line.points;
16972 const linesBelow = getLinesBelow(scale, index);
16973 linesBelow.push(_createBoundaryLine({
16974 x: null,
16975 y: scale.bottom
16976 }, line));
16977 for(let i = 0; i < segments.length; i++){
16978 const segment = segments[i];
16979 for(let j = segment.start; j <= segment.end; j++){
16980 addPointsBelow(points, sourcePoints[j], linesBelow);
16981 }
16982 }
16983 return new LineElement({
16984 points,
16985 options: {}
16986 });
16987 }
16988 function getLinesBelow(scale, index) {
16989 const below = [];
16990 const metas = scale.getMatchingVisibleMetas('line');
16991 for(let i = 0; i < metas.length; i++){
16992 const meta = metas[i];
16993 if (meta.index === index) {
16994 break;
16995 }
16996 if (!meta.hidden) {
16997 below.unshift(meta.dataset);
16998 }
16999 }
17000 return below;
17001 }
17002 function addPointsBelow(points, sourcePoint, linesBelow) {
17003 const postponed = [];
17004 for(let j = 0; j < linesBelow.length; j++){
17005 const line = linesBelow[j];
17006 const { first , last , point } = findPoint(line, sourcePoint, 'x');
17007 if (!point || first && last) {
17008 continue;
17009 }
17010 if (first) {
17011 postponed.unshift(point);
17012 } else {
17013 points.push(point);
17014 if (!last) {
17015 break;
17016 }
17017 }
17018 }
17019 points.push(...postponed);
17020 }
17021 function findPoint(line, sourcePoint, property) {
17022 const point = line.interpolate(sourcePoint, property);
17023 if (!point) {
17024 return {};
17025 }
17026 const pointValue = point[property];
17027 const segments = line.segments;
17028 const linePoints = line.points;
17029 let first = false;
17030 let last = false;
17031 for(let i = 0; i < segments.length; i++){
17032 const segment = segments[i];
17033 const firstValue = linePoints[segment.start][property];
17034 const lastValue = linePoints[segment.end][property];
17035 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(pointValue, firstValue, lastValue)) {
17036 first = pointValue === firstValue;
17037 last = pointValue === lastValue;
17038 break;
17039 }
17040 }
17041 return {
17042 first,
17043 last,
17044 point
17045 };
17046 }
17047
17048 class simpleArc {
17049 constructor(opts){
17050 this.x = opts.x;
17051 this.y = opts.y;
17052 this.radius = opts.radius;
17053 }
17054 pathSegment(ctx, bounds, opts) {
17055 const { x , y , radius } = this;
17056 bounds = bounds || {
17057 start: 0,
17058 end: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T
17059 };
17060 ctx.arc(x, y, radius, bounds.end, bounds.start, true);
17061 return !opts.bounds;
17062 }
17063 interpolate(point) {
17064 const { x , y , radius } = this;
17065 const angle = point.angle;
17066 return {
17067 x: x + Math.cos(angle) * radius,
17068 y: y + Math.sin(angle) * radius,
17069 angle
17070 };
17071 }
17072 }
17073
17074 function _getTarget(source) {
17075 const { chart , fill , line } = source;
17076 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) {
17077 return getLineByIndex(chart, fill);
17078 }
17079 if (fill === 'stack') {
17080 return _buildStackLine(source);
17081 }
17082 if (fill === 'shape') {
17083 return true;
17084 }
17085 const boundary = computeBoundary(source);
17086 if (boundary instanceof simpleArc) {
17087 return boundary;
17088 }
17089 return _createBoundaryLine(boundary, line);
17090 }
17091 function getLineByIndex(chart, index) {
17092 const meta = chart.getDatasetMeta(index);
17093 const visible = meta && chart.isDatasetVisible(index);
17094 return visible ? meta.dataset : null;
17095 }
17096 function computeBoundary(source) {
17097 const scale = source.scale || {};
17098 if (scale.getPointPositionForValue) {
17099 return computeCircularBoundary(source);
17100 }
17101 return computeLinearBoundary(source);
17102 }
17103 function computeLinearBoundary(source) {
17104 const { scale ={} , fill } = source;
17105 const pixel = _getTargetPixel(fill, scale);
17106 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(pixel)) {
17107 const horizontal = scale.isHorizontal();
17108 return {
17109 x: horizontal ? pixel : null,
17110 y: horizontal ? null : pixel
17111 };
17112 }
17113 return null;
17114 }
17115 function computeCircularBoundary(source) {
17116 const { scale , fill } = source;
17117 const options = scale.options;
17118 const length = scale.getLabels().length;
17119 const start = options.reverse ? scale.max : scale.min;
17120 const value = _getTargetValue(fill, scale, start);
17121 const target = [];
17122 if (options.grid.circular) {
17123 const center = scale.getPointPositionForValue(0, start);
17124 return new simpleArc({
17125 x: center.x,
17126 y: center.y,
17127 radius: scale.getDistanceFromCenterForValue(value)
17128 });
17129 }
17130 for(let i = 0; i < length; ++i){
17131 target.push(scale.getPointPositionForValue(i, value));
17132 }
17133 return target;
17134 }
17135
17136 function _drawfill(ctx, source, area) {
17137 const target = _getTarget(source);
17138 const { chart , index , line , scale , axis } = source;
17139 const lineOpts = line.options;
17140 const fillOption = lineOpts.fill;
17141 const color = lineOpts.backgroundColor;
17142 const { above =color , below =color } = fillOption || {};
17143 const meta = chart.getDatasetMeta(index);
17144 const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(chart, meta);
17145 if (target && line.points.length) {
17146 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area);
17147 doFill(ctx, {
17148 line,
17149 target,
17150 above,
17151 below,
17152 area,
17153 scale,
17154 axis,
17155 clip
17156 });
17157 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17158 }
17159 }
17160 function doFill(ctx, cfg) {
17161 const { line , target , above , below , area , scale , clip } = cfg;
17162 const property = line._loop ? 'angle' : cfg.axis;
17163 ctx.save();
17164 let fillColor = below;
17165 if (below !== above) {
17166 if (property === 'x') {
17167 clipVertical(ctx, target, area.top);
17168 fill(ctx, {
17169 line,
17170 target,
17171 color: above,
17172 scale,
17173 property,
17174 clip
17175 });
17176 ctx.restore();
17177 ctx.save();
17178 clipVertical(ctx, target, area.bottom);
17179 } else if (property === 'y') {
17180 clipHorizontal(ctx, target, area.left);
17181 fill(ctx, {
17182 line,
17183 target,
17184 color: below,
17185 scale,
17186 property,
17187 clip
17188 });
17189 ctx.restore();
17190 ctx.save();
17191 clipHorizontal(ctx, target, area.right);
17192 fillColor = above;
17193 }
17194 }
17195 fill(ctx, {
17196 line,
17197 target,
17198 color: fillColor,
17199 scale,
17200 property,
17201 clip
17202 });
17203 ctx.restore();
17204 }
17205 function clipVertical(ctx, target, clipY) {
17206 const { segments , points } = target;
17207 let first = true;
17208 let lineLoop = false;
17209 ctx.beginPath();
17210 for (const segment of segments){
17211 const { start , end } = segment;
17212 const firstPoint = points[start];
17213 const lastPoint = points[_findSegmentEnd(start, end, points)];
17214 if (first) {
17215 ctx.moveTo(firstPoint.x, firstPoint.y);
17216 first = false;
17217 } else {
17218 ctx.lineTo(firstPoint.x, clipY);
17219 ctx.lineTo(firstPoint.x, firstPoint.y);
17220 }
17221 lineLoop = !!target.pathSegment(ctx, segment, {
17222 move: lineLoop
17223 });
17224 if (lineLoop) {
17225 ctx.closePath();
17226 } else {
17227 ctx.lineTo(lastPoint.x, clipY);
17228 }
17229 }
17230 ctx.lineTo(target.first().x, clipY);
17231 ctx.closePath();
17232 ctx.clip();
17233 }
17234 function clipHorizontal(ctx, target, clipX) {
17235 const { segments , points } = target;
17236 let first = true;
17237 let lineLoop = false;
17238 ctx.beginPath();
17239 for (const segment of segments){
17240 const { start , end } = segment;
17241 const firstPoint = points[start];
17242 const lastPoint = points[_findSegmentEnd(start, end, points)];
17243 if (first) {
17244 ctx.moveTo(firstPoint.x, firstPoint.y);
17245 first = false;
17246 } else {
17247 ctx.lineTo(clipX, firstPoint.y);
17248 ctx.lineTo(firstPoint.x, firstPoint.y);
17249 }
17250 lineLoop = !!target.pathSegment(ctx, segment, {
17251 move: lineLoop
17252 });
17253 if (lineLoop) {
17254 ctx.closePath();
17255 } else {
17256 ctx.lineTo(clipX, lastPoint.y);
17257 }
17258 }
17259 ctx.lineTo(clipX, target.first().y);
17260 ctx.closePath();
17261 ctx.clip();
17262 }
17263 function fill(ctx, cfg) {
17264 const { line , target , property , color , scale , clip } = cfg;
17265 const segments = _segments(line, target, property);
17266 for (const { source: src , target: tgt , start , end } of segments){
17267 const { style: { backgroundColor =color } = {} } = src;
17268 const notShape = target !== true;
17269 ctx.save();
17270 ctx.fillStyle = backgroundColor;
17271 clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end));
17272 ctx.beginPath();
17273 const lineLoop = !!line.pathSegment(ctx, src);
17274 let loop;
17275 if (notShape) {
17276 if (lineLoop) {
17277 ctx.closePath();
17278 } else {
17279 interpolatedLineTo(ctx, target, end, property);
17280 }
17281 const targetLoop = !!target.pathSegment(ctx, tgt, {
17282 move: lineLoop,
17283 reverse: true
17284 });
17285 loop = lineLoop && targetLoop;
17286 if (!loop) {
17287 interpolatedLineTo(ctx, target, start, property);
17288 }
17289 }
17290 ctx.closePath();
17291 ctx.fill(loop ? 'evenodd' : 'nonzero');
17292 ctx.restore();
17293 }
17294 }
17295 function clipBounds(ctx, scale, clip, bounds) {
17296 const chartArea = scale.chart.chartArea;
17297 const { property , start , end } = bounds || {};
17298 if (property === 'x' || property === 'y') {
17299 let left, top, right, bottom;
17300 if (property === 'x') {
17301 left = start;
17302 top = chartArea.top;
17303 right = end;
17304 bottom = chartArea.bottom;
17305 } else {
17306 left = chartArea.left;
17307 top = start;
17308 right = chartArea.right;
17309 bottom = end;
17310 }
17311 ctx.beginPath();
17312 if (clip) {
17313 left = Math.max(left, clip.left);
17314 right = Math.min(right, clip.right);
17315 top = Math.max(top, clip.top);
17316 bottom = Math.min(bottom, clip.bottom);
17317 }
17318 ctx.rect(left, top, right - left, bottom - top);
17319 ctx.clip();
17320 }
17321 }
17322 function interpolatedLineTo(ctx, target, point, property) {
17323 const interpolatedPoint = target.interpolate(point, property);
17324 if (interpolatedPoint) {
17325 ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
17326 }
17327 }
17328
17329 var index = {
17330 id: 'filler',
17331 afterDatasetsUpdate (chart, _args, options) {
17332 const count = (chart.data.datasets || []).length;
17333 const sources = [];
17334 let meta, i, line, source;
17335 for(i = 0; i < count; ++i){
17336 meta = chart.getDatasetMeta(i);
17337 line = meta.dataset;
17338 source = null;
17339 if (line && line.options && line instanceof LineElement) {
17340 source = {
17341 visible: chart.isDatasetVisible(i),
17342 index: i,
17343 fill: _decodeFill(line, i, count),
17344 chart,
17345 axis: meta.controller.options.indexAxis,
17346 scale: meta.vScale,
17347 line
17348 };
17349 }
17350 meta.$filler = source;
17351 sources.push(source);
17352 }
17353 for(i = 0; i < count; ++i){
17354 source = sources[i];
17355 if (!source || source.fill === false) {
17356 continue;
17357 }
17358 source.fill = _resolveTarget(sources, i, options.propagate);
17359 }
17360 },
17361 beforeDraw (chart, _args, options) {
17362 const draw = options.drawTime === 'beforeDraw';
17363 const metasets = chart.getSortedVisibleDatasetMetas();
17364 const area = chart.chartArea;
17365 for(let i = metasets.length - 1; i >= 0; --i){
17366 const source = metasets[i].$filler;
17367 if (!source) {
17368 continue;
17369 }
17370 source.line.updateControlPoints(area, source.axis);
17371 if (draw && source.fill) {
17372 _drawfill(chart.ctx, source, area);
17373 }
17374 }
17375 },
17376 beforeDatasetsDraw (chart, _args, options) {
17377 if (options.drawTime !== 'beforeDatasetsDraw') {
17378 return;
17379 }
17380 const metasets = chart.getSortedVisibleDatasetMetas();
17381 for(let i = metasets.length - 1; i >= 0; --i){
17382 const source = metasets[i].$filler;
17383 if (_shouldApplyFill(source)) {
17384 _drawfill(chart.ctx, source, chart.chartArea);
17385 }
17386 }
17387 },
17388 beforeDatasetDraw (chart, args, options) {
17389 const source = args.meta.$filler;
17390 if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') {
17391 return;
17392 }
17393 _drawfill(chart.ctx, source, chart.chartArea);
17394 },
17395 defaults: {
17396 propagate: true,
17397 drawTime: 'beforeDatasetDraw'
17398 }
17399 };
17400
17401 const getBoxSize = (labelOpts, fontSize)=>{
17402 let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts;
17403 if (labelOpts.usePointStyle) {
17404 boxHeight = Math.min(boxHeight, fontSize);
17405 boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);
17406 }
17407 return {
17408 boxWidth,
17409 boxHeight,
17410 itemHeight: Math.max(fontSize, boxHeight)
17411 };
17412 };
17413 const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
17414 class Legend extends Element {
17415 constructor(config){
17416 super();
17417 this._added = false;
17418 this.legendHitBoxes = [];
17419 this._hoveredItem = null;
17420 this.doughnutMode = false;
17421 this.chart = config.chart;
17422 this.options = config.options;
17423 this.ctx = config.ctx;
17424 this.legendItems = undefined;
17425 this.columnSizes = undefined;
17426 this.lineWidths = undefined;
17427 this.maxHeight = undefined;
17428 this.maxWidth = undefined;
17429 this.top = undefined;
17430 this.bottom = undefined;
17431 this.left = undefined;
17432 this.right = undefined;
17433 this.height = undefined;
17434 this.width = undefined;
17435 this._margins = undefined;
17436 this.position = undefined;
17437 this.weight = undefined;
17438 this.fullSize = undefined;
17439 }
17440 update(maxWidth, maxHeight, margins) {
17441 this.maxWidth = maxWidth;
17442 this.maxHeight = maxHeight;
17443 this._margins = margins;
17444 this.setDimensions();
17445 this.buildLabels();
17446 this.fit();
17447 }
17448 setDimensions() {
17449 if (this.isHorizontal()) {
17450 this.width = this.maxWidth;
17451 this.left = this._margins.left;
17452 this.right = this.width;
17453 } else {
17454 this.height = this.maxHeight;
17455 this.top = this._margins.top;
17456 this.bottom = this.height;
17457 }
17458 }
17459 buildLabels() {
17460 const labelOpts = this.options.labels || {};
17461 let legendItems = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(labelOpts.generateLabels, [
17462 this.chart
17463 ], this) || [];
17464 if (labelOpts.filter) {
17465 legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data));
17466 }
17467 if (labelOpts.sort) {
17468 legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data));
17469 }
17470 if (this.options.reverse) {
17471 legendItems.reverse();
17472 }
17473 this.legendItems = legendItems;
17474 }
17475 fit() {
17476 const { options , ctx } = this;
17477 if (!options.display) {
17478 this.width = this.height = 0;
17479 return;
17480 }
17481 const labelOpts = options.labels;
17482 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17483 const fontSize = labelFont.size;
17484 const titleHeight = this._computeTitleHeight();
17485 const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize);
17486 let width, height;
17487 ctx.font = labelFont.string;
17488 if (this.isHorizontal()) {
17489 width = this.maxWidth;
17490 height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
17491 } else {
17492 height = this.maxHeight;
17493 width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;
17494 }
17495 this.width = Math.min(width, options.maxWidth || this.maxWidth);
17496 this.height = Math.min(height, options.maxHeight || this.maxHeight);
17497 }
17498 _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
17499 const { ctx , maxWidth , options: { labels: { padding } } } = this;
17500 const hitboxes = this.legendHitBoxes = [];
17501 const lineWidths = this.lineWidths = [
17502 0
17503 ];
17504 const lineHeight = itemHeight + padding;
17505 let totalHeight = titleHeight;
17506 ctx.textAlign = 'left';
17507 ctx.textBaseline = 'middle';
17508 let row = -1;
17509 let top = -lineHeight;
17510 this.legendItems.forEach((legendItem, i)=>{
17511 const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;
17512 if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
17513 totalHeight += lineHeight;
17514 lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
17515 top += lineHeight;
17516 row++;
17517 }
17518 hitboxes[i] = {
17519 left: 0,
17520 top,
17521 row,
17522 width: itemWidth,
17523 height: itemHeight
17524 };
17525 lineWidths[lineWidths.length - 1] += itemWidth + padding;
17526 });
17527 return totalHeight;
17528 }
17529 _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {
17530 const { ctx , maxHeight , options: { labels: { padding } } } = this;
17531 const hitboxes = this.legendHitBoxes = [];
17532 const columnSizes = this.columnSizes = [];
17533 const heightLimit = maxHeight - titleHeight;
17534 let totalWidth = padding;
17535 let currentColWidth = 0;
17536 let currentColHeight = 0;
17537 let left = 0;
17538 let col = 0;
17539 this.legendItems.forEach((legendItem, i)=>{
17540 const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);
17541 if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
17542 totalWidth += currentColWidth + padding;
17543 columnSizes.push({
17544 width: currentColWidth,
17545 height: currentColHeight
17546 });
17547 left += currentColWidth + padding;
17548 col++;
17549 currentColWidth = currentColHeight = 0;
17550 }
17551 hitboxes[i] = {
17552 left,
17553 top: currentColHeight,
17554 col,
17555 width: itemWidth,
17556 height: itemHeight
17557 };
17558 currentColWidth = Math.max(currentColWidth, itemWidth);
17559 currentColHeight += itemHeight + padding;
17560 });
17561 totalWidth += currentColWidth;
17562 columnSizes.push({
17563 width: currentColWidth,
17564 height: currentColHeight
17565 });
17566 return totalWidth;
17567 }
17568 adjustHitBoxes() {
17569 if (!this.options.display) {
17570 return;
17571 }
17572 const titleHeight = this._computeTitleHeight();
17573 const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this;
17574 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(rtl, this.left, this.width);
17575 if (this.isHorizontal()) {
17576 let row = 0;
17577 let left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17578 for (const hitbox of hitboxes){
17579 if (row !== hitbox.row) {
17580 row = hitbox.row;
17581 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]);
17582 }
17583 hitbox.top += this.top + titleHeight + padding;
17584 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
17585 left += hitbox.width + padding;
17586 }
17587 } else {
17588 let col = 0;
17589 let top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17590 for (const hitbox of hitboxes){
17591 if (hitbox.col !== col) {
17592 col = hitbox.col;
17593 top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
17594 }
17595 hitbox.top = top;
17596 hitbox.left += this.left + padding;
17597 hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
17598 top += hitbox.height + padding;
17599 }
17600 }
17601 }
17602 isHorizontal() {
17603 return this.options.position === 'top' || this.options.position === 'bottom';
17604 }
17605 draw() {
17606 if (this.options.display) {
17607 const ctx = this.ctx;
17608 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, this);
17609 this._draw();
17610 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx);
17611 }
17612 }
17613 _draw() {
17614 const { options: opts , columnSizes , lineWidths , ctx } = this;
17615 const { align , labels: labelOpts } = opts;
17616 const defaultColor = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.color;
17617 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17618 const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font);
17619 const { padding } = labelOpts;
17620 const fontSize = labelFont.size;
17621 const halfFontSize = fontSize / 2;
17622 let cursor;
17623 this.drawTitle();
17624 ctx.textAlign = rtlHelper.textAlign('left');
17625 ctx.textBaseline = 'middle';
17626 ctx.lineWidth = 0.5;
17627 ctx.font = labelFont.string;
17628 const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize);
17629 const drawLegendBox = function(x, y, legendItem) {
17630 if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
17631 return;
17632 }
17633 ctx.save();
17634 const lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineWidth, 1);
17635 ctx.fillStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.fillStyle, defaultColor);
17636 ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineCap, 'butt');
17637 ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDashOffset, 0);
17638 ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineJoin, 'miter');
17639 ctx.lineWidth = lineWidth;
17640 ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.strokeStyle, defaultColor);
17641 ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDash, []));
17642 if (labelOpts.usePointStyle) {
17643 const drawOptions = {
17644 radius: boxHeight * Math.SQRT2 / 2,
17645 pointStyle: legendItem.pointStyle,
17646 rotation: legendItem.rotation,
17647 borderWidth: lineWidth
17648 };
17649 const centerX = rtlHelper.xPlus(x, boxWidth / 2);
17650 const centerY = y + halfFontSize;
17651 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aE)(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);
17652 } else {
17653 const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
17654 const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);
17655 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(legendItem.borderRadius);
17656 ctx.beginPath();
17657 if (Object.values(borderRadius).some((v)=>v !== 0)) {
17658 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
17659 x: xBoxLeft,
17660 y: yBoxTop,
17661 w: boxWidth,
17662 h: boxHeight,
17663 radius: borderRadius
17664 });
17665 } else {
17666 ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
17667 }
17668 ctx.fill();
17669 if (lineWidth !== 0) {
17670 ctx.stroke();
17671 }
17672 }
17673 ctx.restore();
17674 };
17675 const fillText = function(x, y, legendItem) {
17676 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, {
17677 strikethrough: legendItem.hidden,
17678 textAlign: rtlHelper.textAlign(legendItem.textAlign)
17679 });
17680 };
17681 const isHorizontal = this.isHorizontal();
17682 const titleHeight = this._computeTitleHeight();
17683 if (isHorizontal) {
17684 cursor = {
17685 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[0]),
17686 y: this.top + padding + titleHeight,
17687 line: 0
17688 };
17689 } else {
17690 cursor = {
17691 x: this.left + padding,
17692 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
17693 line: 0
17694 };
17695 }
17696 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(this.ctx, opts.textDirection);
17697 const lineHeight = itemHeight + padding;
17698 this.legendItems.forEach((legendItem, i)=>{
17699 ctx.strokeStyle = legendItem.fontColor;
17700 ctx.fillStyle = legendItem.fontColor;
17701 const textWidth = ctx.measureText(legendItem.text).width;
17702 const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
17703 const width = boxWidth + halfFontSize + textWidth;
17704 let x = cursor.x;
17705 let y = cursor.y;
17706 rtlHelper.setWidth(this.width);
17707 if (isHorizontal) {
17708 if (i > 0 && x + width + padding > this.right) {
17709 y = cursor.y += lineHeight;
17710 cursor.line++;
17711 x = cursor.x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[cursor.line]);
17712 }
17713 } else if (i > 0 && y + lineHeight > this.bottom) {
17714 x = cursor.x = x + columnSizes[cursor.line].width + padding;
17715 cursor.line++;
17716 y = cursor.y = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
17717 }
17718 const realX = rtlHelper.x(x);
17719 drawLegendBox(realX, y, legendItem);
17720 x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aC)(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
17721 fillText(rtlHelper.x(x), y, legendItem);
17722 if (isHorizontal) {
17723 cursor.x += width + padding;
17724 } else if (typeof legendItem.text !== 'string') {
17725 const fontLineHeight = labelFont.lineHeight;
17726 cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;
17727 } else {
17728 cursor.y += lineHeight;
17729 }
17730 });
17731 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(this.ctx, opts.textDirection);
17732 }
17733 drawTitle() {
17734 const opts = this.options;
17735 const titleOpts = opts.title;
17736 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17737 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17738 if (!titleOpts.display) {
17739 return;
17740 }
17741 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width);
17742 const ctx = this.ctx;
17743 const position = titleOpts.position;
17744 const halfFontSize = titleFont.size / 2;
17745 const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
17746 let y;
17747 let left = this.left;
17748 let maxWidth = this.width;
17749 if (this.isHorizontal()) {
17750 maxWidth = Math.max(...this.lineWidths);
17751 y = this.top + topPaddingPlusHalfFontSize;
17752 left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, left, this.right - maxWidth);
17753 } else {
17754 const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0);
17755 y = topPaddingPlusHalfFontSize + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
17756 }
17757 const x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(position, left, left + maxWidth);
17758 ctx.textAlign = rtlHelper.textAlign((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(position));
17759 ctx.textBaseline = 'middle';
17760 ctx.strokeStyle = titleOpts.color;
17761 ctx.fillStyle = titleOpts.color;
17762 ctx.font = titleFont.string;
17763 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, titleOpts.text, x, y, titleFont);
17764 }
17765 _computeTitleHeight() {
17766 const titleOpts = this.options.title;
17767 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font);
17768 const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding);
17769 return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
17770 }
17771 _getLegendItemAt(x, y) {
17772 let i, hitBox, lh;
17773 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)) {
17774 lh = this.legendHitBoxes;
17775 for(i = 0; i < lh.length; ++i){
17776 hitBox = lh[i];
17777 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)) {
17778 return this.legendItems[i];
17779 }
17780 }
17781 }
17782 return null;
17783 }
17784 handleEvent(e) {
17785 const opts = this.options;
17786 if (!isListened(e.type, opts)) {
17787 return;
17788 }
17789 const hoveredItem = this._getLegendItemAt(e.x, e.y);
17790 if (e.type === 'mousemove' || e.type === 'mouseout') {
17791 const previous = this._hoveredItem;
17792 const sameItem = itemsEqual(previous, hoveredItem);
17793 if (previous && !sameItem) {
17794 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onLeave, [
17795 e,
17796 previous,
17797 this
17798 ], this);
17799 }
17800 this._hoveredItem = hoveredItem;
17801 if (hoveredItem && !sameItem) {
17802 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onHover, [
17803 e,
17804 hoveredItem,
17805 this
17806 ], this);
17807 }
17808 } else if (hoveredItem) {
17809 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onClick, [
17810 e,
17811 hoveredItem,
17812 this
17813 ], this);
17814 }
17815 }
17816 }
17817 function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {
17818 const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);
17819 const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);
17820 return {
17821 itemWidth,
17822 itemHeight
17823 };
17824 }
17825 function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {
17826 let legendItemText = legendItem.text;
17827 if (legendItemText && typeof legendItemText !== 'string') {
17828 legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b);
17829 }
17830 return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;
17831 }
17832 function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {
17833 let itemHeight = _itemHeight;
17834 if (typeof legendItem.text !== 'string') {
17835 itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);
17836 }
17837 return itemHeight;
17838 }
17839 function calculateLegendItemHeight(legendItem, fontLineHeight) {
17840 const labelHeight = legendItem.text ? legendItem.text.length : 0;
17841 return fontLineHeight * labelHeight;
17842 }
17843 function isListened(type, opts) {
17844 if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) {
17845 return true;
17846 }
17847 if (opts.onClick && (type === 'click' || type === 'mouseup')) {
17848 return true;
17849 }
17850 return false;
17851 }
17852 var plugin_legend = {
17853 id: 'legend',
17854 _element: Legend,
17855 start (chart, _args, options) {
17856 const legend = chart.legend = new Legend({
17857 ctx: chart.ctx,
17858 options,
17859 chart
17860 });
17861 layouts.configure(chart, legend, options);
17862 layouts.addBox(chart, legend);
17863 },
17864 stop (chart) {
17865 layouts.removeBox(chart, chart.legend);
17866 delete chart.legend;
17867 },
17868 beforeUpdate (chart, _args, options) {
17869 const legend = chart.legend;
17870 layouts.configure(chart, legend, options);
17871 legend.options = options;
17872 },
17873 afterUpdate (chart) {
17874 const legend = chart.legend;
17875 legend.buildLabels();
17876 legend.adjustHitBoxes();
17877 },
17878 afterEvent (chart, args) {
17879 if (!args.replay) {
17880 chart.legend.handleEvent(args.event);
17881 }
17882 },
17883 defaults: {
17884 display: true,
17885 position: 'top',
17886 align: 'center',
17887 fullSize: true,
17888 reverse: false,
17889 weight: 1000,
17890 onClick (e, legendItem, legend) {
17891 const index = legendItem.datasetIndex;
17892 const ci = legend.chart;
17893 if (ci.isDatasetVisible(index)) {
17894 ci.hide(index);
17895 legendItem.hidden = true;
17896 } else {
17897 ci.show(index);
17898 legendItem.hidden = false;
17899 }
17900 },
17901 onHover: null,
17902 onLeave: null,
17903 labels: {
17904 color: (ctx)=>ctx.chart.options.color,
17905 boxWidth: 40,
17906 padding: 10,
17907 generateLabels (chart) {
17908 const datasets = chart.data.datasets;
17909 const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;
17910 return chart._getSortedDatasetMetas().map((meta)=>{
17911 const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
17912 const borderWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(style.borderWidth);
17913 return {
17914 text: datasets[meta.index].label,
17915 fillStyle: style.backgroundColor,
17916 fontColor: color,
17917 hidden: !meta.visible,
17918 lineCap: style.borderCapStyle,
17919 lineDash: style.borderDash,
17920 lineDashOffset: style.borderDashOffset,
17921 lineJoin: style.borderJoinStyle,
17922 lineWidth: (borderWidth.width + borderWidth.height) / 4,
17923 strokeStyle: style.borderColor,
17924 pointStyle: pointStyle || style.pointStyle,
17925 rotation: style.rotation,
17926 textAlign: textAlign || style.textAlign,
17927 borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
17928 datasetIndex: meta.index
17929 };
17930 }, this);
17931 }
17932 },
17933 title: {
17934 color: (ctx)=>ctx.chart.options.color,
17935 display: false,
17936 position: 'center',
17937 text: ''
17938 }
17939 },
17940 descriptors: {
17941 _scriptable: (name)=>!name.startsWith('on'),
17942 labels: {
17943 _scriptable: (name)=>![
17944 'generateLabels',
17945 'filter',
17946 'sort'
17947 ].includes(name)
17948 }
17949 }
17950 };
17951
17952 class Title extends Element {
17953 constructor(config){
17954 super();
17955 this.chart = config.chart;
17956 this.options = config.options;
17957 this.ctx = config.ctx;
17958 this._padding = undefined;
17959 this.top = undefined;
17960 this.bottom = undefined;
17961 this.left = undefined;
17962 this.right = undefined;
17963 this.width = undefined;
17964 this.height = undefined;
17965 this.position = undefined;
17966 this.weight = undefined;
17967 this.fullSize = undefined;
17968 }
17969 update(maxWidth, maxHeight) {
17970 const opts = this.options;
17971 this.left = 0;
17972 this.top = 0;
17973 if (!opts.display) {
17974 this.width = this.height = this.right = this.bottom = 0;
17975 return;
17976 }
17977 this.width = this.right = maxWidth;
17978 this.height = this.bottom = maxHeight;
17979 const lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(opts.text) ? opts.text.length : 1;
17980 this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.padding);
17981 const textSize = lineCount * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font).lineHeight + this._padding.height;
17982 if (this.isHorizontal()) {
17983 this.height = textSize;
17984 } else {
17985 this.width = textSize;
17986 }
17987 }
17988 isHorizontal() {
17989 const pos = this.options.position;
17990 return pos === 'top' || pos === 'bottom';
17991 }
17992 _drawArgs(offset) {
17993 const { top , left , bottom , right , options } = this;
17994 const align = options.align;
17995 let rotation = 0;
17996 let maxWidth, titleX, titleY;
17997 if (this.isHorizontal()) {
17998 titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right);
17999 titleY = top + offset;
18000 maxWidth = right - left;
18001 } else {
18002 if (options.position === 'left') {
18003 titleX = left + offset;
18004 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top);
18005 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * -0.5;
18006 } else {
18007 titleX = right - offset;
18008 titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, top, bottom);
18009 rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * 0.5;
18010 }
18011 maxWidth = bottom - top;
18012 }
18013 return {
18014 titleX,
18015 titleY,
18016 maxWidth,
18017 rotation
18018 };
18019 }
18020 draw() {
18021 const ctx = this.ctx;
18022 const opts = this.options;
18023 if (!opts.display) {
18024 return;
18025 }
18026 const fontOpts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
18027 const lineHeight = fontOpts.lineHeight;
18028 const offset = lineHeight / 2 + this._padding.top;
18029 const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset);
18030 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, opts.text, 0, 0, fontOpts, {
18031 color: opts.color,
18032 maxWidth,
18033 rotation,
18034 textAlign: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(opts.align),
18035 textBaseline: 'middle',
18036 translation: [
18037 titleX,
18038 titleY
18039 ]
18040 });
18041 }
18042 }
18043 function createTitle(chart, titleOpts) {
18044 const title = new Title({
18045 ctx: chart.ctx,
18046 options: titleOpts,
18047 chart
18048 });
18049 layouts.configure(chart, title, titleOpts);
18050 layouts.addBox(chart, title);
18051 chart.titleBlock = title;
18052 }
18053 var plugin_title = {
18054 id: 'title',
18055 _element: Title,
18056 start (chart, _args, options) {
18057 createTitle(chart, options);
18058 },
18059 stop (chart) {
18060 const titleBlock = chart.titleBlock;
18061 layouts.removeBox(chart, titleBlock);
18062 delete chart.titleBlock;
18063 },
18064 beforeUpdate (chart, _args, options) {
18065 const title = chart.titleBlock;
18066 layouts.configure(chart, title, options);
18067 title.options = options;
18068 },
18069 defaults: {
18070 align: 'center',
18071 display: false,
18072 font: {
18073 weight: 'bold'
18074 },
18075 fullSize: true,
18076 padding: 10,
18077 position: 'top',
18078 text: '',
18079 weight: 2000
18080 },
18081 defaultRoutes: {
18082 color: 'color'
18083 },
18084 descriptors: {
18085 _scriptable: true,
18086 _indexable: false
18087 }
18088 };
18089
18090 const map = new WeakMap();
18091 var plugin_subtitle = {
18092 id: 'subtitle',
18093 start (chart, _args, options) {
18094 const title = new Title({
18095 ctx: chart.ctx,
18096 options,
18097 chart
18098 });
18099 layouts.configure(chart, title, options);
18100 layouts.addBox(chart, title);
18101 map.set(chart, title);
18102 },
18103 stop (chart) {
18104 layouts.removeBox(chart, map.get(chart));
18105 map.delete(chart);
18106 },
18107 beforeUpdate (chart, _args, options) {
18108 const title = map.get(chart);
18109 layouts.configure(chart, title, options);
18110 title.options = options;
18111 },
18112 defaults: {
18113 align: 'center',
18114 display: false,
18115 font: {
18116 weight: 'normal'
18117 },
18118 fullSize: true,
18119 padding: 0,
18120 position: 'top',
18121 text: '',
18122 weight: 1500
18123 },
18124 defaultRoutes: {
18125 color: 'color'
18126 },
18127 descriptors: {
18128 _scriptable: true,
18129 _indexable: false
18130 }
18131 };
18132
18133 const positioners = {
18134 average (items) {
18135 if (!items.length) {
18136 return false;
18137 }
18138 let i, len;
18139 let xSet = new Set();
18140 let y = 0;
18141 let count = 0;
18142 for(i = 0, len = items.length; i < len; ++i){
18143 const el = items[i].element;
18144 if (el && el.hasValue()) {
18145 const pos = el.tooltipPosition();
18146 xSet.add(pos.x);
18147 y += pos.y;
18148 ++count;
18149 }
18150 }
18151 if (count === 0 || xSet.size === 0) {
18152 return false;
18153 }
18154 const xAverage = [
18155 ...xSet
18156 ].reduce((a, b)=>a + b) / xSet.size;
18157 return {
18158 x: xAverage,
18159 y: y / count
18160 };
18161 },
18162 nearest (items, eventPosition) {
18163 if (!items.length) {
18164 return false;
18165 }
18166 let x = eventPosition.x;
18167 let y = eventPosition.y;
18168 let minDistance = Number.POSITIVE_INFINITY;
18169 let i, len, nearestElement;
18170 for(i = 0, len = items.length; i < len; ++i){
18171 const el = items[i].element;
18172 if (el && el.hasValue()) {
18173 const center = el.getCenterPoint();
18174 const d = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aF)(eventPosition, center);
18175 if (d < minDistance) {
18176 minDistance = d;
18177 nearestElement = el;
18178 }
18179 }
18180 }
18181 if (nearestElement) {
18182 const tp = nearestElement.tooltipPosition();
18183 x = tp.x;
18184 y = tp.y;
18185 }
18186 return {
18187 x,
18188 y
18189 };
18190 }
18191 };
18192 function pushOrConcat(base, toPush) {
18193 if (toPush) {
18194 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(toPush)) {
18195 Array.prototype.push.apply(base, toPush);
18196 } else {
18197 base.push(toPush);
18198 }
18199 }
18200 return base;
18201 }
18202 function splitNewlines(str) {
18203 if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
18204 return str.split('\n');
18205 }
18206 return str;
18207 }
18208 function createTooltipItem(chart, item) {
18209 const { element , datasetIndex , index } = item;
18210 const controller = chart.getDatasetMeta(datasetIndex).controller;
18211 const { label , value } = controller.getLabelAndValue(index);
18212 return {
18213 chart,
18214 label,
18215 parsed: controller.getParsed(index),
18216 raw: chart.data.datasets[datasetIndex].data[index],
18217 formattedValue: value,
18218 dataset: controller.getDataset(),
18219 dataIndex: index,
18220 datasetIndex,
18221 element
18222 };
18223 }
18224 function getTooltipSize(tooltip, options) {
18225 const ctx = tooltip.chart.ctx;
18226 const { body , footer , title } = tooltip;
18227 const { boxWidth , boxHeight } = options;
18228 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18229 const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18230 const footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18231 const titleLineCount = title.length;
18232 const footerLineCount = footer.length;
18233 const bodyLineItemCount = body.length;
18234 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18235 let height = padding.height;
18236 let width = 0;
18237 let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
18238 combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
18239 if (titleLineCount) {
18240 height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;
18241 }
18242 if (combinedBodyLength) {
18243 const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
18244 height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;
18245 }
18246 if (footerLineCount) {
18247 height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;
18248 }
18249 let widthPadding = 0;
18250 const maxLineWidth = function(line) {
18251 width = Math.max(width, ctx.measureText(line).width + widthPadding);
18252 };
18253 ctx.save();
18254 ctx.font = titleFont.string;
18255 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.title, maxLineWidth);
18256 ctx.font = bodyFont.string;
18257 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
18258 widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;
18259 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(body, (bodyItem)=>{
18260 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, maxLineWidth);
18261 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.lines, maxLineWidth);
18262 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, maxLineWidth);
18263 });
18264 widthPadding = 0;
18265 ctx.font = footerFont.string;
18266 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.footer, maxLineWidth);
18267 ctx.restore();
18268 width += padding.width;
18269 return {
18270 width,
18271 height
18272 };
18273 }
18274 function determineYAlign(chart, size) {
18275 const { y , height } = size;
18276 if (y < height / 2) {
18277 return 'top';
18278 } else if (y > chart.height - height / 2) {
18279 return 'bottom';
18280 }
18281 return 'center';
18282 }
18283 function doesNotFitWithAlign(xAlign, chart, options, size) {
18284 const { x , width } = size;
18285 const caret = options.caretSize + options.caretPadding;
18286 if (xAlign === 'left' && x + width + caret > chart.width) {
18287 return true;
18288 }
18289 if (xAlign === 'right' && x - width - caret < 0) {
18290 return true;
18291 }
18292 }
18293 function determineXAlign(chart, options, size, yAlign) {
18294 const { x , width } = size;
18295 const { width: chartWidth , chartArea: { left , right } } = chart;
18296 let xAlign = 'center';
18297 if (yAlign === 'center') {
18298 xAlign = x <= (left + right) / 2 ? 'left' : 'right';
18299 } else if (x <= width / 2) {
18300 xAlign = 'left';
18301 } else if (x >= chartWidth - width / 2) {
18302 xAlign = 'right';
18303 }
18304 if (doesNotFitWithAlign(xAlign, chart, options, size)) {
18305 xAlign = 'center';
18306 }
18307 return xAlign;
18308 }
18309 function determineAlignment(chart, options, size) {
18310 const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
18311 return {
18312 xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
18313 yAlign
18314 };
18315 }
18316 function alignX(size, xAlign) {
18317 let { x , width } = size;
18318 if (xAlign === 'right') {
18319 x -= width;
18320 } else if (xAlign === 'center') {
18321 x -= width / 2;
18322 }
18323 return x;
18324 }
18325 function alignY(size, yAlign, paddingAndSize) {
18326 let { y , height } = size;
18327 if (yAlign === 'top') {
18328 y += paddingAndSize;
18329 } else if (yAlign === 'bottom') {
18330 y -= height + paddingAndSize;
18331 } else {
18332 y -= height / 2;
18333 }
18334 return y;
18335 }
18336 function getBackgroundPoint(options, size, alignment, chart) {
18337 const { caretSize , caretPadding , cornerRadius } = options;
18338 const { xAlign , yAlign } = alignment;
18339 const paddingAndSize = caretSize + caretPadding;
18340 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18341 let x = alignX(size, xAlign);
18342 const y = alignY(size, yAlign, paddingAndSize);
18343 if (yAlign === 'center') {
18344 if (xAlign === 'left') {
18345 x += paddingAndSize;
18346 } else if (xAlign === 'right') {
18347 x -= paddingAndSize;
18348 }
18349 } else if (xAlign === 'left') {
18350 x -= Math.max(topLeft, bottomLeft) + caretSize;
18351 } else if (xAlign === 'right') {
18352 x += Math.max(topRight, bottomRight) + caretSize;
18353 }
18354 return {
18355 x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(x, 0, chart.width - size.width),
18356 y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(y, 0, chart.height - size.height)
18357 };
18358 }
18359 function getAlignedX(tooltip, align, options) {
18360 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18361 return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;
18362 }
18363 function getBeforeAfterBodyLines(callback) {
18364 return pushOrConcat([], splitNewlines(callback));
18365 }
18366 function createTooltipContext(parent, tooltip, tooltipItems) {
18367 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
18368 tooltip,
18369 tooltipItems,
18370 type: 'tooltip'
18371 });
18372 }
18373 function overrideCallbacks(callbacks, context) {
18374 const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
18375 return override ? callbacks.override(override) : callbacks;
18376 }
18377 const defaultCallbacks = {
18378 beforeTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18379 title (tooltipItems) {
18380 if (tooltipItems.length > 0) {
18381 const item = tooltipItems[0];
18382 const labels = item.chart.data.labels;
18383 const labelCount = labels ? labels.length : 0;
18384 if (this && this.options && this.options.mode === 'dataset') {
18385 return item.dataset.label || '';
18386 } else if (item.label) {
18387 return item.label;
18388 } else if (labelCount > 0 && item.dataIndex < labelCount) {
18389 return labels[item.dataIndex];
18390 }
18391 }
18392 return '';
18393 },
18394 afterTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18395 beforeBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18396 beforeLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18397 label (tooltipItem) {
18398 if (this && this.options && this.options.mode === 'dataset') {
18399 return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
18400 }
18401 let label = tooltipItem.dataset.label || '';
18402 if (label) {
18403 label += ': ';
18404 }
18405 const value = tooltipItem.formattedValue;
18406 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
18407 label += value;
18408 }
18409 return label;
18410 },
18411 labelColor (tooltipItem) {
18412 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18413 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18414 return {
18415 borderColor: options.borderColor,
18416 backgroundColor: options.backgroundColor,
18417 borderWidth: options.borderWidth,
18418 borderDash: options.borderDash,
18419 borderDashOffset: options.borderDashOffset,
18420 borderRadius: 0
18421 };
18422 },
18423 labelTextColor () {
18424 return this.options.bodyColor;
18425 },
18426 labelPointStyle (tooltipItem) {
18427 const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
18428 const options = meta.controller.getStyle(tooltipItem.dataIndex);
18429 return {
18430 pointStyle: options.pointStyle,
18431 rotation: options.rotation
18432 };
18433 },
18434 afterLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18435 afterBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18436 beforeFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18437 footer: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG,
18438 afterFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG
18439 };
18440 function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
18441 const result = callbacks[name].call(ctx, arg);
18442 if (typeof result === 'undefined') {
18443 return defaultCallbacks[name].call(ctx, arg);
18444 }
18445 return result;
18446 }
18447 class Tooltip extends Element {
18448 static positioners = positioners;
18449 constructor(config){
18450 super();
18451 this.opacity = 0;
18452 this._active = [];
18453 this._eventPosition = undefined;
18454 this._size = undefined;
18455 this._cachedAnimations = undefined;
18456 this._tooltipItems = [];
18457 this.$animations = undefined;
18458 this.$context = undefined;
18459 this.chart = config.chart;
18460 this.options = config.options;
18461 this.dataPoints = undefined;
18462 this.title = undefined;
18463 this.beforeBody = undefined;
18464 this.body = undefined;
18465 this.afterBody = undefined;
18466 this.footer = undefined;
18467 this.xAlign = undefined;
18468 this.yAlign = undefined;
18469 this.x = undefined;
18470 this.y = undefined;
18471 this.height = undefined;
18472 this.width = undefined;
18473 this.caretX = undefined;
18474 this.caretY = undefined;
18475 this.labelColors = undefined;
18476 this.labelPointStyles = undefined;
18477 this.labelTextColors = undefined;
18478 }
18479 initialize(options) {
18480 this.options = options;
18481 this._cachedAnimations = undefined;
18482 this.$context = undefined;
18483 }
18484 _resolveAnimations() {
18485 const cached = this._cachedAnimations;
18486 if (cached) {
18487 return cached;
18488 }
18489 const chart = this.chart;
18490 const options = this.options.setContext(this.getContext());
18491 const opts = options.enabled && chart.options.animation && options.animations;
18492 const animations = new Animations(this.chart, opts);
18493 if (opts._cacheable) {
18494 this._cachedAnimations = Object.freeze(animations);
18495 }
18496 return animations;
18497 }
18498 getContext() {
18499 return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
18500 }
18501 getTitle(context, options) {
18502 const { callbacks } = options;
18503 const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);
18504 const title = invokeCallbackWithFallback(callbacks, 'title', this, context);
18505 const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);
18506 let lines = [];
18507 lines = pushOrConcat(lines, splitNewlines(beforeTitle));
18508 lines = pushOrConcat(lines, splitNewlines(title));
18509 lines = pushOrConcat(lines, splitNewlines(afterTitle));
18510 return lines;
18511 }
18512 getBeforeBody(tooltipItems, options) {
18513 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems));
18514 }
18515 getBody(tooltipItems, options) {
18516 const { callbacks } = options;
18517 const bodyItems = [];
18518 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18519 const bodyItem = {
18520 before: [],
18521 lines: [],
18522 after: []
18523 };
18524 const scoped = overrideCallbacks(callbacks, context);
18525 pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));
18526 pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));
18527 pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));
18528 bodyItems.push(bodyItem);
18529 });
18530 return bodyItems;
18531 }
18532 getAfterBody(tooltipItems, options) {
18533 return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems));
18534 }
18535 getFooter(tooltipItems, options) {
18536 const { callbacks } = options;
18537 const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);
18538 const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);
18539 const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);
18540 let lines = [];
18541 lines = pushOrConcat(lines, splitNewlines(beforeFooter));
18542 lines = pushOrConcat(lines, splitNewlines(footer));
18543 lines = pushOrConcat(lines, splitNewlines(afterFooter));
18544 return lines;
18545 }
18546 _createItems(options) {
18547 const active = this._active;
18548 const data = this.chart.data;
18549 const labelColors = [];
18550 const labelPointStyles = [];
18551 const labelTextColors = [];
18552 let tooltipItems = [];
18553 let i, len;
18554 for(i = 0, len = active.length; i < len; ++i){
18555 tooltipItems.push(createTooltipItem(this.chart, active[i]));
18556 }
18557 if (options.filter) {
18558 tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data));
18559 }
18560 if (options.itemSort) {
18561 tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data));
18562 }
18563 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{
18564 const scoped = overrideCallbacks(options.callbacks, context);
18565 labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));
18566 labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));
18567 labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));
18568 });
18569 this.labelColors = labelColors;
18570 this.labelPointStyles = labelPointStyles;
18571 this.labelTextColors = labelTextColors;
18572 this.dataPoints = tooltipItems;
18573 return tooltipItems;
18574 }
18575 update(changed, replay) {
18576 const options = this.options.setContext(this.getContext());
18577 const active = this._active;
18578 let properties;
18579 let tooltipItems = [];
18580 if (!active.length) {
18581 if (this.opacity !== 0) {
18582 properties = {
18583 opacity: 0
18584 };
18585 }
18586 } else {
18587 const position = positioners[options.position].call(this, active, this._eventPosition);
18588 tooltipItems = this._createItems(options);
18589 this.title = this.getTitle(tooltipItems, options);
18590 this.beforeBody = this.getBeforeBody(tooltipItems, options);
18591 this.body = this.getBody(tooltipItems, options);
18592 this.afterBody = this.getAfterBody(tooltipItems, options);
18593 this.footer = this.getFooter(tooltipItems, options);
18594 const size = this._size = getTooltipSize(this, options);
18595 const positionAndSize = Object.assign({}, position, size);
18596 const alignment = determineAlignment(this.chart, options, positionAndSize);
18597 const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
18598 this.xAlign = alignment.xAlign;
18599 this.yAlign = alignment.yAlign;
18600 properties = {
18601 opacity: 1,
18602 x: backgroundPoint.x,
18603 y: backgroundPoint.y,
18604 width: size.width,
18605 height: size.height,
18606 caretX: position.x,
18607 caretY: position.y
18608 };
18609 }
18610 this._tooltipItems = tooltipItems;
18611 this.$context = undefined;
18612 if (properties) {
18613 this._resolveAnimations().update(this, properties);
18614 }
18615 if (changed && options.external) {
18616 options.external.call(this, {
18617 chart: this.chart,
18618 tooltip: this,
18619 replay
18620 });
18621 }
18622 }
18623 drawCaret(tooltipPoint, ctx, size, options) {
18624 const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
18625 ctx.lineTo(caretPosition.x1, caretPosition.y1);
18626 ctx.lineTo(caretPosition.x2, caretPosition.y2);
18627 ctx.lineTo(caretPosition.x3, caretPosition.y3);
18628 }
18629 getCaretPosition(tooltipPoint, size, options) {
18630 const { xAlign , yAlign } = this;
18631 const { caretSize , cornerRadius } = options;
18632 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius);
18633 const { x: ptX , y: ptY } = tooltipPoint;
18634 const { width , height } = size;
18635 let x1, x2, x3, y1, y2, y3;
18636 if (yAlign === 'center') {
18637 y2 = ptY + height / 2;
18638 if (xAlign === 'left') {
18639 x1 = ptX;
18640 x2 = x1 - caretSize;
18641 y1 = y2 + caretSize;
18642 y3 = y2 - caretSize;
18643 } else {
18644 x1 = ptX + width;
18645 x2 = x1 + caretSize;
18646 y1 = y2 - caretSize;
18647 y3 = y2 + caretSize;
18648 }
18649 x3 = x1;
18650 } else {
18651 if (xAlign === 'left') {
18652 x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;
18653 } else if (xAlign === 'right') {
18654 x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
18655 } else {
18656 x2 = this.caretX;
18657 }
18658 if (yAlign === 'top') {
18659 y1 = ptY;
18660 y2 = y1 - caretSize;
18661 x1 = x2 - caretSize;
18662 x3 = x2 + caretSize;
18663 } else {
18664 y1 = ptY + height;
18665 y2 = y1 + caretSize;
18666 x1 = x2 + caretSize;
18667 x3 = x2 - caretSize;
18668 }
18669 y3 = y1;
18670 }
18671 return {
18672 x1,
18673 x2,
18674 x3,
18675 y1,
18676 y2,
18677 y3
18678 };
18679 }
18680 drawTitle(pt, ctx, options) {
18681 const title = this.title;
18682 const length = title.length;
18683 let titleFont, titleSpacing, i;
18684 if (length) {
18685 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18686 pt.x = getAlignedX(this, options.titleAlign, options);
18687 ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
18688 ctx.textBaseline = 'middle';
18689 titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont);
18690 titleSpacing = options.titleSpacing;
18691 ctx.fillStyle = options.titleColor;
18692 ctx.font = titleFont.string;
18693 for(i = 0; i < length; ++i){
18694 ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
18695 pt.y += titleFont.lineHeight + titleSpacing;
18696 if (i + 1 === length) {
18697 pt.y += options.titleMarginBottom - titleSpacing;
18698 }
18699 }
18700 }
18701 }
18702 _drawColorBox(ctx, pt, i, rtlHelper, options) {
18703 const labelColor = this.labelColors[i];
18704 const labelPointStyle = this.labelPointStyles[i];
18705 const { boxHeight , boxWidth } = options;
18706 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18707 const colorX = getAlignedX(this, 'left', options);
18708 const rtlColorX = rtlHelper.x(colorX);
18709 const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
18710 const colorY = pt.y + yOffSet;
18711 if (options.usePointStyle) {
18712 const drawOptions = {
18713 radius: Math.min(boxWidth, boxHeight) / 2,
18714 pointStyle: labelPointStyle.pointStyle,
18715 rotation: labelPointStyle.rotation,
18716 borderWidth: 1
18717 };
18718 const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
18719 const centerY = colorY + boxHeight / 2;
18720 ctx.strokeStyle = options.multiKeyBackground;
18721 ctx.fillStyle = options.multiKeyBackground;
18722 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18723 ctx.strokeStyle = labelColor.borderColor;
18724 ctx.fillStyle = labelColor.backgroundColor;
18725 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY);
18726 } else {
18727 ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;
18728 ctx.strokeStyle = labelColor.borderColor;
18729 ctx.setLineDash(labelColor.borderDash || []);
18730 ctx.lineDashOffset = labelColor.borderDashOffset || 0;
18731 const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);
18732 const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);
18733 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(labelColor.borderRadius);
18734 if (Object.values(borderRadius).some((v)=>v !== 0)) {
18735 ctx.beginPath();
18736 ctx.fillStyle = options.multiKeyBackground;
18737 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18738 x: outerX,
18739 y: colorY,
18740 w: boxWidth,
18741 h: boxHeight,
18742 radius: borderRadius
18743 });
18744 ctx.fill();
18745 ctx.stroke();
18746 ctx.fillStyle = labelColor.backgroundColor;
18747 ctx.beginPath();
18748 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
18749 x: innerX,
18750 y: colorY + 1,
18751 w: boxWidth - 2,
18752 h: boxHeight - 2,
18753 radius: borderRadius
18754 });
18755 ctx.fill();
18756 } else {
18757 ctx.fillStyle = options.multiKeyBackground;
18758 ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
18759 ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
18760 ctx.fillStyle = labelColor.backgroundColor;
18761 ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
18762 }
18763 }
18764 ctx.fillStyle = this.labelTextColors[i];
18765 }
18766 drawBody(pt, ctx, options) {
18767 const { body } = this;
18768 const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options;
18769 const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont);
18770 let bodyLineHeight = bodyFont.lineHeight;
18771 let xLinePadding = 0;
18772 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18773 const fillLineOfText = function(line) {
18774 ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
18775 pt.y += bodyLineHeight + bodySpacing;
18776 };
18777 const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
18778 let bodyItem, textColor, lines, i, j, ilen, jlen;
18779 ctx.textAlign = bodyAlign;
18780 ctx.textBaseline = 'middle';
18781 ctx.font = bodyFont.string;
18782 pt.x = getAlignedX(this, bodyAlignForCalculation, options);
18783 ctx.fillStyle = options.bodyColor;
18784 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.beforeBody, fillLineOfText);
18785 xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;
18786 for(i = 0, ilen = body.length; i < ilen; ++i){
18787 bodyItem = body[i];
18788 textColor = this.labelTextColors[i];
18789 ctx.fillStyle = textColor;
18790 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, fillLineOfText);
18791 lines = bodyItem.lines;
18792 if (displayColors && lines.length) {
18793 this._drawColorBox(ctx, pt, i, rtlHelper, options);
18794 bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
18795 }
18796 for(j = 0, jlen = lines.length; j < jlen; ++j){
18797 fillLineOfText(lines[j]);
18798 bodyLineHeight = bodyFont.lineHeight;
18799 }
18800 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, fillLineOfText);
18801 }
18802 xLinePadding = 0;
18803 bodyLineHeight = bodyFont.lineHeight;
18804 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.afterBody, fillLineOfText);
18805 pt.y -= bodySpacing;
18806 }
18807 drawFooter(pt, ctx, options) {
18808 const footer = this.footer;
18809 const length = footer.length;
18810 let footerFont, i;
18811 if (length) {
18812 const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width);
18813 pt.x = getAlignedX(this, options.footerAlign, options);
18814 pt.y += options.footerMarginTop;
18815 ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
18816 ctx.textBaseline = 'middle';
18817 footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont);
18818 ctx.fillStyle = options.footerColor;
18819 ctx.font = footerFont.string;
18820 for(i = 0; i < length; ++i){
18821 ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
18822 pt.y += footerFont.lineHeight + options.footerSpacing;
18823 }
18824 }
18825 }
18826 drawBackground(pt, ctx, tooltipSize, options) {
18827 const { xAlign , yAlign } = this;
18828 const { x , y } = pt;
18829 const { width , height } = tooltipSize;
18830 const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(options.cornerRadius);
18831 ctx.fillStyle = options.backgroundColor;
18832 ctx.strokeStyle = options.borderColor;
18833 ctx.lineWidth = options.borderWidth;
18834 ctx.beginPath();
18835 ctx.moveTo(x + topLeft, y);
18836 if (yAlign === 'top') {
18837 this.drawCaret(pt, ctx, tooltipSize, options);
18838 }
18839 ctx.lineTo(x + width - topRight, y);
18840 ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
18841 if (yAlign === 'center' && xAlign === 'right') {
18842 this.drawCaret(pt, ctx, tooltipSize, options);
18843 }
18844 ctx.lineTo(x + width, y + height - bottomRight);
18845 ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
18846 if (yAlign === 'bottom') {
18847 this.drawCaret(pt, ctx, tooltipSize, options);
18848 }
18849 ctx.lineTo(x + bottomLeft, y + height);
18850 ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
18851 if (yAlign === 'center' && xAlign === 'left') {
18852 this.drawCaret(pt, ctx, tooltipSize, options);
18853 }
18854 ctx.lineTo(x, y + topLeft);
18855 ctx.quadraticCurveTo(x, y, x + topLeft, y);
18856 ctx.closePath();
18857 ctx.fill();
18858 if (options.borderWidth > 0) {
18859 ctx.stroke();
18860 }
18861 }
18862 _updateAnimationTarget(options) {
18863 const chart = this.chart;
18864 const anims = this.$animations;
18865 const animX = anims && anims.x;
18866 const animY = anims && anims.y;
18867 if (animX || animY) {
18868 const position = positioners[options.position].call(this, this._active, this._eventPosition);
18869 if (!position) {
18870 return;
18871 }
18872 const size = this._size = getTooltipSize(this, options);
18873 const positionAndSize = Object.assign({}, position, this._size);
18874 const alignment = determineAlignment(chart, options, positionAndSize);
18875 const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
18876 if (animX._to !== point.x || animY._to !== point.y) {
18877 this.xAlign = alignment.xAlign;
18878 this.yAlign = alignment.yAlign;
18879 this.width = size.width;
18880 this.height = size.height;
18881 this.caretX = position.x;
18882 this.caretY = position.y;
18883 this._resolveAnimations().update(this, point);
18884 }
18885 }
18886 }
18887 _willRender() {
18888 return !!this.opacity;
18889 }
18890 draw(ctx) {
18891 const options = this.options.setContext(this.getContext());
18892 let opacity = this.opacity;
18893 if (!opacity) {
18894 return;
18895 }
18896 this._updateAnimationTarget(options);
18897 const tooltipSize = {
18898 width: this.width,
18899 height: this.height
18900 };
18901 const pt = {
18902 x: this.x,
18903 y: this.y
18904 };
18905 opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
18906 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding);
18907 const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
18908 if (options.enabled && hasTooltipContent) {
18909 ctx.save();
18910 ctx.globalAlpha = opacity;
18911 this.drawBackground(pt, ctx, tooltipSize, options);
18912 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(ctx, options.textDirection);
18913 pt.y += padding.top;
18914 this.drawTitle(pt, ctx, options);
18915 this.drawBody(pt, ctx, options);
18916 this.drawFooter(pt, ctx, options);
18917 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(ctx, options.textDirection);
18918 ctx.restore();
18919 }
18920 }
18921 getActiveElements() {
18922 return this._active || [];
18923 }
18924 setActiveElements(activeElements, eventPosition) {
18925 const lastActive = this._active;
18926 const active = activeElements.map(({ datasetIndex , index })=>{
18927 const meta = this.chart.getDatasetMeta(datasetIndex);
18928 if (!meta) {
18929 throw new Error('Cannot find a dataset at index ' + datasetIndex);
18930 }
18931 return {
18932 datasetIndex,
18933 element: meta.data[index],
18934 index
18935 };
18936 });
18937 const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(lastActive, active);
18938 const positionChanged = this._positionChanged(active, eventPosition);
18939 if (changed || positionChanged) {
18940 this._active = active;
18941 this._eventPosition = eventPosition;
18942 this._ignoreReplayEvents = true;
18943 this.update(true);
18944 }
18945 }
18946 handleEvent(e, replay, inChartArea = true) {
18947 if (replay && this._ignoreReplayEvents) {
18948 return false;
18949 }
18950 this._ignoreReplayEvents = false;
18951 const options = this.options;
18952 const lastActive = this._active || [];
18953 const active = this._getActiveElements(e, lastActive, replay, inChartArea);
18954 const positionChanged = this._positionChanged(active, e);
18955 const changed = replay || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive) || positionChanged;
18956 if (changed) {
18957 this._active = active;
18958 if (options.enabled || options.external) {
18959 this._eventPosition = {
18960 x: e.x,
18961 y: e.y
18962 };
18963 this.update(true, replay);
18964 }
18965 }
18966 return changed;
18967 }
18968 _getActiveElements(e, lastActive, replay, inChartArea) {
18969 const options = this.options;
18970 if (e.type === 'mouseout') {
18971 return [];
18972 }
18973 if (!inChartArea) {
18974 return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined);
18975 }
18976 const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
18977 if (options.reverse) {
18978 active.reverse();
18979 }
18980 return active;
18981 }
18982 _positionChanged(active, e) {
18983 const { caretX , caretY , options } = this;
18984 const position = positioners[options.position].call(this, active, e);
18985 return position !== false && (caretX !== position.x || caretY !== position.y);
18986 }
18987 }
18988 var plugin_tooltip = {
18989 id: 'tooltip',
18990 _element: Tooltip,
18991 positioners,
18992 afterInit (chart, _args, options) {
18993 if (options) {
18994 chart.tooltip = new Tooltip({
18995 chart,
18996 options
18997 });
18998 }
18999 },
19000 beforeUpdate (chart, _args, options) {
19001 if (chart.tooltip) {
19002 chart.tooltip.initialize(options);
19003 }
19004 },
19005 reset (chart, _args, options) {
19006 if (chart.tooltip) {
19007 chart.tooltip.initialize(options);
19008 }
19009 },
19010 afterDraw (chart) {
19011 const tooltip = chart.tooltip;
19012 if (tooltip && tooltip._willRender()) {
19013 const args = {
19014 tooltip
19015 };
19016 if (chart.notifyPlugins('beforeTooltipDraw', {
19017 ...args,
19018 cancelable: true
19019 }) === false) {
19020 return;
19021 }
19022 tooltip.draw(chart.ctx);
19023 chart.notifyPlugins('afterTooltipDraw', args);
19024 }
19025 },
19026 afterEvent (chart, args) {
19027 if (chart.tooltip) {
19028 const useFinalPosition = args.replay;
19029 if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
19030 args.changed = true;
19031 }
19032 }
19033 },
19034 defaults: {
19035 enabled: true,
19036 external: null,
19037 position: 'average',
19038 backgroundColor: 'rgba(0,0,0,0.8)',
19039 titleColor: '#fff',
19040 titleFont: {
19041 weight: 'bold'
19042 },
19043 titleSpacing: 2,
19044 titleMarginBottom: 6,
19045 titleAlign: 'left',
19046 bodyColor: '#fff',
19047 bodySpacing: 2,
19048 bodyFont: {},
19049 bodyAlign: 'left',
19050 footerColor: '#fff',
19051 footerSpacing: 2,
19052 footerMarginTop: 6,
19053 footerFont: {
19054 weight: 'bold'
19055 },
19056 footerAlign: 'left',
19057 padding: 6,
19058 caretPadding: 2,
19059 caretSize: 5,
19060 cornerRadius: 6,
19061 boxHeight: (ctx, opts)=>opts.bodyFont.size,
19062 boxWidth: (ctx, opts)=>opts.bodyFont.size,
19063 multiKeyBackground: '#fff',
19064 displayColors: true,
19065 boxPadding: 0,
19066 borderColor: 'rgba(0,0,0,0)',
19067 borderWidth: 0,
19068 animation: {
19069 duration: 400,
19070 easing: 'easeOutQuart'
19071 },
19072 animations: {
19073 numbers: {
19074 type: 'number',
19075 properties: [
19076 'x',
19077 'y',
19078 'width',
19079 'height',
19080 'caretX',
19081 'caretY'
19082 ]
19083 },
19084 opacity: {
19085 easing: 'linear',
19086 duration: 200
19087 }
19088 },
19089 callbacks: defaultCallbacks
19090 },
19091 defaultRoutes: {
19092 bodyFont: 'font',
19093 footerFont: 'font',
19094 titleFont: 'font'
19095 },
19096 descriptors: {
19097 _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external',
19098 _indexable: false,
19099 callbacks: {
19100 _scriptable: false,
19101 _indexable: false
19102 },
19103 animation: {
19104 _fallback: false
19105 },
19106 animations: {
19107 _fallback: 'animation'
19108 }
19109 },
19110 additionalOptionScopes: [
19111 'interaction'
19112 ]
19113 };
19114
19115 var plugins = /*#__PURE__*/Object.freeze({
19116 __proto__: null,
19117 Colors: plugin_colors,
19118 Decimation: plugin_decimation,
19119 Filler: index,
19120 Legend: plugin_legend,
19121 SubTitle: plugin_subtitle,
19122 Title: plugin_title,
19123 Tooltip: plugin_tooltip
19124 });
19125
19126 const addIfString = (labels, raw, index, addedLabels)=>{
19127 if (typeof raw === 'string') {
19128 index = labels.push(raw) - 1;
19129 addedLabels.unshift({
19130 index,
19131 label: raw
19132 });
19133 } else if (isNaN(raw)) {
19134 index = null;
19135 }
19136 return index;
19137 };
19138 function findOrAddLabel(labels, raw, index, addedLabels) {
19139 const first = labels.indexOf(raw);
19140 if (first === -1) {
19141 return addIfString(labels, raw, index, addedLabels);
19142 }
19143 const last = labels.lastIndexOf(raw);
19144 return first !== last ? index : first;
19145 }
19146 const validIndex = (index, max)=>index === null ? null : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(Math.round(index), 0, max);
19147 function _getLabelForValue(value) {
19148 const labels = this.getLabels();
19149 if (value >= 0 && value < labels.length) {
19150 return labels[value];
19151 }
19152 return value;
19153 }
19154 class CategoryScale extends Scale {
19155 static id = 'category';
19156 static defaults = {
19157 ticks: {
19158 callback: _getLabelForValue
19159 }
19160 };
19161 constructor(cfg){
19162 super(cfg);
19163 this._startValue = undefined;
19164 this._valueRange = 0;
19165 this._addedLabels = [];
19166 }
19167 init(scaleOptions) {
19168 const added = this._addedLabels;
19169 if (added.length) {
19170 const labels = this.getLabels();
19171 for (const { index , label } of added){
19172 if (labels[index] === label) {
19173 labels.splice(index, 1);
19174 }
19175 }
19176 this._addedLabels = [];
19177 }
19178 super.init(scaleOptions);
19179 }
19180 parse(raw, index) {
19181 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19182 return null;
19183 }
19184 const labels = this.getLabels();
19185 index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(index, raw), this._addedLabels);
19186 return validIndex(index, labels.length - 1);
19187 }
19188 determineDataLimits() {
19189 const { minDefined , maxDefined } = this.getUserBounds();
19190 let { min , max } = this.getMinMax(true);
19191 if (this.options.bounds === 'ticks') {
19192 if (!minDefined) {
19193 min = 0;
19194 }
19195 if (!maxDefined) {
19196 max = this.getLabels().length - 1;
19197 }
19198 }
19199 this.min = min;
19200 this.max = max;
19201 }
19202 buildTicks() {
19203 const min = this.min;
19204 const max = this.max;
19205 const offset = this.options.offset;
19206 const ticks = [];
19207 let labels = this.getLabels();
19208 labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);
19209 this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
19210 this._startValue = this.min - (offset ? 0.5 : 0);
19211 for(let value = min; value <= max; value++){
19212 ticks.push({
19213 value
19214 });
19215 }
19216 return ticks;
19217 }
19218 getLabelForValue(value) {
19219 return _getLabelForValue.call(this, value);
19220 }
19221 configure() {
19222 super.configure();
19223 if (!this.isHorizontal()) {
19224 this._reversePixels = !this._reversePixels;
19225 }
19226 }
19227 getPixelForValue(value) {
19228 if (typeof value !== 'number') {
19229 value = this.parse(value);
19230 }
19231 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19232 }
19233 getPixelForTick(index) {
19234 const ticks = this.ticks;
19235 if (index < 0 || index > ticks.length - 1) {
19236 return null;
19237 }
19238 return this.getPixelForValue(ticks[index].value);
19239 }
19240 getValueForPixel(pixel) {
19241 return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
19242 }
19243 getBasePixel() {
19244 return this.bottom;
19245 }
19246 }
19247
19248 function generateTicks$1(generationOptions, dataRange) {
19249 const ticks = [];
19250 const MIN_SPACING = 1e-14;
19251 const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions;
19252 const unit = step || 1;
19253 const maxSpaces = maxTicks - 1;
19254 const { min: rmin , max: rmax } = dataRange;
19255 const minDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(min);
19256 const maxDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(max);
19257 const countDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(count);
19258 const minSpacing = (rmax - rmin) / (maxDigits + 1);
19259 let spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)((rmax - rmin) / maxSpaces / unit) * unit;
19260 let factor, niceMin, niceMax, numSpaces;
19261 if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
19262 return [
19263 {
19264 value: rmin
19265 },
19266 {
19267 value: rmax
19268 }
19269 ];
19270 }
19271 numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
19272 if (numSpaces > maxSpaces) {
19273 spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)(numSpaces * spacing / maxSpaces / unit) * unit;
19274 }
19275 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision)) {
19276 factor = Math.pow(10, precision);
19277 spacing = Math.ceil(spacing * factor) / factor;
19278 }
19279 if (bounds === 'ticks') {
19280 niceMin = Math.floor(rmin / spacing) * spacing;
19281 niceMax = Math.ceil(rmax / spacing) * spacing;
19282 } else {
19283 niceMin = rmin;
19284 niceMax = rmax;
19285 }
19286 if (minDefined && maxDefined && step && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aJ)((max - min) / step, spacing / 1000)) {
19287 numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
19288 spacing = (max - min) / numSpaces;
19289 niceMin = min;
19290 niceMax = max;
19291 } else if (countDefined) {
19292 niceMin = minDefined ? min : niceMin;
19293 niceMax = maxDefined ? max : niceMax;
19294 numSpaces = count - 1;
19295 spacing = (niceMax - niceMin) / numSpaces;
19296 } else {
19297 numSpaces = (niceMax - niceMin) / spacing;
19298 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(numSpaces, Math.round(numSpaces), spacing / 1000)) {
19299 numSpaces = Math.round(numSpaces);
19300 } else {
19301 numSpaces = Math.ceil(numSpaces);
19302 }
19303 }
19304 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));
19305 factor = Math.pow(10, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision) ? decimalPlaces : precision);
19306 niceMin = Math.round(niceMin * factor) / factor;
19307 niceMax = Math.round(niceMax * factor) / factor;
19308 let j = 0;
19309 if (minDefined) {
19310 if (includeBounds && niceMin !== min) {
19311 ticks.push({
19312 value: min
19313 });
19314 if (niceMin < min) {
19315 j++;
19316 }
19317 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
19318 j++;
19319 }
19320 } else if (niceMin < min) {
19321 j++;
19322 }
19323 }
19324 for(; j < numSpaces; ++j){
19325 const tickValue = Math.round((niceMin + j * spacing) * factor) / factor;
19326 if (maxDefined && tickValue > max) {
19327 break;
19328 }
19329 ticks.push({
19330 value: tickValue
19331 });
19332 }
19333 if (maxDefined && includeBounds && niceMax !== max) {
19334 if (ticks.length && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
19335 ticks[ticks.length - 1].value = max;
19336 } else {
19337 ticks.push({
19338 value: max
19339 });
19340 }
19341 } else if (!maxDefined || niceMax === max) {
19342 ticks.push({
19343 value: niceMax
19344 });
19345 }
19346 return ticks;
19347 }
19348 function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) {
19349 const rad = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(minRotation);
19350 const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;
19351 const length = 0.75 * minSpacing * ('' + value).length;
19352 return Math.min(minSpacing / ratio, length);
19353 }
19354 class LinearScaleBase extends Scale {
19355 constructor(cfg){
19356 super(cfg);
19357 this.start = undefined;
19358 this.end = undefined;
19359 this._startValue = undefined;
19360 this._endValue = undefined;
19361 this._valueRange = 0;
19362 }
19363 parse(raw, index) {
19364 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) {
19365 return null;
19366 }
19367 if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
19368 return null;
19369 }
19370 return +raw;
19371 }
19372 handleTickRangeOptions() {
19373 const { beginAtZero } = this.options;
19374 const { minDefined , maxDefined } = this.getUserBounds();
19375 let { min , max } = this;
19376 const setMin = (v)=>min = minDefined ? min : v;
19377 const setMax = (v)=>max = maxDefined ? max : v;
19378 if (beginAtZero) {
19379 const minSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(min);
19380 const maxSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(max);
19381 if (minSign < 0 && maxSign < 0) {
19382 setMax(0);
19383 } else if (minSign > 0 && maxSign > 0) {
19384 setMin(0);
19385 }
19386 }
19387 if (min === max) {
19388 let offset = max === 0 ? 1 : Math.abs(max * 0.05);
19389 setMax(max + offset);
19390 if (!beginAtZero) {
19391 setMin(min - offset);
19392 }
19393 }
19394 this.min = min;
19395 this.max = max;
19396 }
19397 getTickLimit() {
19398 const tickOpts = this.options.ticks;
19399 let { maxTicksLimit , stepSize } = tickOpts;
19400 let maxTicks;
19401 if (stepSize) {
19402 maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
19403 if (maxTicks > 1000) {
19404 console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
19405 maxTicks = 1000;
19406 }
19407 } else {
19408 maxTicks = this.computeTickLimit();
19409 maxTicksLimit = maxTicksLimit || 11;
19410 }
19411 if (maxTicksLimit) {
19412 maxTicks = Math.min(maxTicksLimit, maxTicks);
19413 }
19414 return maxTicks;
19415 }
19416 computeTickLimit() {
19417 return Number.POSITIVE_INFINITY;
19418 }
19419 buildTicks() {
19420 const opts = this.options;
19421 const tickOpts = opts.ticks;
19422 let maxTicks = this.getTickLimit();
19423 maxTicks = Math.max(2, maxTicks);
19424 const numericGeneratorOptions = {
19425 maxTicks,
19426 bounds: opts.bounds,
19427 min: opts.min,
19428 max: opts.max,
19429 precision: tickOpts.precision,
19430 step: tickOpts.stepSize,
19431 count: tickOpts.count,
19432 maxDigits: this._maxDigits(),
19433 horizontal: this.isHorizontal(),
19434 minRotation: tickOpts.minRotation || 0,
19435 includeBounds: tickOpts.includeBounds !== false
19436 };
19437 const dataRange = this._range || this;
19438 const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
19439 if (opts.bounds === 'ticks') {
19440 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19441 }
19442 if (opts.reverse) {
19443 ticks.reverse();
19444 this.start = this.max;
19445 this.end = this.min;
19446 } else {
19447 this.start = this.min;
19448 this.end = this.max;
19449 }
19450 return ticks;
19451 }
19452 configure() {
19453 const ticks = this.ticks;
19454 let start = this.min;
19455 let end = this.max;
19456 super.configure();
19457 if (this.options.offset && ticks.length) {
19458 const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
19459 start -= offset;
19460 end += offset;
19461 }
19462 this._startValue = start;
19463 this._endValue = end;
19464 this._valueRange = end - start;
19465 }
19466 getLabelForValue(value) {
19467 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19468 }
19469 }
19470
19471 class LinearScale extends LinearScaleBase {
19472 static id = 'linear';
19473 static defaults = {
19474 ticks: {
19475 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19476 }
19477 };
19478 determineDataLimits() {
19479 const { min , max } = this.getMinMax(true);
19480 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? min : 0;
19481 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? max : 1;
19482 this.handleTickRangeOptions();
19483 }
19484 computeTickLimit() {
19485 const horizontal = this.isHorizontal();
19486 const length = horizontal ? this.width : this.height;
19487 const minRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.ticks.minRotation);
19488 const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;
19489 const tickFont = this._resolveTickFontOptions(0);
19490 return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
19491 }
19492 getPixelForValue(value) {
19493 return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
19494 }
19495 getValueForPixel(pixel) {
19496 return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
19497 }
19498 }
19499
19500 const log10Floor = (v)=>Math.floor((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(v));
19501 const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m);
19502 function isMajor(tickVal) {
19503 const remain = tickVal / Math.pow(10, log10Floor(tickVal));
19504 return remain === 1;
19505 }
19506 function steps(min, max, rangeExp) {
19507 const rangeStep = Math.pow(10, rangeExp);
19508 const start = Math.floor(min / rangeStep);
19509 const end = Math.ceil(max / rangeStep);
19510 return end - start;
19511 }
19512 function startExp(min, max) {
19513 const range = max - min;
19514 let rangeExp = log10Floor(range);
19515 while(steps(min, max, rangeExp) > 10){
19516 rangeExp++;
19517 }
19518 while(steps(min, max, rangeExp) < 10){
19519 rangeExp--;
19520 }
19521 return Math.min(rangeExp, log10Floor(min));
19522 }
19523 function generateTicks(generationOptions, { min , max }) {
19524 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, min);
19525 const ticks = [];
19526 const minExp = log10Floor(min);
19527 let exp = startExp(min, max);
19528 let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
19529 const stepSize = Math.pow(10, exp);
19530 const base = minExp > exp ? Math.pow(10, minExp) : 0;
19531 const start = Math.round((min - base) * precision) / precision;
19532 const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;
19533 let significand = Math.floor((start - offset) / Math.pow(10, exp));
19534 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);
19535 while(value < max){
19536 ticks.push({
19537 value,
19538 major: isMajor(value),
19539 significand
19540 });
19541 if (significand >= 10) {
19542 significand = significand < 15 ? 15 : 20;
19543 } else {
19544 significand++;
19545 }
19546 if (significand >= 20) {
19547 exp++;
19548 significand = 2;
19549 precision = exp >= 0 ? 1 : precision;
19550 }
19551 value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;
19552 }
19553 const lastTick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.max, value);
19554 ticks.push({
19555 value: lastTick,
19556 major: isMajor(lastTick),
19557 significand
19558 });
19559 return ticks;
19560 }
19561 class LogarithmicScale extends Scale {
19562 static id = 'logarithmic';
19563 static defaults = {
19564 ticks: {
19565 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.logarithmic,
19566 major: {
19567 enabled: true
19568 }
19569 }
19570 };
19571 constructor(cfg){
19572 super(cfg);
19573 this.start = undefined;
19574 this.end = undefined;
19575 this._startValue = undefined;
19576 this._valueRange = 0;
19577 }
19578 parse(raw, index) {
19579 const value = LinearScaleBase.prototype.parse.apply(this, [
19580 raw,
19581 index
19582 ]);
19583 if (value === 0) {
19584 this._zero = true;
19585 return undefined;
19586 }
19587 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value) && value > 0 ? value : null;
19588 }
19589 determineDataLimits() {
19590 const { min , max } = this.getMinMax(true);
19591 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? Math.max(0, min) : null;
19592 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? Math.max(0, max) : null;
19593 if (this.options.beginAtZero) {
19594 this._zero = true;
19595 }
19596 if (this._zero && this.min !== this._suggestedMin && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(this._userMin)) {
19597 this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);
19598 }
19599 this.handleTickRangeOptions();
19600 }
19601 handleTickRangeOptions() {
19602 const { minDefined , maxDefined } = this.getUserBounds();
19603 let min = this.min;
19604 let max = this.max;
19605 const setMin = (v)=>min = minDefined ? min : v;
19606 const setMax = (v)=>max = maxDefined ? max : v;
19607 if (min === max) {
19608 if (min <= 0) {
19609 setMin(1);
19610 setMax(10);
19611 } else {
19612 setMin(changeExponent(min, -1));
19613 setMax(changeExponent(max, +1));
19614 }
19615 }
19616 if (min <= 0) {
19617 setMin(changeExponent(max, -1));
19618 }
19619 if (max <= 0) {
19620 setMax(changeExponent(min, +1));
19621 }
19622 this.min = min;
19623 this.max = max;
19624 }
19625 buildTicks() {
19626 const opts = this.options;
19627 const generationOptions = {
19628 min: this._userMin,
19629 max: this._userMax
19630 };
19631 const ticks = generateTicks(generationOptions, this);
19632 if (opts.bounds === 'ticks') {
19633 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value');
19634 }
19635 if (opts.reverse) {
19636 ticks.reverse();
19637 this.start = this.max;
19638 this.end = this.min;
19639 } else {
19640 this.start = this.min;
19641 this.end = this.max;
19642 }
19643 return ticks;
19644 }
19645 getLabelForValue(value) {
19646 return value === undefined ? '0' : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format);
19647 }
19648 configure() {
19649 const start = this.min;
19650 super.configure();
19651 this._startValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start);
19652 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);
19653 }
19654 getPixelForValue(value) {
19655 if (value === undefined || value === 0) {
19656 value = this.min;
19657 }
19658 if (value === null || isNaN(value)) {
19659 return NaN;
19660 }
19661 return this.getPixelForDecimal(value === this.min ? 0 : ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(value) - this._startValue) / this._valueRange);
19662 }
19663 getValueForPixel(pixel) {
19664 const decimal = this.getDecimalForPixel(pixel);
19665 return Math.pow(10, this._startValue + decimal * this._valueRange);
19666 }
19667 }
19668
19669 function getTickBackdropHeight(opts) {
19670 const tickOpts = opts.ticks;
19671 if (tickOpts.display && opts.display) {
19672 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(tickOpts.backdropPadding);
19673 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;
19674 }
19675 return 0;
19676 }
19677 function measureLabelSize(ctx, font, label) {
19678 label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label : [
19679 label
19680 ];
19681 return {
19682 w: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aO)(ctx, font.string, label),
19683 h: label.length * font.lineHeight
19684 };
19685 }
19686 function determineLimits(angle, pos, size, min, max) {
19687 if (angle === min || angle === max) {
19688 return {
19689 start: pos - size / 2,
19690 end: pos + size / 2
19691 };
19692 } else if (angle < min || angle > max) {
19693 return {
19694 start: pos - size,
19695 end: pos
19696 };
19697 }
19698 return {
19699 start: pos,
19700 end: pos + size
19701 };
19702 }
19703 function fitWithPointLabels(scale) {
19704 const orig = {
19705 l: scale.left + scale._padding.left,
19706 r: scale.right - scale._padding.right,
19707 t: scale.top + scale._padding.top,
19708 b: scale.bottom - scale._padding.bottom
19709 };
19710 const limits = Object.assign({}, orig);
19711 const labelSizes = [];
19712 const padding = [];
19713 const valueCount = scale._pointLabels.length;
19714 const pointLabelOpts = scale.options.pointLabels;
19715 const additionalAngle = pointLabelOpts.centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0;
19716 for(let i = 0; i < valueCount; i++){
19717 const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
19718 padding[i] = opts.padding;
19719 const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
19720 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font);
19721 const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
19722 labelSizes[i] = textSize;
19723 const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(scale.getIndexAngle(i) + additionalAngle);
19724 const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(angleRadians));
19725 const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
19726 const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
19727 updateLimits(limits, orig, angleRadians, hLimits, vLimits);
19728 }
19729 scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);
19730 scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
19731 }
19732 function updateLimits(limits, orig, angle, hLimits, vLimits) {
19733 const sin = Math.abs(Math.sin(angle));
19734 const cos = Math.abs(Math.cos(angle));
19735 let x = 0;
19736 let y = 0;
19737 if (hLimits.start < orig.l) {
19738 x = (orig.l - hLimits.start) / sin;
19739 limits.l = Math.min(limits.l, orig.l - x);
19740 } else if (hLimits.end > orig.r) {
19741 x = (hLimits.end - orig.r) / sin;
19742 limits.r = Math.max(limits.r, orig.r + x);
19743 }
19744 if (vLimits.start < orig.t) {
19745 y = (orig.t - vLimits.start) / cos;
19746 limits.t = Math.min(limits.t, orig.t - y);
19747 } else if (vLimits.end > orig.b) {
19748 y = (vLimits.end - orig.b) / cos;
19749 limits.b = Math.max(limits.b, orig.b + y);
19750 }
19751 }
19752 function createPointLabelItem(scale, index, itemOpts) {
19753 const outerDistance = scale.drawingArea;
19754 const { extra , additionalAngle , padding , size } = itemOpts;
19755 const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);
19756 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)));
19757 const y = yForAngle(pointLabelPosition.y, size.h, angle);
19758 const textAlign = getTextAlignForAngle(angle);
19759 const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
19760 return {
19761 visible: true,
19762 x: pointLabelPosition.x,
19763 y,
19764 textAlign,
19765 left,
19766 top: y,
19767 right: left + size.w,
19768 bottom: y + size.h
19769 };
19770 }
19771 function isNotOverlapped(item, area) {
19772 if (!area) {
19773 return true;
19774 }
19775 const { left , top , right , bottom } = item;
19776 const apexesInArea = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19777 x: left,
19778 y: top
19779 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19780 x: left,
19781 y: bottom
19782 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19783 x: right,
19784 y: top
19785 }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({
19786 x: right,
19787 y: bottom
19788 }, area);
19789 return !apexesInArea;
19790 }
19791 function buildPointLabelItems(scale, labelSizes, padding) {
19792 const items = [];
19793 const valueCount = scale._pointLabels.length;
19794 const opts = scale.options;
19795 const { centerPointLabels , display } = opts.pointLabels;
19796 const itemOpts = {
19797 extra: getTickBackdropHeight(opts) / 2,
19798 additionalAngle: centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0
19799 };
19800 let area;
19801 for(let i = 0; i < valueCount; i++){
19802 itemOpts.padding = padding[i];
19803 itemOpts.size = labelSizes[i];
19804 const item = createPointLabelItem(scale, i, itemOpts);
19805 items.push(item);
19806 if (display === 'auto') {
19807 item.visible = isNotOverlapped(item, area);
19808 if (item.visible) {
19809 area = item;
19810 }
19811 }
19812 }
19813 return items;
19814 }
19815 function getTextAlignForAngle(angle) {
19816 if (angle === 0 || angle === 180) {
19817 return 'center';
19818 } else if (angle < 180) {
19819 return 'left';
19820 }
19821 return 'right';
19822 }
19823 function leftForTextAlign(x, w, align) {
19824 if (align === 'right') {
19825 x -= w;
19826 } else if (align === 'center') {
19827 x -= w / 2;
19828 }
19829 return x;
19830 }
19831 function yForAngle(y, h, angle) {
19832 if (angle === 90 || angle === 270) {
19833 y -= h / 2;
19834 } else if (angle > 270 || angle < 90) {
19835 y -= h;
19836 }
19837 return y;
19838 }
19839 function drawPointLabelBox(ctx, opts, item) {
19840 const { left , top , right , bottom } = item;
19841 const { backdropColor } = opts;
19842 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(backdropColor)) {
19843 const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(opts.borderRadius);
19844 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.backdropPadding);
19845 ctx.fillStyle = backdropColor;
19846 const backdropLeft = left - padding.left;
19847 const backdropTop = top - padding.top;
19848 const backdropWidth = right - left + padding.width;
19849 const backdropHeight = bottom - top + padding.height;
19850 if (Object.values(borderRadius).some((v)=>v !== 0)) {
19851 ctx.beginPath();
19852 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, {
19853 x: backdropLeft,
19854 y: backdropTop,
19855 w: backdropWidth,
19856 h: backdropHeight,
19857 radius: borderRadius
19858 });
19859 ctx.fill();
19860 } else {
19861 ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);
19862 }
19863 }
19864 }
19865 function drawPointLabels(scale, labelCount) {
19866 const { ctx , options: { pointLabels } } = scale;
19867 for(let i = labelCount - 1; i >= 0; i--){
19868 const item = scale._pointLabelItems[i];
19869 if (!item.visible) {
19870 continue;
19871 }
19872 const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));
19873 drawPointLabelBox(ctx, optsAtIndex, item);
19874 const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
19875 const { x , y , textAlign } = item;
19876 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, {
19877 color: optsAtIndex.color,
19878 textAlign: textAlign,
19879 textBaseline: 'middle'
19880 });
19881 }
19882 }
19883 function pathRadiusLine(scale, radius, circular, labelCount) {
19884 const { ctx } = scale;
19885 if (circular) {
19886 ctx.arc(scale.xCenter, scale.yCenter, radius, 0, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T);
19887 } else {
19888 let pointPosition = scale.getPointPosition(0, radius);
19889 ctx.moveTo(pointPosition.x, pointPosition.y);
19890 for(let i = 1; i < labelCount; i++){
19891 pointPosition = scale.getPointPosition(i, radius);
19892 ctx.lineTo(pointPosition.x, pointPosition.y);
19893 }
19894 }
19895 }
19896 function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {
19897 const ctx = scale.ctx;
19898 const circular = gridLineOpts.circular;
19899 const { color , lineWidth } = gridLineOpts;
19900 if (!circular && !labelCount || !color || !lineWidth || radius < 0) {
19901 return;
19902 }
19903 ctx.save();
19904 ctx.strokeStyle = color;
19905 ctx.lineWidth = lineWidth;
19906 ctx.setLineDash(borderOpts.dash || []);
19907 ctx.lineDashOffset = borderOpts.dashOffset;
19908 ctx.beginPath();
19909 pathRadiusLine(scale, radius, circular, labelCount);
19910 ctx.closePath();
19911 ctx.stroke();
19912 ctx.restore();
19913 }
19914 function createPointLabelContext(parent, index, label) {
19915 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, {
19916 label,
19917 index,
19918 type: 'pointLabel'
19919 });
19920 }
19921 class RadialLinearScale extends LinearScaleBase {
19922 static id = 'radialLinear';
19923 static defaults = {
19924 display: true,
19925 animate: true,
19926 position: 'chartArea',
19927 angleLines: {
19928 display: true,
19929 lineWidth: 1,
19930 borderDash: [],
19931 borderDashOffset: 0.0
19932 },
19933 grid: {
19934 circular: false
19935 },
19936 startAngle: 0,
19937 ticks: {
19938 showLabelBackdrop: true,
19939 callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric
19940 },
19941 pointLabels: {
19942 backdropColor: undefined,
19943 backdropPadding: 2,
19944 display: true,
19945 font: {
19946 size: 10
19947 },
19948 callback (label) {
19949 return label;
19950 },
19951 padding: 5,
19952 centerPointLabels: false
19953 }
19954 };
19955 static defaultRoutes = {
19956 'angleLines.color': 'borderColor',
19957 'pointLabels.color': 'color',
19958 'ticks.color': 'color'
19959 };
19960 static descriptors = {
19961 angleLines: {
19962 _fallback: 'grid'
19963 }
19964 };
19965 constructor(cfg){
19966 super(cfg);
19967 this.xCenter = undefined;
19968 this.yCenter = undefined;
19969 this.drawingArea = undefined;
19970 this._pointLabels = [];
19971 this._pointLabelItems = [];
19972 }
19973 setDimensions() {
19974 const padding = this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(getTickBackdropHeight(this.options) / 2);
19975 const w = this.width = this.maxWidth - padding.width;
19976 const h = this.height = this.maxHeight - padding.height;
19977 this.xCenter = Math.floor(this.left + w / 2 + padding.left);
19978 this.yCenter = Math.floor(this.top + h / 2 + padding.top);
19979 this.drawingArea = Math.floor(Math.min(w, h) / 2);
19980 }
19981 determineDataLimits() {
19982 const { min , max } = this.getMinMax(false);
19983 this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : 0;
19984 this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : 0;
19985 this.handleTickRangeOptions();
19986 }
19987 computeTickLimit() {
19988 return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
19989 }
19990 generateTickLabels(ticks) {
19991 LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
19992 this._pointLabels = this.getLabels().map((value, index)=>{
19993 const label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.pointLabels.callback, [
19994 value,
19995 index
19996 ], this);
19997 return label || label === 0 ? label : '';
19998 }).filter((v, i)=>this.chart.getDataVisibility(i));
19999 }
20000 fit() {
20001 const opts = this.options;
20002 if (opts.display && opts.pointLabels.display) {
20003 fitWithPointLabels(this);
20004 } else {
20005 this.setCenterPoint(0, 0, 0, 0);
20006 }
20007 }
20008 setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
20009 this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
20010 this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
20011 this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
20012 }
20013 getIndexAngle(index) {
20014 const angleMultiplier = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T / (this._pointLabels.length || 1);
20015 const startAngle = this.options.startAngle || 0;
20016 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(index * angleMultiplier + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(startAngle));
20017 }
20018 getDistanceFromCenterForValue(value) {
20019 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) {
20020 return NaN;
20021 }
20022 const scalingFactor = this.drawingArea / (this.max - this.min);
20023 if (this.options.reverse) {
20024 return (this.max - value) * scalingFactor;
20025 }
20026 return (value - this.min) * scalingFactor;
20027 }
20028 getValueForDistanceFromCenter(distance) {
20029 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(distance)) {
20030 return NaN;
20031 }
20032 const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
20033 return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
20034 }
20035 getPointLabelContext(index) {
20036 const pointLabels = this._pointLabels || [];
20037 if (index >= 0 && index < pointLabels.length) {
20038 const pointLabel = pointLabels[index];
20039 return createPointLabelContext(this.getContext(), index, pointLabel);
20040 }
20041 }
20042 getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
20043 const angle = this.getIndexAngle(index) - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H + additionalAngle;
20044 return {
20045 x: Math.cos(angle) * distanceFromCenter + this.xCenter,
20046 y: Math.sin(angle) * distanceFromCenter + this.yCenter,
20047 angle
20048 };
20049 }
20050 getPointPositionForValue(index, value) {
20051 return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
20052 }
20053 getBasePosition(index) {
20054 return this.getPointPositionForValue(index || 0, this.getBaseValue());
20055 }
20056 getPointLabelPosition(index) {
20057 const { left , top , right , bottom } = this._pointLabelItems[index];
20058 return {
20059 left,
20060 top,
20061 right,
20062 bottom
20063 };
20064 }
20065 drawBackground() {
20066 const { backgroundColor , grid: { circular } } = this.options;
20067 if (backgroundColor) {
20068 const ctx = this.ctx;
20069 ctx.save();
20070 ctx.beginPath();
20071 pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
20072 ctx.closePath();
20073 ctx.fillStyle = backgroundColor;
20074 ctx.fill();
20075 ctx.restore();
20076 }
20077 }
20078 drawGrid() {
20079 const ctx = this.ctx;
20080 const opts = this.options;
20081 const { angleLines , grid , border } = opts;
20082 const labelCount = this._pointLabels.length;
20083 let i, offset, position;
20084 if (opts.pointLabels.display) {
20085 drawPointLabels(this, labelCount);
20086 }
20087 if (grid.display) {
20088 this.ticks.forEach((tick, index)=>{
20089 if (index !== 0 || index === 0 && this.min < 0) {
20090 offset = this.getDistanceFromCenterForValue(tick.value);
20091 const context = this.getContext(index);
20092 const optsAtIndex = grid.setContext(context);
20093 const optsAtIndexBorder = border.setContext(context);
20094 drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);
20095 }
20096 });
20097 }
20098 if (angleLines.display) {
20099 ctx.save();
20100 for(i = labelCount - 1; i >= 0; i--){
20101 const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
20102 const { color , lineWidth } = optsAtIndex;
20103 if (!lineWidth || !color) {
20104 continue;
20105 }
20106 ctx.lineWidth = lineWidth;
20107 ctx.strokeStyle = color;
20108 ctx.setLineDash(optsAtIndex.borderDash);
20109 ctx.lineDashOffset = optsAtIndex.borderDashOffset;
20110 offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);
20111 position = this.getPointPosition(i, offset);
20112 ctx.beginPath();
20113 ctx.moveTo(this.xCenter, this.yCenter);
20114 ctx.lineTo(position.x, position.y);
20115 ctx.stroke();
20116 }
20117 ctx.restore();
20118 }
20119 }
20120 drawBorder() {}
20121 drawLabels() {
20122 const ctx = this.ctx;
20123 const opts = this.options;
20124 const tickOpts = opts.ticks;
20125 if (!tickOpts.display) {
20126 return;
20127 }
20128 const startAngle = this.getIndexAngle(0);
20129 let offset, width;
20130 ctx.save();
20131 ctx.translate(this.xCenter, this.yCenter);
20132 ctx.rotate(startAngle);
20133 ctx.textAlign = 'center';
20134 ctx.textBaseline = 'middle';
20135 this.ticks.forEach((tick, index)=>{
20136 if (index === 0 && this.min >= 0 && !opts.reverse) {
20137 return;
20138 }
20139 const optsAtIndex = tickOpts.setContext(this.getContext(index));
20140 const tickFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font);
20141 offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
20142 if (optsAtIndex.showLabelBackdrop) {
20143 ctx.font = tickFont.string;
20144 width = ctx.measureText(tick.label).width;
20145 ctx.fillStyle = optsAtIndex.backdropColor;
20146 const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding);
20147 ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);
20148 }
20149 ;(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, tick.label, 0, -offset, tickFont, {
20150 color: optsAtIndex.color,
20151 strokeColor: optsAtIndex.textStrokeColor,
20152 strokeWidth: optsAtIndex.textStrokeWidth
20153 });
20154 });
20155 ctx.restore();
20156 }
20157 drawTitle() {}
20158 }
20159
20160 const INTERVALS = {
20161 millisecond: {
20162 common: true,
20163 size: 1,
20164 steps: 1000
20165 },
20166 second: {
20167 common: true,
20168 size: 1000,
20169 steps: 60
20170 },
20171 minute: {
20172 common: true,
20173 size: 60000,
20174 steps: 60
20175 },
20176 hour: {
20177 common: true,
20178 size: 3600000,
20179 steps: 24
20180 },
20181 day: {
20182 common: true,
20183 size: 86400000,
20184 steps: 30
20185 },
20186 week: {
20187 common: false,
20188 size: 604800000,
20189 steps: 4
20190 },
20191 month: {
20192 common: true,
20193 size: 2.628e9,
20194 steps: 12
20195 },
20196 quarter: {
20197 common: false,
20198 size: 7.884e9,
20199 steps: 4
20200 },
20201 year: {
20202 common: true,
20203 size: 3.154e10
20204 }
20205 };
20206 const UNITS = /* #__PURE__ */ Object.keys(INTERVALS);
20207 function sorter(a, b) {
20208 return a - b;
20209 }
20210 function parse(scale, input) {
20211 if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(input)) {
20212 return null;
20213 }
20214 const adapter = scale._adapter;
20215 const { parser , round , isoWeekday } = scale._parseOpts;
20216 let value = input;
20217 if (typeof parser === 'function') {
20218 value = parser(value);
20219 }
20220 if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) {
20221 value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value);
20222 }
20223 if (value === null) {
20224 return null;
20225 }
20226 if (round) {
20227 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);
20228 }
20229 return +value;
20230 }
20231 function determineUnitForAutoTicks(minUnit, min, max, capacity) {
20232 const ilen = UNITS.length;
20233 for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){
20234 const interval = INTERVALS[UNITS[i]];
20235 const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
20236 if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
20237 return UNITS[i];
20238 }
20239 }
20240 return UNITS[ilen - 1];
20241 }
20242 function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
20243 for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){
20244 const unit = UNITS[i];
20245 if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
20246 return unit;
20247 }
20248 }
20249 return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
20250 }
20251 function determineMajorUnit(unit) {
20252 for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){
20253 if (INTERVALS[UNITS[i]].common) {
20254 return UNITS[i];
20255 }
20256 }
20257 }
20258 function addTick(ticks, time, timestamps) {
20259 if (!timestamps) {
20260 ticks[time] = true;
20261 } else if (timestamps.length) {
20262 const { lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aQ)(timestamps, time);
20263 const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
20264 ticks[timestamp] = true;
20265 }
20266 }
20267 function setMajorTicks(scale, ticks, map, majorUnit) {
20268 const adapter = scale._adapter;
20269 const first = +adapter.startOf(ticks[0].value, majorUnit);
20270 const last = ticks[ticks.length - 1].value;
20271 let major, index;
20272 for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){
20273 index = map[major];
20274 if (index >= 0) {
20275 ticks[index].major = true;
20276 }
20277 }
20278 return ticks;
20279 }
20280 function ticksFromTimestamps(scale, values, majorUnit) {
20281 const ticks = [];
20282 const map = {};
20283 const ilen = values.length;
20284 let i, value;
20285 for(i = 0; i < ilen; ++i){
20286 value = values[i];
20287 map[value] = i;
20288 ticks.push({
20289 value,
20290 major: false
20291 });
20292 }
20293 return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
20294 }
20295 class TimeScale extends Scale {
20296 static id = 'time';
20297 static defaults = {
20298 bounds: 'data',
20299 adapters: {},
20300 time: {
20301 parser: false,
20302 unit: false,
20303 round: false,
20304 isoWeekday: false,
20305 minUnit: 'millisecond',
20306 displayFormats: {}
20307 },
20308 ticks: {
20309 source: 'auto',
20310 callback: false,
20311 major: {
20312 enabled: false
20313 }
20314 }
20315 };
20316 constructor(props){
20317 super(props);
20318 this._cache = {
20319 data: [],
20320 labels: [],
20321 all: []
20322 };
20323 this._unit = 'day';
20324 this._majorUnit = undefined;
20325 this._offsets = {};
20326 this._normalized = false;
20327 this._parseOpts = undefined;
20328 }
20329 init(scaleOpts, opts = {}) {
20330 const time = scaleOpts.time || (scaleOpts.time = {});
20331 const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
20332 adapter.init(opts);
20333 (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(time.displayFormats, adapter.formats());
20334 this._parseOpts = {
20335 parser: time.parser,
20336 round: time.round,
20337 isoWeekday: time.isoWeekday
20338 };
20339 super.init(scaleOpts);
20340 this._normalized = opts.normalized;
20341 }
20342 parse(raw, index) {
20343 if (raw === undefined) {
20344 return null;
20345 }
20346 return parse(this, raw);
20347 }
20348 beforeLayout() {
20349 super.beforeLayout();
20350 this._cache = {
20351 data: [],
20352 labels: [],
20353 all: []
20354 };
20355 }
20356 determineDataLimits() {
20357 const options = this.options;
20358 const adapter = this._adapter;
20359 const unit = options.time.unit || 'day';
20360 let { min , max , minDefined , maxDefined } = this.getUserBounds();
20361 function _applyBounds(bounds) {
20362 if (!minDefined && !isNaN(bounds.min)) {
20363 min = Math.min(min, bounds.min);
20364 }
20365 if (!maxDefined && !isNaN(bounds.max)) {
20366 max = Math.max(max, bounds.max);
20367 }
20368 }
20369 if (!minDefined || !maxDefined) {
20370 _applyBounds(this._getLabelBounds());
20371 if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
20372 _applyBounds(this.getMinMax(false));
20373 }
20374 }
20375 min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
20376 max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
20377 this.min = Math.min(min, max - 1);
20378 this.max = Math.max(min + 1, max);
20379 }
20380 _getLabelBounds() {
20381 const arr = this.getLabelTimestamps();
20382 let min = Number.POSITIVE_INFINITY;
20383 let max = Number.NEGATIVE_INFINITY;
20384 if (arr.length) {
20385 min = arr[0];
20386 max = arr[arr.length - 1];
20387 }
20388 return {
20389 min,
20390 max
20391 };
20392 }
20393 buildTicks() {
20394 const options = this.options;
20395 const timeOpts = options.time;
20396 const tickOpts = options.ticks;
20397 const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();
20398 if (options.bounds === 'ticks' && timestamps.length) {
20399 this.min = this._userMin || timestamps[0];
20400 this.max = this._userMax || timestamps[timestamps.length - 1];
20401 }
20402 const min = this.min;
20403 const max = this.max;
20404 const ticks = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aP)(timestamps, min, max);
20405 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));
20406 this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit);
20407 this.initOffsets(timestamps);
20408 if (options.reverse) {
20409 ticks.reverse();
20410 }
20411 return ticksFromTimestamps(this, ticks, this._majorUnit);
20412 }
20413 afterAutoSkip() {
20414 if (this.options.offsetAfterAutoskip) {
20415 this.initOffsets(this.ticks.map((tick)=>+tick.value));
20416 }
20417 }
20418 initOffsets(timestamps = []) {
20419 let start = 0;
20420 let end = 0;
20421 let first, last;
20422 if (this.options.offset && timestamps.length) {
20423 first = this.getDecimalForValue(timestamps[0]);
20424 if (timestamps.length === 1) {
20425 start = 1 - first;
20426 } else {
20427 start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
20428 }
20429 last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
20430 if (timestamps.length === 1) {
20431 end = last;
20432 } else {
20433 end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
20434 }
20435 }
20436 const limit = timestamps.length < 3 ? 0.5 : 0.25;
20437 start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(start, 0, limit);
20438 end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(end, 0, limit);
20439 this._offsets = {
20440 start,
20441 end,
20442 factor: 1 / (start + 1 + end)
20443 };
20444 }
20445 _generate() {
20446 const adapter = this._adapter;
20447 const min = this.min;
20448 const max = this.max;
20449 const options = this.options;
20450 const timeOpts = options.time;
20451 const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
20452 const stepSize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.stepSize, 1);
20453 const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
20454 const hasWeekday = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(weekday) || weekday === true;
20455 const ticks = {};
20456 let first = min;
20457 let time, count;
20458 if (hasWeekday) {
20459 first = +adapter.startOf(first, 'isoWeek', weekday);
20460 }
20461 first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
20462 if (adapter.diff(max, min, minor) > 100000 * stepSize) {
20463 throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
20464 }
20465 const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();
20466 for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){
20467 addTick(ticks, time, timestamps);
20468 }
20469 if (time === max || options.bounds === 'ticks' || count === 1) {
20470 addTick(ticks, time, timestamps);
20471 }
20472 return Object.keys(ticks).sort(sorter).map((x)=>+x);
20473 }
20474 getLabelForValue(value) {
20475 const adapter = this._adapter;
20476 const timeOpts = this.options.time;
20477 if (timeOpts.tooltipFormat) {
20478 return adapter.format(value, timeOpts.tooltipFormat);
20479 }
20480 return adapter.format(value, timeOpts.displayFormats.datetime);
20481 }
20482 format(value, format) {
20483 const options = this.options;
20484 const formats = options.time.displayFormats;
20485 const unit = this._unit;
20486 const fmt = format || formats[unit];
20487 return this._adapter.format(value, fmt);
20488 }
20489 _tickFormatFunction(time, index, ticks, format) {
20490 const options = this.options;
20491 const formatter = options.ticks.callback;
20492 if (formatter) {
20493 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(formatter, [
20494 time,
20495 index,
20496 ticks
20497 ], this);
20498 }
20499 const formats = options.time.displayFormats;
20500 const unit = this._unit;
20501 const majorUnit = this._majorUnit;
20502 const minorFormat = unit && formats[unit];
20503 const majorFormat = majorUnit && formats[majorUnit];
20504 const tick = ticks[index];
20505 const major = majorUnit && majorFormat && tick && tick.major;
20506 return this._adapter.format(time, format || (major ? majorFormat : minorFormat));
20507 }
20508 generateTickLabels(ticks) {
20509 let i, ilen, tick;
20510 for(i = 0, ilen = ticks.length; i < ilen; ++i){
20511 tick = ticks[i];
20512 tick.label = this._tickFormatFunction(tick.value, i, ticks);
20513 }
20514 }
20515 getDecimalForValue(value) {
20516 return value === null ? NaN : (value - this.min) / (this.max - this.min);
20517 }
20518 getPixelForValue(value) {
20519 const offsets = this._offsets;
20520 const pos = this.getDecimalForValue(value);
20521 return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
20522 }
20523 getValueForPixel(pixel) {
20524 const offsets = this._offsets;
20525 const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20526 return this.min + pos * (this.max - this.min);
20527 }
20528 _getLabelSize(label) {
20529 const ticksOpts = this.options.ticks;
20530 const tickLabelWidth = this.ctx.measureText(label).width;
20531 const angle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
20532 const cosRotation = Math.cos(angle);
20533 const sinRotation = Math.sin(angle);
20534 const tickFontSize = this._resolveTickFontOptions(0).size;
20535 return {
20536 w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,
20537 h: tickLabelWidth * sinRotation + tickFontSize * cosRotation
20538 };
20539 }
20540 _getLabelCapacity(exampleTime) {
20541 const timeOpts = this.options.time;
20542 const displayFormats = timeOpts.displayFormats;
20543 const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
20544 const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [
20545 exampleTime
20546 ], this._majorUnit), format);
20547 const size = this._getLabelSize(exampleLabel);
20548 const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
20549 return capacity > 0 ? capacity : 1;
20550 }
20551 getDataTimestamps() {
20552 let timestamps = this._cache.data || [];
20553 let i, ilen;
20554 if (timestamps.length) {
20555 return timestamps;
20556 }
20557 const metas = this.getMatchingVisibleMetas();
20558 if (this._normalized && metas.length) {
20559 return this._cache.data = metas[0].controller.getAllParsedValues(this);
20560 }
20561 for(i = 0, ilen = metas.length; i < ilen; ++i){
20562 timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));
20563 }
20564 return this._cache.data = this.normalize(timestamps);
20565 }
20566 getLabelTimestamps() {
20567 const timestamps = this._cache.labels || [];
20568 let i, ilen;
20569 if (timestamps.length) {
20570 return timestamps;
20571 }
20572 const labels = this.getLabels();
20573 for(i = 0, ilen = labels.length; i < ilen; ++i){
20574 timestamps.push(parse(this, labels[i]));
20575 }
20576 return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);
20577 }
20578 normalize(values) {
20579 return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort(sorter));
20580 }
20581 }
20582
20583 function interpolate(table, val, reverse) {
20584 let lo = 0;
20585 let hi = table.length - 1;
20586 let prevSource, nextSource, prevTarget, nextTarget;
20587 if (reverse) {
20588 if (val >= table[lo].pos && val <= table[hi].pos) {
20589 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'pos', val));
20590 }
20591 ({ pos: prevSource , time: prevTarget } = table[lo]);
20592 ({ pos: nextSource , time: nextTarget } = table[hi]);
20593 } else {
20594 if (val >= table[lo].time && val <= table[hi].time) {
20595 ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'time', val));
20596 }
20597 ({ time: prevSource , pos: prevTarget } = table[lo]);
20598 ({ time: nextSource , pos: nextTarget } = table[hi]);
20599 }
20600 const span = nextSource - prevSource;
20601 return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
20602 }
20603 class TimeSeriesScale extends TimeScale {
20604 static id = 'timeseries';
20605 static defaults = TimeScale.defaults;
20606 constructor(props){
20607 super(props);
20608 this._table = [];
20609 this._minPos = undefined;
20610 this._tableRange = undefined;
20611 }
20612 initOffsets() {
20613 const timestamps = this._getTimestampsForTable();
20614 const table = this._table = this.buildLookupTable(timestamps);
20615 this._minPos = interpolate(table, this.min);
20616 this._tableRange = interpolate(table, this.max) - this._minPos;
20617 super.initOffsets(timestamps);
20618 }
20619 buildLookupTable(timestamps) {
20620 const { min , max } = this;
20621 const items = [];
20622 const table = [];
20623 let i, ilen, prev, curr, next;
20624 for(i = 0, ilen = timestamps.length; i < ilen; ++i){
20625 curr = timestamps[i];
20626 if (curr >= min && curr <= max) {
20627 items.push(curr);
20628 }
20629 }
20630 if (items.length < 2) {
20631 return [
20632 {
20633 time: min,
20634 pos: 0
20635 },
20636 {
20637 time: max,
20638 pos: 1
20639 }
20640 ];
20641 }
20642 for(i = 0, ilen = items.length; i < ilen; ++i){
20643 next = items[i + 1];
20644 prev = items[i - 1];
20645 curr = items[i];
20646 if (Math.round((next + prev) / 2) !== curr) {
20647 table.push({
20648 time: curr,
20649 pos: i / (ilen - 1)
20650 });
20651 }
20652 }
20653 return table;
20654 }
20655 _generate() {
20656 const min = this.min;
20657 const max = this.max;
20658 let timestamps = super.getDataTimestamps();
20659 if (!timestamps.includes(min) || !timestamps.length) {
20660 timestamps.splice(0, 0, min);
20661 }
20662 if (!timestamps.includes(max) || timestamps.length === 1) {
20663 timestamps.push(max);
20664 }
20665 return timestamps.sort((a, b)=>a - b);
20666 }
20667 _getTimestampsForTable() {
20668 let timestamps = this._cache.all || [];
20669 if (timestamps.length) {
20670 return timestamps;
20671 }
20672 const data = this.getDataTimestamps();
20673 const label = this.getLabelTimestamps();
20674 if (data.length && label.length) {
20675 timestamps = this.normalize(data.concat(label));
20676 } else {
20677 timestamps = data.length ? data : label;
20678 }
20679 timestamps = this._cache.all = timestamps;
20680 return timestamps;
20681 }
20682 getDecimalForValue(value) {
20683 return (interpolate(this._table, value) - this._minPos) / this._tableRange;
20684 }
20685 getValueForPixel(pixel) {
20686 const offsets = this._offsets;
20687 const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
20688 return interpolate(this._table, decimal * this._tableRange + this._minPos, true);
20689 }
20690 }
20691
20692 var scales = /*#__PURE__*/Object.freeze({
20693 __proto__: null,
20694 CategoryScale: CategoryScale,
20695 LinearScale: LinearScale,
20696 LogarithmicScale: LogarithmicScale,
20697 RadialLinearScale: RadialLinearScale,
20698 TimeScale: TimeScale,
20699 TimeSeriesScale: TimeSeriesScale
20700 });
20701
20702 const registerables = [
20703 controllers,
20704 elements,
20705 plugins,
20706 scales
20707 ];
20708
20709
20710 //# sourceMappingURL=chart.js.map
20711
20712
20713 /***/ },
20714
20715 /***/ "./node_modules/chart.js/dist/chunks/helpers.dataset.js"
20716 /*!**************************************************************!*\
20717 !*** ./node_modules/chart.js/dist/chunks/helpers.dataset.js ***!
20718 \**************************************************************/
20719 (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
20720
20721 "use strict";
20722 __webpack_require__.r(__webpack_exports__);
20723 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
20724 /* harmony export */ $: () => (/* binding */ unclipArea),
20725 /* harmony export */ A: () => (/* binding */ _rlookupByKey),
20726 /* harmony export */ B: () => (/* binding */ _lookupByKey),
20727 /* harmony export */ C: () => (/* binding */ _isPointInArea),
20728 /* harmony export */ D: () => (/* binding */ getAngleFromPoint),
20729 /* harmony export */ E: () => (/* binding */ toPadding),
20730 /* harmony export */ F: () => (/* binding */ each),
20731 /* harmony export */ G: () => (/* binding */ getMaximumSize),
20732 /* harmony export */ H: () => (/* binding */ HALF_PI),
20733 /* harmony export */ I: () => (/* binding */ _getParentNode),
20734 /* harmony export */ J: () => (/* binding */ readUsedSize),
20735 /* harmony export */ K: () => (/* binding */ supportsEventListenerOptions),
20736 /* harmony export */ L: () => (/* binding */ throttled),
20737 /* harmony export */ M: () => (/* binding */ _isDomSupported),
20738 /* harmony export */ N: () => (/* binding */ _factorize),
20739 /* harmony export */ O: () => (/* binding */ finiteOrDefault),
20740 /* harmony export */ P: () => (/* binding */ PI),
20741 /* harmony export */ Q: () => (/* binding */ callback),
20742 /* harmony export */ R: () => (/* binding */ _addGrace),
20743 /* harmony export */ S: () => (/* binding */ _limitValue),
20744 /* harmony export */ T: () => (/* binding */ TAU),
20745 /* harmony export */ U: () => (/* binding */ toDegrees),
20746 /* harmony export */ V: () => (/* binding */ _measureText),
20747 /* harmony export */ W: () => (/* binding */ _int16Range),
20748 /* harmony export */ X: () => (/* binding */ _alignPixel),
20749 /* harmony export */ Y: () => (/* binding */ clipArea),
20750 /* harmony export */ Z: () => (/* binding */ renderText),
20751 /* harmony export */ _: () => (/* binding */ _arrayUnique),
20752 /* harmony export */ a: () => (/* binding */ resolve),
20753 /* harmony export */ a$: () => (/* binding */ getStyle),
20754 /* harmony export */ a0: () => (/* binding */ toFont),
20755 /* harmony export */ a1: () => (/* binding */ _toLeftRightCenter),
20756 /* harmony export */ a2: () => (/* binding */ _alignStartEnd),
20757 /* harmony export */ a3: () => (/* binding */ overrides),
20758 /* harmony export */ a4: () => (/* binding */ merge),
20759 /* harmony export */ a5: () => (/* binding */ _capitalize),
20760 /* harmony export */ a6: () => (/* binding */ descriptors),
20761 /* harmony export */ a7: () => (/* binding */ isFunction),
20762 /* harmony export */ a8: () => (/* binding */ _attachContext),
20763 /* harmony export */ a9: () => (/* binding */ _createResolver),
20764 /* harmony export */ aA: () => (/* binding */ getRtlAdapter),
20765 /* harmony export */ aB: () => (/* binding */ overrideTextDirection),
20766 /* harmony export */ aC: () => (/* binding */ _textX),
20767 /* harmony export */ aD: () => (/* binding */ restoreTextDirection),
20768 /* harmony export */ aE: () => (/* binding */ drawPointLegend),
20769 /* harmony export */ aF: () => (/* binding */ distanceBetweenPoints),
20770 /* harmony export */ aG: () => (/* binding */ noop),
20771 /* harmony export */ aH: () => (/* binding */ _setMinAndMaxByKey),
20772 /* harmony export */ aI: () => (/* binding */ niceNum),
20773 /* harmony export */ aJ: () => (/* binding */ almostWhole),
20774 /* harmony export */ aK: () => (/* binding */ almostEquals),
20775 /* harmony export */ aL: () => (/* binding */ _decimalPlaces),
20776 /* harmony export */ aM: () => (/* binding */ Ticks),
20777 /* harmony export */ aN: () => (/* binding */ log10),
20778 /* harmony export */ aO: () => (/* binding */ _longestText),
20779 /* harmony export */ aP: () => (/* binding */ _filterBetween),
20780 /* harmony export */ aQ: () => (/* binding */ _lookup),
20781 /* harmony export */ aR: () => (/* binding */ isPatternOrGradient),
20782 /* harmony export */ aS: () => (/* binding */ getHoverColor),
20783 /* harmony export */ aT: () => (/* binding */ clone),
20784 /* harmony export */ aU: () => (/* binding */ _merger),
20785 /* harmony export */ aV: () => (/* binding */ _mergerIf),
20786 /* harmony export */ aW: () => (/* binding */ _deprecated),
20787 /* harmony export */ aX: () => (/* binding */ _splitKey),
20788 /* harmony export */ aY: () => (/* binding */ toFontString),
20789 /* harmony export */ aZ: () => (/* binding */ splineCurve),
20790 /* harmony export */ a_: () => (/* binding */ splineCurveMonotone),
20791 /* harmony export */ aa: () => (/* binding */ _descriptors),
20792 /* harmony export */ ab: () => (/* binding */ mergeIf),
20793 /* harmony export */ ac: () => (/* binding */ uid),
20794 /* harmony export */ ad: () => (/* binding */ debounce),
20795 /* harmony export */ ae: () => (/* binding */ retinaScale),
20796 /* harmony export */ af: () => (/* binding */ clearCanvas),
20797 /* harmony export */ ag: () => (/* binding */ setsEqual),
20798 /* harmony export */ ah: () => (/* binding */ getDatasetClipArea),
20799 /* harmony export */ ai: () => (/* binding */ _elementsEqual),
20800 /* harmony export */ aj: () => (/* binding */ _isClickEvent),
20801 /* harmony export */ ak: () => (/* binding */ _isBetween),
20802 /* harmony export */ al: () => (/* binding */ _normalizeAngle),
20803 /* harmony export */ am: () => (/* binding */ _readValueToProps),
20804 /* harmony export */ an: () => (/* binding */ _updateBezierControlPoints),
20805 /* harmony export */ ao: () => (/* binding */ _computeSegments),
20806 /* harmony export */ ap: () => (/* binding */ _boundSegments),
20807 /* harmony export */ aq: () => (/* binding */ _steppedInterpolation),
20808 /* harmony export */ ar: () => (/* binding */ _bezierInterpolation),
20809 /* harmony export */ as: () => (/* binding */ _pointInLine),
20810 /* harmony export */ at: () => (/* binding */ _steppedLineTo),
20811 /* harmony export */ au: () => (/* binding */ _bezierCurveTo),
20812 /* harmony export */ av: () => (/* binding */ drawPoint),
20813 /* harmony export */ aw: () => (/* binding */ addRoundedRectPath),
20814 /* harmony export */ ax: () => (/* binding */ toTRBL),
20815 /* harmony export */ ay: () => (/* binding */ toTRBLCorners),
20816 /* harmony export */ az: () => (/* binding */ _boundSegment),
20817 /* harmony export */ b: () => (/* binding */ isArray),
20818 /* harmony export */ b0: () => (/* binding */ fontString),
20819 /* harmony export */ b1: () => (/* binding */ toLineHeight),
20820 /* harmony export */ b2: () => (/* binding */ PITAU),
20821 /* harmony export */ b3: () => (/* binding */ INFINITY),
20822 /* harmony export */ b4: () => (/* binding */ RAD_PER_DEG),
20823 /* harmony export */ b5: () => (/* binding */ QUARTER_PI),
20824 /* harmony export */ b6: () => (/* binding */ TWO_THIRDS_PI),
20825 /* harmony export */ b7: () => (/* binding */ _angleDiff),
20826 /* harmony export */ c: () => (/* binding */ color),
20827 /* harmony export */ d: () => (/* binding */ defaults),
20828 /* harmony export */ e: () => (/* binding */ effects),
20829 /* harmony export */ f: () => (/* binding */ resolveObjectKey),
20830 /* harmony export */ g: () => (/* binding */ isNumberFinite),
20831 /* harmony export */ h: () => (/* binding */ defined),
20832 /* harmony export */ i: () => (/* binding */ isObject),
20833 /* harmony export */ j: () => (/* binding */ createContext),
20834 /* harmony export */ k: () => (/* binding */ isNullOrUndef),
20835 /* harmony export */ l: () => (/* binding */ listenArrayEvents),
20836 /* harmony export */ m: () => (/* binding */ toPercentage),
20837 /* harmony export */ n: () => (/* binding */ toDimension),
20838 /* harmony export */ o: () => (/* binding */ formatNumber),
20839 /* harmony export */ p: () => (/* binding */ _angleBetween),
20840 /* harmony export */ q: () => (/* binding */ _getStartAndCountOfVisiblePoints),
20841 /* harmony export */ r: () => (/* binding */ requestAnimFrame),
20842 /* harmony export */ s: () => (/* binding */ sign),
20843 /* harmony export */ t: () => (/* binding */ toRadians),
20844 /* harmony export */ u: () => (/* binding */ unlistenArrayEvents),
20845 /* harmony export */ v: () => (/* binding */ valueOrDefault),
20846 /* harmony export */ w: () => (/* binding */ _scaleRangesChanged),
20847 /* harmony export */ x: () => (/* binding */ isNumber),
20848 /* harmony export */ y: () => (/* binding */ _parseObjectDataRadialScale),
20849 /* harmony export */ z: () => (/* binding */ getRelativePosition)
20850 /* harmony export */ });
20851 /* harmony import */ var _kurkle_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kurkle/color */ "./node_modules/@kurkle/color/dist/color.esm.js");
20852 /*!
20853 * Chart.js v4.5.1
20854 * https://www.chartjs.org
20855 * (c) 2025 Chart.js Contributors
20856 * Released under the MIT License
20857 */
20858
20859
20860 /**
20861 * @namespace Chart.helpers
20862 */ /**
20863 * An empty function that can be used, for example, for optional callback.
20864 */ function noop() {
20865 /* noop */ }
20866 /**
20867 * Returns a unique id, sequentially generated from a global variable.
20868 */ const uid = (()=>{
20869 let id = 0;
20870 return ()=>id++;
20871 })();
20872 /**
20873 * Returns true if `value` is neither null nor undefined, else returns false.
20874 * @param value - The value to test.
20875 * @since 2.7.0
20876 */ function isNullOrUndef(value) {
20877 return value === null || value === undefined;
20878 }
20879 /**
20880 * Returns true if `value` is an array (including typed arrays), else returns false.
20881 * @param value - The value to test.
20882 * @function
20883 */ function isArray(value) {
20884 if (Array.isArray && Array.isArray(value)) {
20885 return true;
20886 }
20887 const type = Object.prototype.toString.call(value);
20888 if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') {
20889 return true;
20890 }
20891 return false;
20892 }
20893 /**
20894 * Returns true if `value` is an object (excluding null), else returns false.
20895 * @param value - The value to test.
20896 * @since 2.7.0
20897 */ function isObject(value) {
20898 return value !== null && Object.prototype.toString.call(value) === '[object Object]';
20899 }
20900 /**
20901 * Returns true if `value` is a finite number, else returns false
20902 * @param value - The value to test.
20903 */ function isNumberFinite(value) {
20904 return (typeof value === 'number' || value instanceof Number) && isFinite(+value);
20905 }
20906 /**
20907 * Returns `value` if finite, else returns `defaultValue`.
20908 * @param value - The value to return if defined.
20909 * @param defaultValue - The value to return if `value` is not finite.
20910 */ function finiteOrDefault(value, defaultValue) {
20911 return isNumberFinite(value) ? value : defaultValue;
20912 }
20913 /**
20914 * Returns `value` if defined, else returns `defaultValue`.
20915 * @param value - The value to return if defined.
20916 * @param defaultValue - The value to return if `value` is undefined.
20917 */ function valueOrDefault(value, defaultValue) {
20918 return typeof value === 'undefined' ? defaultValue : value;
20919 }
20920 const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;
20921 const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;
20922 /**
20923 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
20924 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
20925 * @param fn - The function to call.
20926 * @param args - The arguments with which `fn` should be called.
20927 * @param [thisArg] - The value of `this` provided for the call to `fn`.
20928 */ function callback(fn, args, thisArg) {
20929 if (fn && typeof fn.call === 'function') {
20930 return fn.apply(thisArg, args);
20931 }
20932 }
20933 function each(loopable, fn, thisArg, reverse) {
20934 let i, len, keys;
20935 if (isArray(loopable)) {
20936 len = loopable.length;
20937 if (reverse) {
20938 for(i = len - 1; i >= 0; i--){
20939 fn.call(thisArg, loopable[i], i);
20940 }
20941 } else {
20942 for(i = 0; i < len; i++){
20943 fn.call(thisArg, loopable[i], i);
20944 }
20945 }
20946 } else if (isObject(loopable)) {
20947 keys = Object.keys(loopable);
20948 len = keys.length;
20949 for(i = 0; i < len; i++){
20950 fn.call(thisArg, loopable[keys[i]], keys[i]);
20951 }
20952 }
20953 }
20954 /**
20955 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
20956 * @param a0 - The array to compare
20957 * @param a1 - The array to compare
20958 * @private
20959 */ function _elementsEqual(a0, a1) {
20960 let i, ilen, v0, v1;
20961 if (!a0 || !a1 || a0.length !== a1.length) {
20962 return false;
20963 }
20964 for(i = 0, ilen = a0.length; i < ilen; ++i){
20965 v0 = a0[i];
20966 v1 = a1[i];
20967 if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
20968 return false;
20969 }
20970 }
20971 return true;
20972 }
20973 /**
20974 * Returns a deep copy of `source` without keeping references on objects and arrays.
20975 * @param source - The value to clone.
20976 */ function clone(source) {
20977 if (isArray(source)) {
20978 return source.map(clone);
20979 }
20980 if (isObject(source)) {
20981 const target = Object.create(null);
20982 const keys = Object.keys(source);
20983 const klen = keys.length;
20984 let k = 0;
20985 for(; k < klen; ++k){
20986 target[keys[k]] = clone(source[keys[k]]);
20987 }
20988 return target;
20989 }
20990 return source;
20991 }
20992 function isValidKey(key) {
20993 return [
20994 '__proto__',
20995 'prototype',
20996 'constructor'
20997 ].indexOf(key) === -1;
20998 }
20999 /**
21000 * The default merger when Chart.helpers.merge is called without merger option.
21001 * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
21002 * @private
21003 */ function _merger(key, target, source, options) {
21004 if (!isValidKey(key)) {
21005 return;
21006 }
21007 const tval = target[key];
21008 const sval = source[key];
21009 if (isObject(tval) && isObject(sval)) {
21010 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21011 merge(tval, sval, options);
21012 } else {
21013 target[key] = clone(sval);
21014 }
21015 }
21016 function merge(target, source, options) {
21017 const sources = isArray(source) ? source : [
21018 source
21019 ];
21020 const ilen = sources.length;
21021 if (!isObject(target)) {
21022 return target;
21023 }
21024 options = options || {};
21025 const merger = options.merger || _merger;
21026 let current;
21027 for(let i = 0; i < ilen; ++i){
21028 current = sources[i];
21029 if (!isObject(current)) {
21030 continue;
21031 }
21032 const keys = Object.keys(current);
21033 for(let k = 0, klen = keys.length; k < klen; ++k){
21034 merger(keys[k], target, current, options);
21035 }
21036 }
21037 return target;
21038 }
21039 function mergeIf(target, source) {
21040 // eslint-disable-next-line @typescript-eslint/no-use-before-define
21041 return merge(target, source, {
21042 merger: _mergerIf
21043 });
21044 }
21045 /**
21046 * Merges source[key] in target[key] only if target[key] is undefined.
21047 * @private
21048 */ function _mergerIf(key, target, source) {
21049 if (!isValidKey(key)) {
21050 return;
21051 }
21052 const tval = target[key];
21053 const sval = source[key];
21054 if (isObject(tval) && isObject(sval)) {
21055 mergeIf(tval, sval);
21056 } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
21057 target[key] = clone(sval);
21058 }
21059 }
21060 /**
21061 * @private
21062 */ function _deprecated(scope, value, previous, current) {
21063 if (value !== undefined) {
21064 console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead');
21065 }
21066 }
21067 // resolveObjectKey resolver cache
21068 const keyResolvers = {
21069 // Chart.helpers.core resolveObjectKey should resolve empty key to root object
21070 '': (v)=>v,
21071 // default resolvers
21072 x: (o)=>o.x,
21073 y: (o)=>o.y
21074 };
21075 /**
21076 * @private
21077 */ function _splitKey(key) {
21078 const parts = key.split('.');
21079 const keys = [];
21080 let tmp = '';
21081 for (const part of parts){
21082 tmp += part;
21083 if (tmp.endsWith('\\')) {
21084 tmp = tmp.slice(0, -1) + '.';
21085 } else {
21086 keys.push(tmp);
21087 tmp = '';
21088 }
21089 }
21090 return keys;
21091 }
21092 function _getKeyResolver(key) {
21093 const keys = _splitKey(key);
21094 return (obj)=>{
21095 for (const k of keys){
21096 if (k === '') {
21097 break;
21098 }
21099 obj = obj && obj[k];
21100 }
21101 return obj;
21102 };
21103 }
21104 function resolveObjectKey(obj, key) {
21105 const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
21106 return resolver(obj);
21107 }
21108 /**
21109 * @private
21110 */ function _capitalize(str) {
21111 return str.charAt(0).toUpperCase() + str.slice(1);
21112 }
21113 const defined = (value)=>typeof value !== 'undefined';
21114 const isFunction = (value)=>typeof value === 'function';
21115 // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
21116 const setsEqual = (a, b)=>{
21117 if (a.size !== b.size) {
21118 return false;
21119 }
21120 for (const item of a){
21121 if (!b.has(item)) {
21122 return false;
21123 }
21124 }
21125 return true;
21126 };
21127 /**
21128 * @param e - The event
21129 * @private
21130 */ function _isClickEvent(e) {
21131 return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
21132 }
21133
21134 /**
21135 * @alias Chart.helpers.math
21136 * @namespace
21137 */ const PI = Math.PI;
21138 const TAU = 2 * PI;
21139 const PITAU = TAU + PI;
21140 const INFINITY = Number.POSITIVE_INFINITY;
21141 const RAD_PER_DEG = PI / 180;
21142 const HALF_PI = PI / 2;
21143 const QUARTER_PI = PI / 4;
21144 const TWO_THIRDS_PI = PI * 2 / 3;
21145 const log10 = Math.log10;
21146 const sign = Math.sign;
21147 function almostEquals(x, y, epsilon) {
21148 return Math.abs(x - y) < epsilon;
21149 }
21150 /**
21151 * Implementation of the nice number algorithm used in determining where axis labels will go
21152 */ function niceNum(range) {
21153 const roundedRange = Math.round(range);
21154 range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
21155 const niceRange = Math.pow(10, Math.floor(log10(range)));
21156 const fraction = range / niceRange;
21157 const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
21158 return niceFraction * niceRange;
21159 }
21160 /**
21161 * Returns an array of factors sorted from 1 to sqrt(value)
21162 * @private
21163 */ function _factorize(value) {
21164 const result = [];
21165 const sqrt = Math.sqrt(value);
21166 let i;
21167 for(i = 1; i < sqrt; i++){
21168 if (value % i === 0) {
21169 result.push(i);
21170 result.push(value / i);
21171 }
21172 }
21173 if (sqrt === (sqrt | 0)) {
21174 result.push(sqrt);
21175 }
21176 result.sort((a, b)=>a - b).pop();
21177 return result;
21178 }
21179 /**
21180 * Verifies that attempting to coerce n to string or number won't throw a TypeError.
21181 */ function isNonPrimitive(n) {
21182 return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n);
21183 }
21184 function isNumber(n) {
21185 return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n);
21186 }
21187 function almostWhole(x, epsilon) {
21188 const rounded = Math.round(x);
21189 return rounded - epsilon <= x && rounded + epsilon >= x;
21190 }
21191 /**
21192 * @private
21193 */ function _setMinAndMaxByKey(array, target, property) {
21194 let i, ilen, value;
21195 for(i = 0, ilen = array.length; i < ilen; i++){
21196 value = array[i][property];
21197 if (!isNaN(value)) {
21198 target.min = Math.min(target.min, value);
21199 target.max = Math.max(target.max, value);
21200 }
21201 }
21202 }
21203 function toRadians(degrees) {
21204 return degrees * (PI / 180);
21205 }
21206 function toDegrees(radians) {
21207 return radians * (180 / PI);
21208 }
21209 /**
21210 * Returns the number of decimal places
21211 * i.e. the number of digits after the decimal point, of the value of this Number.
21212 * @param x - A number.
21213 * @returns The number of decimal places.
21214 * @private
21215 */ function _decimalPlaces(x) {
21216 if (!isNumberFinite(x)) {
21217 return;
21218 }
21219 let e = 1;
21220 let p = 0;
21221 while(Math.round(x * e) / e !== x){
21222 e *= 10;
21223 p++;
21224 }
21225 return p;
21226 }
21227 // Gets the angle from vertical upright to the point about a centre.
21228 function getAngleFromPoint(centrePoint, anglePoint) {
21229 const distanceFromXCenter = anglePoint.x - centrePoint.x;
21230 const distanceFromYCenter = anglePoint.y - centrePoint.y;
21231 const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
21232 let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
21233 if (angle < -0.5 * PI) {
21234 angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
21235 }
21236 return {
21237 angle,
21238 distance: radialDistanceFromCenter
21239 };
21240 }
21241 function distanceBetweenPoints(pt1, pt2) {
21242 return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
21243 }
21244 /**
21245 * Shortest distance between angles, in either direction.
21246 * @private
21247 */ function _angleDiff(a, b) {
21248 return (a - b + PITAU) % TAU - PI;
21249 }
21250 /**
21251 * Normalize angle to be between 0 and 2*PI
21252 * @private
21253 */ function _normalizeAngle(a) {
21254 return (a % TAU + TAU) % TAU;
21255 }
21256 /**
21257 * @private
21258 */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
21259 const a = _normalizeAngle(angle);
21260 const s = _normalizeAngle(start);
21261 const e = _normalizeAngle(end);
21262 const angleToStart = _normalizeAngle(s - a);
21263 const angleToEnd = _normalizeAngle(e - a);
21264 const startToAngle = _normalizeAngle(a - s);
21265 const endToAngle = _normalizeAngle(a - e);
21266 return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;
21267 }
21268 /**
21269 * Limit `value` between `min` and `max`
21270 * @param value
21271 * @param min
21272 * @param max
21273 * @private
21274 */ function _limitValue(value, min, max) {
21275 return Math.max(min, Math.min(max, value));
21276 }
21277 /**
21278 * @param {number} value
21279 * @private
21280 */ function _int16Range(value) {
21281 return _limitValue(value, -32768, 32767);
21282 }
21283 /**
21284 * @param value
21285 * @param start
21286 * @param end
21287 * @param [epsilon]
21288 * @private
21289 */ function _isBetween(value, start, end, epsilon = 1e-6) {
21290 return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
21291 }
21292
21293 function _lookup(table, value, cmp) {
21294 cmp = cmp || ((index)=>table[index] < value);
21295 let hi = table.length - 1;
21296 let lo = 0;
21297 let mid;
21298 while(hi - lo > 1){
21299 mid = lo + hi >> 1;
21300 if (cmp(mid)) {
21301 lo = mid;
21302 } else {
21303 hi = mid;
21304 }
21305 }
21306 return {
21307 lo,
21308 hi
21309 };
21310 }
21311 /**
21312 * Binary search
21313 * @param table - the table search. must be sorted!
21314 * @param key - property name for the value in each entry
21315 * @param value - value to find
21316 * @param last - lookup last index
21317 * @private
21318 */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{
21319 const ti = table[index][key];
21320 return ti < value || ti === value && table[index + 1][key] === value;
21321 } : (index)=>table[index][key] < value);
21322 /**
21323 * Reverse binary search
21324 * @param table - the table search. must be sorted!
21325 * @param key - property name for the value in each entry
21326 * @param value - value to find
21327 * @private
21328 */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);
21329 /**
21330 * Return subset of `values` between `min` and `max` inclusive.
21331 * Values are assumed to be in sorted order.
21332 * @param values - sorted array of values
21333 * @param min - min value
21334 * @param max - max value
21335 */ function _filterBetween(values, min, max) {
21336 let start = 0;
21337 let end = values.length;
21338 while(start < end && values[start] < min){
21339 start++;
21340 }
21341 while(end > start && values[end - 1] > max){
21342 end--;
21343 }
21344 return start > 0 || end < values.length ? values.slice(start, end) : values;
21345 }
21346 const arrayEvents = [
21347 'push',
21348 'pop',
21349 'shift',
21350 'splice',
21351 'unshift'
21352 ];
21353 function listenArrayEvents(array, listener) {
21354 if (array._chartjs) {
21355 array._chartjs.listeners.push(listener);
21356 return;
21357 }
21358 Object.defineProperty(array, '_chartjs', {
21359 configurable: true,
21360 enumerable: false,
21361 value: {
21362 listeners: [
21363 listener
21364 ]
21365 }
21366 });
21367 arrayEvents.forEach((key)=>{
21368 const method = '_onData' + _capitalize(key);
21369 const base = array[key];
21370 Object.defineProperty(array, key, {
21371 configurable: true,
21372 enumerable: false,
21373 value (...args) {
21374 const res = base.apply(this, args);
21375 array._chartjs.listeners.forEach((object)=>{
21376 if (typeof object[method] === 'function') {
21377 object[method](...args);
21378 }
21379 });
21380 return res;
21381 }
21382 });
21383 });
21384 }
21385 function unlistenArrayEvents(array, listener) {
21386 const stub = array._chartjs;
21387 if (!stub) {
21388 return;
21389 }
21390 const listeners = stub.listeners;
21391 const index = listeners.indexOf(listener);
21392 if (index !== -1) {
21393 listeners.splice(index, 1);
21394 }
21395 if (listeners.length > 0) {
21396 return;
21397 }
21398 arrayEvents.forEach((key)=>{
21399 delete array[key];
21400 });
21401 delete array._chartjs;
21402 }
21403 /**
21404 * @param items
21405 */ function _arrayUnique(items) {
21406 const set = new Set(items);
21407 if (set.size === items.length) {
21408 return items;
21409 }
21410 return Array.from(set);
21411 }
21412
21413 function fontString(pixelSize, fontStyle, fontFamily) {
21414 return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
21415 }
21416 /**
21417 * Request animation polyfill
21418 */ const requestAnimFrame = function() {
21419 if (typeof window === 'undefined') {
21420 return function(callback) {
21421 return callback();
21422 };
21423 }
21424 return window.requestAnimationFrame;
21425 }();
21426 /**
21427 * Throttles calling `fn` once per animation frame
21428 * Latest arguments are used on the actual call
21429 */ function throttled(fn, thisArg) {
21430 let argsToUse = [];
21431 let ticking = false;
21432 return function(...args) {
21433 // Save the args for use later
21434 argsToUse = args;
21435 if (!ticking) {
21436 ticking = true;
21437 requestAnimFrame.call(window, ()=>{
21438 ticking = false;
21439 fn.apply(thisArg, argsToUse);
21440 });
21441 }
21442 };
21443 }
21444 /**
21445 * Debounces calling `fn` for `delay` ms
21446 */ function debounce(fn, delay) {
21447 let timeout;
21448 return function(...args) {
21449 if (delay) {
21450 clearTimeout(timeout);
21451 timeout = setTimeout(fn, delay, args);
21452 } else {
21453 fn.apply(this, args);
21454 }
21455 return delay;
21456 };
21457 }
21458 /**
21459 * Converts 'start' to 'left', 'end' to 'right' and others to 'center'
21460 * @private
21461 */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
21462 /**
21463 * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`
21464 * @private
21465 */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
21466 /**
21467 * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`
21468 * @private
21469 */ const _textX = (align, left, right, rtl)=>{
21470 const check = rtl ? 'left' : 'right';
21471 return align === check ? right : align === 'center' ? (left + right) / 2 : left;
21472 };
21473 /**
21474 * Return start and count of visible points.
21475 * @private
21476 */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
21477 const pointCount = points.length;
21478 let start = 0;
21479 let count = pointCount;
21480 if (meta._sorted) {
21481 const { iScale , vScale , _parsed } = meta;
21482 const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null;
21483 const axis = iScale.axis;
21484 const { min , max , minDefined , maxDefined } = iScale.getUserBounds();
21485 if (minDefined) {
21486 start = Math.min(// @ts-expect-error Need to type _parsed
21487 _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey
21488 animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo);
21489 if (spanGaps) {
21490 const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21491 start -= Math.max(0, distanceToDefinedLo);
21492 }
21493 start = _limitValue(start, 0, pointCount - 1);
21494 }
21495 if (maxDefined) {
21496 let end = Math.max(// @ts-expect-error Need to type _parsed
21497 _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey
21498 animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1);
21499 if (spanGaps) {
21500 const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis]));
21501 end += Math.max(0, distanceToDefinedHi);
21502 }
21503 count = _limitValue(end, start, pointCount) - start;
21504 } else {
21505 count = pointCount - start;
21506 }
21507 }
21508 return {
21509 start,
21510 count
21511 };
21512 }
21513 /**
21514 * Checks if the scale ranges have changed.
21515 * @param {object} meta - dataset meta.
21516 * @returns {boolean}
21517 * @private
21518 */ function _scaleRangesChanged(meta) {
21519 const { xScale , yScale , _scaleRanges } = meta;
21520 const newRanges = {
21521 xmin: xScale.min,
21522 xmax: xScale.max,
21523 ymin: yScale.min,
21524 ymax: yScale.max
21525 };
21526 if (!_scaleRanges) {
21527 meta._scaleRanges = newRanges;
21528 return true;
21529 }
21530 const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max;
21531 Object.assign(_scaleRanges, newRanges);
21532 return changed;
21533 }
21534
21535 const atEdge = (t)=>t === 0 || t === 1;
21536 const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
21537 const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
21538 /**
21539 * Easing functions adapted from Robert Penner's easing equations.
21540 * @namespace Chart.helpers.easing.effects
21541 * @see http://www.robertpenner.com/easing/
21542 */ const effects = {
21543 linear: (t)=>t,
21544 easeInQuad: (t)=>t * t,
21545 easeOutQuad: (t)=>-t * (t - 2),
21546 easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),
21547 easeInCubic: (t)=>t * t * t,
21548 easeOutCubic: (t)=>(t -= 1) * t * t + 1,
21549 easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),
21550 easeInQuart: (t)=>t * t * t * t,
21551 easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),
21552 easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),
21553 easeInQuint: (t)=>t * t * t * t * t,
21554 easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,
21555 easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),
21556 easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,
21557 easeOutSine: (t)=>Math.sin(t * HALF_PI),
21558 easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),
21559 easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
21560 easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,
21561 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),
21562 easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),
21563 easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),
21564 easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
21565 easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
21566 easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
21567 easeInOutElastic (t) {
21568 const s = 0.1125;
21569 const p = 0.45;
21570 return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
21571 },
21572 easeInBack (t) {
21573 const s = 1.70158;
21574 return t * t * ((s + 1) * t - s);
21575 },
21576 easeOutBack (t) {
21577 const s = 1.70158;
21578 return (t -= 1) * t * ((s + 1) * t + s) + 1;
21579 },
21580 easeInOutBack (t) {
21581 let s = 1.70158;
21582 if ((t /= 0.5) < 1) {
21583 return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
21584 }
21585 return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
21586 },
21587 easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),
21588 easeOutBounce (t) {
21589 const m = 7.5625;
21590 const d = 2.75;
21591 if (t < 1 / d) {
21592 return m * t * t;
21593 }
21594 if (t < 2 / d) {
21595 return m * (t -= 1.5 / d) * t + 0.75;
21596 }
21597 if (t < 2.5 / d) {
21598 return m * (t -= 2.25 / d) * t + 0.9375;
21599 }
21600 return m * (t -= 2.625 / d) * t + 0.984375;
21601 },
21602 easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5
21603 };
21604
21605 function isPatternOrGradient(value) {
21606 if (value && typeof value === 'object') {
21607 const type = value.toString();
21608 return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
21609 }
21610 return false;
21611 }
21612 function color(value) {
21613 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value);
21614 }
21615 function getHoverColor(value) {
21616 return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value).saturate(0.5).darken(0.1).hexString();
21617 }
21618
21619 const numbers = [
21620 'x',
21621 'y',
21622 'borderWidth',
21623 'radius',
21624 'tension'
21625 ];
21626 const colors = [
21627 'color',
21628 'borderColor',
21629 'backgroundColor'
21630 ];
21631 function applyAnimationsDefaults(defaults) {
21632 defaults.set('animation', {
21633 delay: undefined,
21634 duration: 1000,
21635 easing: 'easeOutQuart',
21636 fn: undefined,
21637 from: undefined,
21638 loop: undefined,
21639 to: undefined,
21640 type: undefined
21641 });
21642 defaults.describe('animation', {
21643 _fallback: false,
21644 _indexable: false,
21645 _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'
21646 });
21647 defaults.set('animations', {
21648 colors: {
21649 type: 'color',
21650 properties: colors
21651 },
21652 numbers: {
21653 type: 'number',
21654 properties: numbers
21655 }
21656 });
21657 defaults.describe('animations', {
21658 _fallback: 'animation'
21659 });
21660 defaults.set('transitions', {
21661 active: {
21662 animation: {
21663 duration: 400
21664 }
21665 },
21666 resize: {
21667 animation: {
21668 duration: 0
21669 }
21670 },
21671 show: {
21672 animations: {
21673 colors: {
21674 from: 'transparent'
21675 },
21676 visible: {
21677 type: 'boolean',
21678 duration: 0
21679 }
21680 }
21681 },
21682 hide: {
21683 animations: {
21684 colors: {
21685 to: 'transparent'
21686 },
21687 visible: {
21688 type: 'boolean',
21689 easing: 'linear',
21690 fn: (v)=>v | 0
21691 }
21692 }
21693 }
21694 });
21695 }
21696
21697 function applyLayoutsDefaults(defaults) {
21698 defaults.set('layout', {
21699 autoPadding: true,
21700 padding: {
21701 top: 0,
21702 right: 0,
21703 bottom: 0,
21704 left: 0
21705 }
21706 });
21707 }
21708
21709 const intlCache = new Map();
21710 function getNumberFormat(locale, options) {
21711 options = options || {};
21712 const cacheKey = locale + JSON.stringify(options);
21713 let formatter = intlCache.get(cacheKey);
21714 if (!formatter) {
21715 formatter = new Intl.NumberFormat(locale, options);
21716 intlCache.set(cacheKey, formatter);
21717 }
21718 return formatter;
21719 }
21720 function formatNumber(num, locale, options) {
21721 return getNumberFormat(locale, options).format(num);
21722 }
21723
21724 const formatters = {
21725 values (value) {
21726 return isArray(value) ? value : '' + value;
21727 },
21728 numeric (tickValue, index, ticks) {
21729 if (tickValue === 0) {
21730 return '0';
21731 }
21732 const locale = this.chart.options.locale;
21733 let notation;
21734 let delta = tickValue;
21735 if (ticks.length > 1) {
21736 const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
21737 if (maxTick < 1e-4 || maxTick > 1e+15) {
21738 notation = 'scientific';
21739 }
21740 delta = calculateDelta(tickValue, ticks);
21741 }
21742 const logDelta = log10(Math.abs(delta));
21743 const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
21744 const options = {
21745 notation,
21746 minimumFractionDigits: numDecimal,
21747 maximumFractionDigits: numDecimal
21748 };
21749 Object.assign(options, this.options.ticks.format);
21750 return formatNumber(tickValue, locale, options);
21751 },
21752 logarithmic (tickValue, index, ticks) {
21753 if (tickValue === 0) {
21754 return '0';
21755 }
21756 const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
21757 if ([
21758 1,
21759 2,
21760 3,
21761 5,
21762 10,
21763 15
21764 ].includes(remain) || index > 0.8 * ticks.length) {
21765 return formatters.numeric.call(this, tickValue, index, ticks);
21766 }
21767 return '';
21768 }
21769 };
21770 function calculateDelta(tickValue, ticks) {
21771 let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
21772 if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
21773 delta = tickValue - Math.floor(tickValue);
21774 }
21775 return delta;
21776 }
21777 var Ticks = {
21778 formatters
21779 };
21780
21781 function applyScaleDefaults(defaults) {
21782 defaults.set('scale', {
21783 display: true,
21784 offset: false,
21785 reverse: false,
21786 beginAtZero: false,
21787 bounds: 'ticks',
21788 clip: true,
21789 grace: 0,
21790 grid: {
21791 display: true,
21792 lineWidth: 1,
21793 drawOnChartArea: true,
21794 drawTicks: true,
21795 tickLength: 8,
21796 tickWidth: (_ctx, options)=>options.lineWidth,
21797 tickColor: (_ctx, options)=>options.color,
21798 offset: false
21799 },
21800 border: {
21801 display: true,
21802 dash: [],
21803 dashOffset: 0.0,
21804 width: 1
21805 },
21806 title: {
21807 display: false,
21808 text: '',
21809 padding: {
21810 top: 4,
21811 bottom: 4
21812 }
21813 },
21814 ticks: {
21815 minRotation: 0,
21816 maxRotation: 50,
21817 mirror: false,
21818 textStrokeWidth: 0,
21819 textStrokeColor: '',
21820 padding: 3,
21821 display: true,
21822 autoSkip: true,
21823 autoSkipPadding: 3,
21824 labelOffset: 0,
21825 callback: Ticks.formatters.values,
21826 minor: {},
21827 major: {},
21828 align: 'center',
21829 crossAlign: 'near',
21830 showLabelBackdrop: false,
21831 backdropColor: 'rgba(255, 255, 255, 0.75)',
21832 backdropPadding: 2
21833 }
21834 });
21835 defaults.route('scale.ticks', 'color', '', 'color');
21836 defaults.route('scale.grid', 'color', '', 'borderColor');
21837 defaults.route('scale.border', 'color', '', 'borderColor');
21838 defaults.route('scale.title', 'color', '', 'color');
21839 defaults.describe('scale', {
21840 _fallback: false,
21841 _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
21842 _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'
21843 });
21844 defaults.describe('scales', {
21845 _fallback: 'scale'
21846 });
21847 defaults.describe('scale.ticks', {
21848 _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',
21849 _indexable: (name)=>name !== 'backdropPadding'
21850 });
21851 }
21852
21853 const overrides = Object.create(null);
21854 const descriptors = Object.create(null);
21855 function getScope$1(node, key) {
21856 if (!key) {
21857 return node;
21858 }
21859 const keys = key.split('.');
21860 for(let i = 0, n = keys.length; i < n; ++i){
21861 const k = keys[i];
21862 node = node[k] || (node[k] = Object.create(null));
21863 }
21864 return node;
21865 }
21866 function set(root, scope, values) {
21867 if (typeof scope === 'string') {
21868 return merge(getScope$1(root, scope), values);
21869 }
21870 return merge(getScope$1(root, ''), scope);
21871 }
21872 class Defaults {
21873 constructor(_descriptors, _appliers){
21874 this.animation = undefined;
21875 this.backgroundColor = 'rgba(0,0,0,0.1)';
21876 this.borderColor = 'rgba(0,0,0,0.1)';
21877 this.color = '#666';
21878 this.datasets = {};
21879 this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio();
21880 this.elements = {};
21881 this.events = [
21882 'mousemove',
21883 'mouseout',
21884 'click',
21885 'touchstart',
21886 'touchmove'
21887 ];
21888 this.font = {
21889 family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
21890 size: 12,
21891 style: 'normal',
21892 lineHeight: 1.2,
21893 weight: null
21894 };
21895 this.hover = {};
21896 this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor);
21897 this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor);
21898 this.hoverColor = (ctx, options)=>getHoverColor(options.color);
21899 this.indexAxis = 'x';
21900 this.interaction = {
21901 mode: 'nearest',
21902 intersect: true,
21903 includeInvisible: false
21904 };
21905 this.maintainAspectRatio = true;
21906 this.onHover = null;
21907 this.onClick = null;
21908 this.parsing = true;
21909 this.plugins = {};
21910 this.responsive = true;
21911 this.scale = undefined;
21912 this.scales = {};
21913 this.showLine = true;
21914 this.drawActiveElementsOnTop = true;
21915 this.describe(_descriptors);
21916 this.apply(_appliers);
21917 }
21918 set(scope, values) {
21919 return set(this, scope, values);
21920 }
21921 get(scope) {
21922 return getScope$1(this, scope);
21923 }
21924 describe(scope, values) {
21925 return set(descriptors, scope, values);
21926 }
21927 override(scope, values) {
21928 return set(overrides, scope, values);
21929 }
21930 route(scope, name, targetScope, targetName) {
21931 const scopeObject = getScope$1(this, scope);
21932 const targetScopeObject = getScope$1(this, targetScope);
21933 const privateName = '_' + name;
21934 Object.defineProperties(scopeObject, {
21935 [privateName]: {
21936 value: scopeObject[name],
21937 writable: true
21938 },
21939 [name]: {
21940 enumerable: true,
21941 get () {
21942 const local = this[privateName];
21943 const target = targetScopeObject[targetName];
21944 if (isObject(local)) {
21945 return Object.assign({}, target, local);
21946 }
21947 return valueOrDefault(local, target);
21948 },
21949 set (value) {
21950 this[privateName] = value;
21951 }
21952 }
21953 });
21954 }
21955 apply(appliers) {
21956 appliers.forEach((apply)=>apply(this));
21957 }
21958 }
21959 var defaults = /* #__PURE__ */ new Defaults({
21960 _scriptable: (name)=>!name.startsWith('on'),
21961 _indexable: (name)=>name !== 'events',
21962 hover: {
21963 _fallback: 'interaction'
21964 },
21965 interaction: {
21966 _scriptable: false,
21967 _indexable: false
21968 }
21969 }, [
21970 applyAnimationsDefaults,
21971 applyLayoutsDefaults,
21972 applyScaleDefaults
21973 ]);
21974
21975 /**
21976 * Converts the given font object into a CSS font string.
21977 * @param font - A font object.
21978 * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
21979 * @private
21980 */ function toFontString(font) {
21981 if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
21982 return null;
21983 }
21984 return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family;
21985 }
21986 /**
21987 * @private
21988 */ function _measureText(ctx, data, gc, longest, string) {
21989 let textWidth = data[string];
21990 if (!textWidth) {
21991 textWidth = data[string] = ctx.measureText(string).width;
21992 gc.push(string);
21993 }
21994 if (textWidth > longest) {
21995 longest = textWidth;
21996 }
21997 return longest;
21998 }
21999 /**
22000 * @private
22001 */ // eslint-disable-next-line complexity
22002 function _longestText(ctx, font, arrayOfThings, cache) {
22003 cache = cache || {};
22004 let data = cache.data = cache.data || {};
22005 let gc = cache.garbageCollect = cache.garbageCollect || [];
22006 if (cache.font !== font) {
22007 data = cache.data = {};
22008 gc = cache.garbageCollect = [];
22009 cache.font = font;
22010 }
22011 ctx.save();
22012 ctx.font = font;
22013 let longest = 0;
22014 const ilen = arrayOfThings.length;
22015 let i, j, jlen, thing, nestedThing;
22016 for(i = 0; i < ilen; i++){
22017 thing = arrayOfThings[i];
22018 // Undefined strings and arrays should not be measured
22019 if (thing !== undefined && thing !== null && !isArray(thing)) {
22020 longest = _measureText(ctx, data, gc, longest, thing);
22021 } else if (isArray(thing)) {
22022 // if it is an array lets measure each element
22023 // to do maybe simplify this function a bit so we can do this more recursively?
22024 for(j = 0, jlen = thing.length; j < jlen; j++){
22025 nestedThing = thing[j];
22026 // Undefined strings and arrays should not be measured
22027 if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
22028 longest = _measureText(ctx, data, gc, longest, nestedThing);
22029 }
22030 }
22031 }
22032 }
22033 ctx.restore();
22034 const gcLen = gc.length / 2;
22035 if (gcLen > arrayOfThings.length) {
22036 for(i = 0; i < gcLen; i++){
22037 delete data[gc[i]];
22038 }
22039 gc.splice(0, gcLen);
22040 }
22041 return longest;
22042 }
22043 /**
22044 * Returns the aligned pixel value to avoid anti-aliasing blur
22045 * @param chart - The chart instance.
22046 * @param pixel - A pixel value.
22047 * @param width - The width of the element.
22048 * @returns The aligned pixel value.
22049 * @private
22050 */ function _alignPixel(chart, pixel, width) {
22051 const devicePixelRatio = chart.currentDevicePixelRatio;
22052 const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
22053 return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
22054 }
22055 /**
22056 * Clears the entire canvas.
22057 */ function clearCanvas(canvas, ctx) {
22058 if (!ctx && !canvas) {
22059 return;
22060 }
22061 ctx = ctx || canvas.getContext('2d');
22062 ctx.save();
22063 // canvas.width and canvas.height do not consider the canvas transform,
22064 // while clearRect does
22065 ctx.resetTransform();
22066 ctx.clearRect(0, 0, canvas.width, canvas.height);
22067 ctx.restore();
22068 }
22069 function drawPoint(ctx, options, x, y) {
22070 // eslint-disable-next-line @typescript-eslint/no-use-before-define
22071 drawPointLegend(ctx, options, x, y, null);
22072 }
22073 // eslint-disable-next-line complexity
22074 function drawPointLegend(ctx, options, x, y, w) {
22075 let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;
22076 const style = options.pointStyle;
22077 const rotation = options.rotation;
22078 const radius = options.radius;
22079 let rad = (rotation || 0) * RAD_PER_DEG;
22080 if (style && typeof style === 'object') {
22081 type = style.toString();
22082 if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
22083 ctx.save();
22084 ctx.translate(x, y);
22085 ctx.rotate(rad);
22086 ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
22087 ctx.restore();
22088 return;
22089 }
22090 }
22091 if (isNaN(radius) || radius <= 0) {
22092 return;
22093 }
22094 ctx.beginPath();
22095 switch(style){
22096 // Default includes circle
22097 default:
22098 if (w) {
22099 ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);
22100 } else {
22101 ctx.arc(x, y, radius, 0, TAU);
22102 }
22103 ctx.closePath();
22104 break;
22105 case 'triangle':
22106 width = w ? w / 2 : radius;
22107 ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22108 rad += TWO_THIRDS_PI;
22109 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22110 rad += TWO_THIRDS_PI;
22111 ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
22112 ctx.closePath();
22113 break;
22114 case 'rectRounded':
22115 // NOTE: the rounded rect implementation changed to use `arc` instead of
22116 // `quadraticCurveTo` since it generates better results when rect is
22117 // almost a circle. 0.516 (instead of 0.5) produces results with visually
22118 // closer proportion to the previous impl and it is inscribed in the
22119 // circle with `radius`. For more details, see the following PRs:
22120 // https://github.com/chartjs/Chart.js/issues/5597
22121 // https://github.com/chartjs/Chart.js/issues/5858
22122 cornerRadius = radius * 0.516;
22123 size = radius - cornerRadius;
22124 xOffset = Math.cos(rad + QUARTER_PI) * size;
22125 xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22126 yOffset = Math.sin(rad + QUARTER_PI) * size;
22127 yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
22128 ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
22129 ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);
22130 ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);
22131 ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
22132 ctx.closePath();
22133 break;
22134 case 'rect':
22135 if (!rotation) {
22136 size = Math.SQRT1_2 * radius;
22137 width = w ? w / 2 : size;
22138 ctx.rect(x - width, y - size, 2 * width, 2 * size);
22139 break;
22140 }
22141 rad += QUARTER_PI;
22142 /* falls through */ case 'rectRot':
22143 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22144 xOffset = Math.cos(rad) * radius;
22145 yOffset = Math.sin(rad) * radius;
22146 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22147 ctx.moveTo(x - xOffsetW, y - yOffset);
22148 ctx.lineTo(x + yOffsetW, y - xOffset);
22149 ctx.lineTo(x + xOffsetW, y + yOffset);
22150 ctx.lineTo(x - yOffsetW, y + xOffset);
22151 ctx.closePath();
22152 break;
22153 case 'crossRot':
22154 rad += QUARTER_PI;
22155 /* falls through */ case 'cross':
22156 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22157 xOffset = Math.cos(rad) * radius;
22158 yOffset = Math.sin(rad) * radius;
22159 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22160 ctx.moveTo(x - xOffsetW, y - yOffset);
22161 ctx.lineTo(x + xOffsetW, y + yOffset);
22162 ctx.moveTo(x + yOffsetW, y - xOffset);
22163 ctx.lineTo(x - yOffsetW, y + xOffset);
22164 break;
22165 case 'star':
22166 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22167 xOffset = Math.cos(rad) * radius;
22168 yOffset = Math.sin(rad) * radius;
22169 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22170 ctx.moveTo(x - xOffsetW, y - yOffset);
22171 ctx.lineTo(x + xOffsetW, y + yOffset);
22172 ctx.moveTo(x + yOffsetW, y - xOffset);
22173 ctx.lineTo(x - yOffsetW, y + xOffset);
22174 rad += QUARTER_PI;
22175 xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
22176 xOffset = Math.cos(rad) * radius;
22177 yOffset = Math.sin(rad) * radius;
22178 yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
22179 ctx.moveTo(x - xOffsetW, y - yOffset);
22180 ctx.lineTo(x + xOffsetW, y + yOffset);
22181 ctx.moveTo(x + yOffsetW, y - xOffset);
22182 ctx.lineTo(x - yOffsetW, y + xOffset);
22183 break;
22184 case 'line':
22185 xOffset = w ? w / 2 : Math.cos(rad) * radius;
22186 yOffset = Math.sin(rad) * radius;
22187 ctx.moveTo(x - xOffset, y - yOffset);
22188 ctx.lineTo(x + xOffset, y + yOffset);
22189 break;
22190 case 'dash':
22191 ctx.moveTo(x, y);
22192 ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);
22193 break;
22194 case false:
22195 ctx.closePath();
22196 break;
22197 }
22198 ctx.fill();
22199 if (options.borderWidth > 0) {
22200 ctx.stroke();
22201 }
22202 }
22203 /**
22204 * Returns true if the point is inside the rectangle
22205 * @param point - The point to test
22206 * @param area - The rectangle
22207 * @param margin - allowed margin
22208 * @private
22209 */ function _isPointInArea(point, area, margin) {
22210 margin = margin || 0.5; // margin - default is to match rounded decimals
22211 return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;
22212 }
22213 function clipArea(ctx, area) {
22214 ctx.save();
22215 ctx.beginPath();
22216 ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
22217 ctx.clip();
22218 }
22219 function unclipArea(ctx) {
22220 ctx.restore();
22221 }
22222 /**
22223 * @private
22224 */ function _steppedLineTo(ctx, previous, target, flip, mode) {
22225 if (!previous) {
22226 return ctx.lineTo(target.x, target.y);
22227 }
22228 if (mode === 'middle') {
22229 const midpoint = (previous.x + target.x) / 2.0;
22230 ctx.lineTo(midpoint, previous.y);
22231 ctx.lineTo(midpoint, target.y);
22232 } else if (mode === 'after' !== !!flip) {
22233 ctx.lineTo(previous.x, target.y);
22234 } else {
22235 ctx.lineTo(target.x, previous.y);
22236 }
22237 ctx.lineTo(target.x, target.y);
22238 }
22239 /**
22240 * @private
22241 */ function _bezierCurveTo(ctx, previous, target, flip) {
22242 if (!previous) {
22243 return ctx.lineTo(target.x, target.y);
22244 }
22245 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);
22246 }
22247 function setRenderOpts(ctx, opts) {
22248 if (opts.translation) {
22249 ctx.translate(opts.translation[0], opts.translation[1]);
22250 }
22251 if (!isNullOrUndef(opts.rotation)) {
22252 ctx.rotate(opts.rotation);
22253 }
22254 if (opts.color) {
22255 ctx.fillStyle = opts.color;
22256 }
22257 if (opts.textAlign) {
22258 ctx.textAlign = opts.textAlign;
22259 }
22260 if (opts.textBaseline) {
22261 ctx.textBaseline = opts.textBaseline;
22262 }
22263 }
22264 function decorateText(ctx, x, y, line, opts) {
22265 if (opts.strikethrough || opts.underline) {
22266 /**
22267 * Now that IE11 support has been dropped, we can use more
22268 * of the TextMetrics object. The actual bounding boxes
22269 * are unflagged in Chrome, Firefox, Edge, and Safari so they
22270 * can be safely used.
22271 * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
22272 */ const metrics = ctx.measureText(line);
22273 const left = x - metrics.actualBoundingBoxLeft;
22274 const right = x + metrics.actualBoundingBoxRight;
22275 const top = y - metrics.actualBoundingBoxAscent;
22276 const bottom = y + metrics.actualBoundingBoxDescent;
22277 const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
22278 ctx.strokeStyle = ctx.fillStyle;
22279 ctx.beginPath();
22280 ctx.lineWidth = opts.decorationWidth || 2;
22281 ctx.moveTo(left, yDecoration);
22282 ctx.lineTo(right, yDecoration);
22283 ctx.stroke();
22284 }
22285 }
22286 function drawBackdrop(ctx, opts) {
22287 const oldColor = ctx.fillStyle;
22288 ctx.fillStyle = opts.color;
22289 ctx.fillRect(opts.left, opts.top, opts.width, opts.height);
22290 ctx.fillStyle = oldColor;
22291 }
22292 /**
22293 * Render text onto the canvas
22294 */ function renderText(ctx, text, x, y, font, opts = {}) {
22295 const lines = isArray(text) ? text : [
22296 text
22297 ];
22298 const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
22299 let i, line;
22300 ctx.save();
22301 ctx.font = font.string;
22302 setRenderOpts(ctx, opts);
22303 for(i = 0; i < lines.length; ++i){
22304 line = lines[i];
22305 if (opts.backdrop) {
22306 drawBackdrop(ctx, opts.backdrop);
22307 }
22308 if (stroke) {
22309 if (opts.strokeColor) {
22310 ctx.strokeStyle = opts.strokeColor;
22311 }
22312 if (!isNullOrUndef(opts.strokeWidth)) {
22313 ctx.lineWidth = opts.strokeWidth;
22314 }
22315 ctx.strokeText(line, x, y, opts.maxWidth);
22316 }
22317 ctx.fillText(line, x, y, opts.maxWidth);
22318 decorateText(ctx, x, y, line, opts);
22319 y += Number(font.lineHeight);
22320 }
22321 ctx.restore();
22322 }
22323 /**
22324 * Add a path of a rectangle with rounded corners to the current sub-path
22325 * @param ctx - Context
22326 * @param rect - Bounding rect
22327 */ function addRoundedRectPath(ctx, rect) {
22328 const { x , y , w , h , radius } = rect;
22329 // top left arc
22330 ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
22331 // line from top left to bottom left
22332 ctx.lineTo(x, y + h - radius.bottomLeft);
22333 // bottom left arc
22334 ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
22335 // line from bottom left to bottom right
22336 ctx.lineTo(x + w - radius.bottomRight, y + h);
22337 // bottom right arc
22338 ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
22339 // line from bottom right to top right
22340 ctx.lineTo(x + w, y + radius.topRight);
22341 // top right arc
22342 ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
22343 // line from top right to top left
22344 ctx.lineTo(x + radius.topLeft, y);
22345 }
22346
22347 const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
22348 const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
22349 /**
22350 * @alias Chart.helpers.options
22351 * @namespace
22352 */ /**
22353 * Converts the given line height `value` in pixels for a specific font `size`.
22354 * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
22355 * @param size - The font size (in pixels) used to resolve relative `value`.
22356 * @returns The effective line height in pixels (size * 1.2 if value is invalid).
22357 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
22358 * @since 2.7.0
22359 */ function toLineHeight(value, size) {
22360 const matches = ('' + value).match(LINE_HEIGHT);
22361 if (!matches || matches[1] === 'normal') {
22362 return size * 1.2;
22363 }
22364 value = +matches[2];
22365 switch(matches[3]){
22366 case 'px':
22367 return value;
22368 case '%':
22369 value /= 100;
22370 break;
22371 }
22372 return size * value;
22373 }
22374 const numberOrZero = (v)=>+v || 0;
22375 function _readValueToProps(value, props) {
22376 const ret = {};
22377 const objProps = isObject(props);
22378 const keys = objProps ? Object.keys(props) : props;
22379 const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value;
22380 for (const prop of keys){
22381 ret[prop] = numberOrZero(read(prop));
22382 }
22383 return ret;
22384 }
22385 /**
22386 * Converts the given value into a TRBL object.
22387 * @param value - If a number, set the value to all TRBL component,
22388 * else, if an object, use defined properties and sets undefined ones to 0.
22389 * x / y are shorthands for same value for left/right and top/bottom.
22390 * @returns The padding values (top, right, bottom, left)
22391 * @since 3.0.0
22392 */ function toTRBL(value) {
22393 return _readValueToProps(value, {
22394 top: 'y',
22395 right: 'x',
22396 bottom: 'y',
22397 left: 'x'
22398 });
22399 }
22400 /**
22401 * Converts the given value into a TRBL corners object (similar with css border-radius).
22402 * @param value - If a number, set the value to all TRBL corner components,
22403 * else, if an object, use defined properties and sets undefined ones to 0.
22404 * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)
22405 * @since 3.0.0
22406 */ function toTRBLCorners(value) {
22407 return _readValueToProps(value, [
22408 'topLeft',
22409 'topRight',
22410 'bottomLeft',
22411 'bottomRight'
22412 ]);
22413 }
22414 /**
22415 * Converts the given value into a padding object with pre-computed width/height.
22416 * @param value - If a number, set the value to all TRBL component,
22417 * else, if an object, use defined properties and sets undefined ones to 0.
22418 * x / y are shorthands for same value for left/right and top/bottom.
22419 * @returns The padding values (top, right, bottom, left, width, height)
22420 * @since 2.7.0
22421 */ function toPadding(value) {
22422 const obj = toTRBL(value);
22423 obj.width = obj.left + obj.right;
22424 obj.height = obj.top + obj.bottom;
22425 return obj;
22426 }
22427 /**
22428 * Parses font options and returns the font object.
22429 * @param options - A object that contains font options to be parsed.
22430 * @param fallback - A object that contains fallback font options.
22431 * @return The font object.
22432 * @private
22433 */ function toFont(options, fallback) {
22434 options = options || {};
22435 fallback = fallback || defaults.font;
22436 let size = valueOrDefault(options.size, fallback.size);
22437 if (typeof size === 'string') {
22438 size = parseInt(size, 10);
22439 }
22440 let style = valueOrDefault(options.style, fallback.style);
22441 if (style && !('' + style).match(FONT_STYLE)) {
22442 console.warn('Invalid font style specified: "' + style + '"');
22443 style = undefined;
22444 }
22445 const font = {
22446 family: valueOrDefault(options.family, fallback.family),
22447 lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
22448 size,
22449 style,
22450 weight: valueOrDefault(options.weight, fallback.weight),
22451 string: ''
22452 };
22453 font.string = toFontString(font);
22454 return font;
22455 }
22456 /**
22457 * Evaluates the given `inputs` sequentially and returns the first defined value.
22458 * @param inputs - An array of values, falling back to the last value.
22459 * @param context - If defined and the current value is a function, the value
22460 * is called with `context` as first argument and the result becomes the new input.
22461 * @param index - If defined and the current value is an array, the value
22462 * at `index` become the new input.
22463 * @param info - object to return information about resolution in
22464 * @param info.cacheable - Will be set to `false` if option is not cacheable.
22465 * @since 2.7.0
22466 */ function resolve(inputs, context, index, info) {
22467 let cacheable = true;
22468 let i, ilen, value;
22469 for(i = 0, ilen = inputs.length; i < ilen; ++i){
22470 value = inputs[i];
22471 if (value === undefined) {
22472 continue;
22473 }
22474 if (context !== undefined && typeof value === 'function') {
22475 value = value(context);
22476 cacheable = false;
22477 }
22478 if (index !== undefined && isArray(value)) {
22479 value = value[index % value.length];
22480 cacheable = false;
22481 }
22482 if (value !== undefined) {
22483 if (info && !cacheable) {
22484 info.cacheable = false;
22485 }
22486 return value;
22487 }
22488 }
22489 }
22490 /**
22491 * @param minmax
22492 * @param grace
22493 * @param beginAtZero
22494 * @private
22495 */ function _addGrace(minmax, grace, beginAtZero) {
22496 const { min , max } = minmax;
22497 const change = toDimension(grace, (max - min) / 2);
22498 const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;
22499 return {
22500 min: keepZero(min, -Math.abs(change)),
22501 max: keepZero(max, change)
22502 };
22503 }
22504 function createContext(parentContext, context) {
22505 return Object.assign(Object.create(parentContext), context);
22506 }
22507
22508 /**
22509 * Creates a Proxy for resolving raw values for options.
22510 * @param scopes - The option scopes to look for values, in resolution order
22511 * @param prefixes - The prefixes for values, in resolution order.
22512 * @param rootScopes - The root option scopes
22513 * @param fallback - Parent scopes fallback
22514 * @param getTarget - callback for getting the target for changed values
22515 * @returns Proxy
22516 * @private
22517 */ function _createResolver(scopes, prefixes = [
22518 ''
22519 ], rootScopes, fallback, getTarget = ()=>scopes[0]) {
22520 const finalRootScopes = rootScopes || scopes;
22521 if (typeof fallback === 'undefined') {
22522 fallback = _resolve('_fallback', scopes);
22523 }
22524 const cache = {
22525 [Symbol.toStringTag]: 'Object',
22526 _cacheable: true,
22527 _scopes: scopes,
22528 _rootScopes: finalRootScopes,
22529 _fallback: fallback,
22530 _getTarget: getTarget,
22531 override: (scope)=>_createResolver([
22532 scope,
22533 ...scopes
22534 ], prefixes, finalRootScopes, fallback)
22535 };
22536 return new Proxy(cache, {
22537 /**
22538 * A trap for the delete operator.
22539 */ deleteProperty (target, prop) {
22540 delete target[prop]; // remove from cache
22541 delete target._keys; // remove cached keys
22542 delete scopes[0][prop]; // remove from top level scope
22543 return true;
22544 },
22545 /**
22546 * A trap for getting property values.
22547 */ get (target, prop) {
22548 return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));
22549 },
22550 /**
22551 * A trap for Object.getOwnPropertyDescriptor.
22552 * Also used by Object.hasOwnProperty.
22553 */ getOwnPropertyDescriptor (target, prop) {
22554 return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
22555 },
22556 /**
22557 * A trap for Object.getPrototypeOf.
22558 */ getPrototypeOf () {
22559 return Reflect.getPrototypeOf(scopes[0]);
22560 },
22561 /**
22562 * A trap for the in operator.
22563 */ has (target, prop) {
22564 return getKeysFromAllScopes(target).includes(prop);
22565 },
22566 /**
22567 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22568 */ ownKeys (target) {
22569 return getKeysFromAllScopes(target);
22570 },
22571 /**
22572 * A trap for setting property values.
22573 */ set (target, prop, value) {
22574 const storage = target._storage || (target._storage = getTarget());
22575 target[prop] = storage[prop] = value; // set to top level scope + cache
22576 delete target._keys; // remove cached keys
22577 return true;
22578 }
22579 });
22580 }
22581 /**
22582 * Returns an Proxy for resolving option values with context.
22583 * @param proxy - The Proxy returned by `_createResolver`
22584 * @param context - Context object for scriptable/indexable options
22585 * @param subProxy - The proxy provided for scriptable options
22586 * @param descriptorDefaults - Defaults for descriptors
22587 * @private
22588 */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {
22589 const cache = {
22590 _cacheable: false,
22591 _proxy: proxy,
22592 _context: context,
22593 _subProxy: subProxy,
22594 _stack: new Set(),
22595 _descriptors: _descriptors(proxy, descriptorDefaults),
22596 setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),
22597 override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
22598 };
22599 return new Proxy(cache, {
22600 /**
22601 * A trap for the delete operator.
22602 */ deleteProperty (target, prop) {
22603 delete target[prop]; // remove from cache
22604 delete proxy[prop]; // remove from proxy
22605 return true;
22606 },
22607 /**
22608 * A trap for getting property values.
22609 */ get (target, prop, receiver) {
22610 return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));
22611 },
22612 /**
22613 * A trap for Object.getOwnPropertyDescriptor.
22614 * Also used by Object.hasOwnProperty.
22615 */ getOwnPropertyDescriptor (target, prop) {
22616 return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
22617 enumerable: true,
22618 configurable: true
22619 } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);
22620 },
22621 /**
22622 * A trap for Object.getPrototypeOf.
22623 */ getPrototypeOf () {
22624 return Reflect.getPrototypeOf(proxy);
22625 },
22626 /**
22627 * A trap for the in operator.
22628 */ has (target, prop) {
22629 return Reflect.has(proxy, prop);
22630 },
22631 /**
22632 * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
22633 */ ownKeys () {
22634 return Reflect.ownKeys(proxy);
22635 },
22636 /**
22637 * A trap for setting property values.
22638 */ set (target, prop, value) {
22639 proxy[prop] = value; // set to proxy
22640 delete target[prop]; // remove from cache
22641 return true;
22642 }
22643 });
22644 }
22645 /**
22646 * @private
22647 */ function _descriptors(proxy, defaults = {
22648 scriptable: true,
22649 indexable: true
22650 }) {
22651 const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;
22652 return {
22653 allKeys: _allKeys,
22654 scriptable: _scriptable,
22655 indexable: _indexable,
22656 isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,
22657 isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable
22658 };
22659 }
22660 const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;
22661 const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);
22662 function _cached(target, prop, resolve) {
22663 if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {
22664 return target[prop];
22665 }
22666 const value = resolve();
22667 // cache the resolved value
22668 target[prop] = value;
22669 return value;
22670 }
22671 function _resolveWithContext(target, prop, receiver) {
22672 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22673 let value = _proxy[prop]; // resolve from proxy
22674 // resolve with context
22675 if (isFunction(value) && descriptors.isScriptable(prop)) {
22676 value = _resolveScriptable(prop, value, target, receiver);
22677 }
22678 if (isArray(value) && value.length) {
22679 value = _resolveArray(prop, value, target, descriptors.isIndexable);
22680 }
22681 if (needsSubResolver(prop, value)) {
22682 // if the resolved value is an object, create a sub resolver for it
22683 value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
22684 }
22685 return value;
22686 }
22687 function _resolveScriptable(prop, getValue, target, receiver) {
22688 const { _proxy , _context , _subProxy , _stack } = target;
22689 if (_stack.has(prop)) {
22690 throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
22691 }
22692 _stack.add(prop);
22693 let value = getValue(_context, _subProxy || receiver);
22694 _stack.delete(prop);
22695 if (needsSubResolver(prop, value)) {
22696 // When scriptable option returns an object, create a resolver on that.
22697 value = createSubResolver(_proxy._scopes, _proxy, prop, value);
22698 }
22699 return value;
22700 }
22701 function _resolveArray(prop, value, target, isIndexable) {
22702 const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
22703 if (typeof _context.index !== 'undefined' && isIndexable(prop)) {
22704 return value[_context.index % value.length];
22705 } else if (isObject(value[0])) {
22706 // Array of objects, return array or resolvers
22707 const arr = value;
22708 const scopes = _proxy._scopes.filter((s)=>s !== arr);
22709 value = [];
22710 for (const item of arr){
22711 const resolver = createSubResolver(scopes, _proxy, prop, item);
22712 value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
22713 }
22714 }
22715 return value;
22716 }
22717 function resolveFallback(fallback, prop, value) {
22718 return isFunction(fallback) ? fallback(prop, value) : fallback;
22719 }
22720 const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
22721 function addScopes(set, parentScopes, key, parentFallback, value) {
22722 for (const parent of parentScopes){
22723 const scope = getScope(key, parent);
22724 if (scope) {
22725 set.add(scope);
22726 const fallback = resolveFallback(scope._fallback, key, value);
22727 if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {
22728 // When we reach the descriptor that defines a new _fallback, return that.
22729 // The fallback will resume to that new scope.
22730 return fallback;
22731 }
22732 } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {
22733 // Fallback to `false` results to `false`, when falling back to different key.
22734 // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`
22735 return null;
22736 }
22737 }
22738 return false;
22739 }
22740 function createSubResolver(parentScopes, resolver, prop, value) {
22741 const rootScopes = resolver._rootScopes;
22742 const fallback = resolveFallback(resolver._fallback, prop, value);
22743 const allScopes = [
22744 ...parentScopes,
22745 ...rootScopes
22746 ];
22747 const set = new Set();
22748 set.add(value);
22749 let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
22750 if (key === null) {
22751 return false;
22752 }
22753 if (typeof fallback !== 'undefined' && fallback !== prop) {
22754 key = addScopesFromKey(set, allScopes, fallback, key, value);
22755 if (key === null) {
22756 return false;
22757 }
22758 }
22759 return _createResolver(Array.from(set), [
22760 ''
22761 ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));
22762 }
22763 function addScopesFromKey(set, allScopes, key, fallback, item) {
22764 while(key){
22765 key = addScopes(set, allScopes, key, fallback, item);
22766 }
22767 return key;
22768 }
22769 function subGetTarget(resolver, prop, value) {
22770 const parent = resolver._getTarget();
22771 if (!(prop in parent)) {
22772 parent[prop] = {};
22773 }
22774 const target = parent[prop];
22775 if (isArray(target) && isObject(value)) {
22776 // For array of objects, the object is used to store updated values
22777 return value;
22778 }
22779 return target || {};
22780 }
22781 function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
22782 let value;
22783 for (const prefix of prefixes){
22784 value = _resolve(readKey(prefix, prop), scopes);
22785 if (typeof value !== 'undefined') {
22786 return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
22787 }
22788 }
22789 }
22790 function _resolve(key, scopes) {
22791 for (const scope of scopes){
22792 if (!scope) {
22793 continue;
22794 }
22795 const value = scope[key];
22796 if (typeof value !== 'undefined') {
22797 return value;
22798 }
22799 }
22800 }
22801 function getKeysFromAllScopes(target) {
22802 let keys = target._keys;
22803 if (!keys) {
22804 keys = target._keys = resolveKeysFromAllScopes(target._scopes);
22805 }
22806 return keys;
22807 }
22808 function resolveKeysFromAllScopes(scopes) {
22809 const set = new Set();
22810 for (const scope of scopes){
22811 for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){
22812 set.add(key);
22813 }
22814 }
22815 return Array.from(set);
22816 }
22817 function _parseObjectDataRadialScale(meta, data, start, count) {
22818 const { iScale } = meta;
22819 const { key ='r' } = this._parsing;
22820 const parsed = new Array(count);
22821 let i, ilen, index, item;
22822 for(i = 0, ilen = count; i < ilen; ++i){
22823 index = i + start;
22824 item = data[index];
22825 parsed[i] = {
22826 r: iScale.parse(resolveObjectKey(item, key), index)
22827 };
22828 }
22829 return parsed;
22830 }
22831
22832 const EPSILON = Number.EPSILON || 1e-14;
22833 const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];
22834 const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';
22835 function splineCurve(firstPoint, middlePoint, afterPoint, t) {
22836 // Props to Rob Spencer at scaled innovation for his post on splining between points
22837 // http://scaledinnovation.com/analytics/splines/aboutSplines.html
22838 // This function must also respect "skipped" points
22839 const previous = firstPoint.skip ? middlePoint : firstPoint;
22840 const current = middlePoint;
22841 const next = afterPoint.skip ? middlePoint : afterPoint;
22842 const d01 = distanceBetweenPoints(current, previous);
22843 const d12 = distanceBetweenPoints(next, current);
22844 let s01 = d01 / (d01 + d12);
22845 let s12 = d12 / (d01 + d12);
22846 // If all points are the same, s01 & s02 will be inf
22847 s01 = isNaN(s01) ? 0 : s01;
22848 s12 = isNaN(s12) ? 0 : s12;
22849 const fa = t * s01; // scaling factor for triangle Ta
22850 const fb = t * s12;
22851 return {
22852 previous: {
22853 x: current.x - fa * (next.x - previous.x),
22854 y: current.y - fa * (next.y - previous.y)
22855 },
22856 next: {
22857 x: current.x + fb * (next.x - previous.x),
22858 y: current.y + fb * (next.y - previous.y)
22859 }
22860 };
22861 }
22862 /**
22863 * Adjust tangents to ensure monotonic properties
22864 */ function monotoneAdjust(points, deltaK, mK) {
22865 const pointsLen = points.length;
22866 let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
22867 let pointAfter = getPoint(points, 0);
22868 for(let i = 0; i < pointsLen - 1; ++i){
22869 pointCurrent = pointAfter;
22870 pointAfter = getPoint(points, i + 1);
22871 if (!pointCurrent || !pointAfter) {
22872 continue;
22873 }
22874 if (almostEquals(deltaK[i], 0, EPSILON)) {
22875 mK[i] = mK[i + 1] = 0;
22876 continue;
22877 }
22878 alphaK = mK[i] / deltaK[i];
22879 betaK = mK[i + 1] / deltaK[i];
22880 squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
22881 if (squaredMagnitude <= 9) {
22882 continue;
22883 }
22884 tauK = 3 / Math.sqrt(squaredMagnitude);
22885 mK[i] = alphaK * tauK * deltaK[i];
22886 mK[i + 1] = betaK * tauK * deltaK[i];
22887 }
22888 }
22889 function monotoneCompute(points, mK, indexAxis = 'x') {
22890 const valueAxis = getValueAxis(indexAxis);
22891 const pointsLen = points.length;
22892 let delta, pointBefore, pointCurrent;
22893 let pointAfter = getPoint(points, 0);
22894 for(let i = 0; i < pointsLen; ++i){
22895 pointBefore = pointCurrent;
22896 pointCurrent = pointAfter;
22897 pointAfter = getPoint(points, i + 1);
22898 if (!pointCurrent) {
22899 continue;
22900 }
22901 const iPixel = pointCurrent[indexAxis];
22902 const vPixel = pointCurrent[valueAxis];
22903 if (pointBefore) {
22904 delta = (iPixel - pointBefore[indexAxis]) / 3;
22905 pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
22906 pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
22907 }
22908 if (pointAfter) {
22909 delta = (pointAfter[indexAxis] - iPixel) / 3;
22910 pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
22911 pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
22912 }
22913 }
22914 }
22915 /**
22916 * This function calculates Bézier control points in a similar way than |splineCurve|,
22917 * but preserves monotonicity of the provided data and ensures no local extremums are added
22918 * between the dataset discrete points due to the interpolation.
22919 * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
22920 */ function splineCurveMonotone(points, indexAxis = 'x') {
22921 const valueAxis = getValueAxis(indexAxis);
22922 const pointsLen = points.length;
22923 const deltaK = Array(pointsLen).fill(0);
22924 const mK = Array(pointsLen);
22925 // Calculate slopes (deltaK) and initialize tangents (mK)
22926 let i, pointBefore, pointCurrent;
22927 let pointAfter = getPoint(points, 0);
22928 for(i = 0; i < pointsLen; ++i){
22929 pointBefore = pointCurrent;
22930 pointCurrent = pointAfter;
22931 pointAfter = getPoint(points, i + 1);
22932 if (!pointCurrent) {
22933 continue;
22934 }
22935 if (pointAfter) {
22936 const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
22937 // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
22938 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
22939 }
22940 mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;
22941 }
22942 monotoneAdjust(points, deltaK, mK);
22943 monotoneCompute(points, mK, indexAxis);
22944 }
22945 function capControlPoint(pt, min, max) {
22946 return Math.max(Math.min(pt, max), min);
22947 }
22948 function capBezierPoints(points, area) {
22949 let i, ilen, point, inArea, inAreaPrev;
22950 let inAreaNext = _isPointInArea(points[0], area);
22951 for(i = 0, ilen = points.length; i < ilen; ++i){
22952 inAreaPrev = inArea;
22953 inArea = inAreaNext;
22954 inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
22955 if (!inArea) {
22956 continue;
22957 }
22958 point = points[i];
22959 if (inAreaPrev) {
22960 point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
22961 point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
22962 }
22963 if (inAreaNext) {
22964 point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
22965 point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
22966 }
22967 }
22968 }
22969 /**
22970 * @private
22971 */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
22972 let i, ilen, point, controlPoints;
22973 // Only consider points that are drawn in case the spanGaps option is used
22974 if (options.spanGaps) {
22975 points = points.filter((pt)=>!pt.skip);
22976 }
22977 if (options.cubicInterpolationMode === 'monotone') {
22978 splineCurveMonotone(points, indexAxis);
22979 } else {
22980 let prev = loop ? points[points.length - 1] : points[0];
22981 for(i = 0, ilen = points.length; i < ilen; ++i){
22982 point = points[i];
22983 controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);
22984 point.cp1x = controlPoints.previous.x;
22985 point.cp1y = controlPoints.previous.y;
22986 point.cp2x = controlPoints.next.x;
22987 point.cp2y = controlPoints.next.y;
22988 prev = point;
22989 }
22990 }
22991 if (options.capBezierPoints) {
22992 capBezierPoints(points, area);
22993 }
22994 }
22995
22996 /**
22997 * @private
22998 */ function _isDomSupported() {
22999 return typeof window !== 'undefined' && typeof document !== 'undefined';
23000 }
23001 /**
23002 * @private
23003 */ function _getParentNode(domNode) {
23004 let parent = domNode.parentNode;
23005 if (parent && parent.toString() === '[object ShadowRoot]') {
23006 parent = parent.host;
23007 }
23008 return parent;
23009 }
23010 /**
23011 * convert max-width/max-height values that may be percentages into a number
23012 * @private
23013 */ function parseMaxStyle(styleValue, node, parentProperty) {
23014 let valueInPixels;
23015 if (typeof styleValue === 'string') {
23016 valueInPixels = parseInt(styleValue, 10);
23017 if (styleValue.indexOf('%') !== -1) {
23018 // percentage * size in dimension
23019 valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
23020 }
23021 } else {
23022 valueInPixels = styleValue;
23023 }
23024 return valueInPixels;
23025 }
23026 const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);
23027 function getStyle(el, property) {
23028 return getComputedStyle(el).getPropertyValue(property);
23029 }
23030 const positions = [
23031 'top',
23032 'right',
23033 'bottom',
23034 'left'
23035 ];
23036 function getPositionedStyle(styles, style, suffix) {
23037 const result = {};
23038 suffix = suffix ? '-' + suffix : '';
23039 for(let i = 0; i < 4; i++){
23040 const pos = positions[i];
23041 result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
23042 }
23043 result.width = result.left + result.right;
23044 result.height = result.top + result.bottom;
23045 return result;
23046 }
23047 const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);
23048 /**
23049 * @param e
23050 * @param canvas
23051 * @returns Canvas position
23052 */ function getCanvasPosition(e, canvas) {
23053 const touches = e.touches;
23054 const source = touches && touches.length ? touches[0] : e;
23055 const { offsetX , offsetY } = source;
23056 let box = false;
23057 let x, y;
23058 if (useOffsetPos(offsetX, offsetY, e.target)) {
23059 x = offsetX;
23060 y = offsetY;
23061 } else {
23062 const rect = canvas.getBoundingClientRect();
23063 x = source.clientX - rect.left;
23064 y = source.clientY - rect.top;
23065 box = true;
23066 }
23067 return {
23068 x,
23069 y,
23070 box
23071 };
23072 }
23073 /**
23074 * Gets an event's x, y coordinates, relative to the chart area
23075 * @param event
23076 * @param chart
23077 * @returns x and y coordinates of the event
23078 */ function getRelativePosition(event, chart) {
23079 if ('native' in event) {
23080 return event;
23081 }
23082 const { canvas , currentDevicePixelRatio } = chart;
23083 const style = getComputedStyle(canvas);
23084 const borderBox = style.boxSizing === 'border-box';
23085 const paddings = getPositionedStyle(style, 'padding');
23086 const borders = getPositionedStyle(style, 'border', 'width');
23087 const { x , y , box } = getCanvasPosition(event, canvas);
23088 const xOffset = paddings.left + (box && borders.left);
23089 const yOffset = paddings.top + (box && borders.top);
23090 let { width , height } = chart;
23091 if (borderBox) {
23092 width -= paddings.width + borders.width;
23093 height -= paddings.height + borders.height;
23094 }
23095 return {
23096 x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
23097 y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
23098 };
23099 }
23100 function getContainerSize(canvas, width, height) {
23101 let maxWidth, maxHeight;
23102 if (width === undefined || height === undefined) {
23103 const container = canvas && _getParentNode(canvas);
23104 if (!container) {
23105 width = canvas.clientWidth;
23106 height = canvas.clientHeight;
23107 } else {
23108 const rect = container.getBoundingClientRect(); // this is the border box of the container
23109 const containerStyle = getComputedStyle(container);
23110 const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
23111 const containerPadding = getPositionedStyle(containerStyle, 'padding');
23112 width = rect.width - containerPadding.width - containerBorder.width;
23113 height = rect.height - containerPadding.height - containerBorder.height;
23114 maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
23115 maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
23116 }
23117 }
23118 return {
23119 width,
23120 height,
23121 maxWidth: maxWidth || INFINITY,
23122 maxHeight: maxHeight || INFINITY
23123 };
23124 }
23125 const round1 = (v)=>Math.round(v * 10) / 10;
23126 // eslint-disable-next-line complexity
23127 function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
23128 const style = getComputedStyle(canvas);
23129 const margins = getPositionedStyle(style, 'margin');
23130 const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
23131 const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
23132 const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
23133 let { width , height } = containerSize;
23134 if (style.boxSizing === 'content-box') {
23135 const borders = getPositionedStyle(style, 'border', 'width');
23136 const paddings = getPositionedStyle(style, 'padding');
23137 width -= paddings.width + borders.width;
23138 height -= paddings.height + borders.height;
23139 }
23140 width = Math.max(0, width - margins.width);
23141 height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
23142 width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
23143 height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
23144 if (width && !height) {
23145 // https://github.com/chartjs/Chart.js/issues/4659
23146 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)
23147 height = round1(width / 2);
23148 }
23149 const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;
23150 if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
23151 height = containerSize.height;
23152 width = round1(Math.floor(height * aspectRatio));
23153 }
23154 return {
23155 width,
23156 height
23157 };
23158 }
23159 /**
23160 * @param chart
23161 * @param forceRatio
23162 * @param forceStyle
23163 * @returns True if the canvas context size or transformation has changed.
23164 */ function retinaScale(chart, forceRatio, forceStyle) {
23165 const pixelRatio = forceRatio || 1;
23166 const deviceHeight = round1(chart.height * pixelRatio);
23167 const deviceWidth = round1(chart.width * pixelRatio);
23168 chart.height = round1(chart.height);
23169 chart.width = round1(chart.width);
23170 const canvas = chart.canvas;
23171 // If no style has been set on the canvas, the render size is used as display size,
23172 // making the chart visually bigger, so let's enforce it to the "correct" values.
23173 // See https://github.com/chartjs/Chart.js/issues/3575
23174 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
23175 canvas.style.height = `${chart.height}px`;
23176 canvas.style.width = `${chart.width}px`;
23177 }
23178 if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
23179 chart.currentDevicePixelRatio = pixelRatio;
23180 canvas.height = deviceHeight;
23181 canvas.width = deviceWidth;
23182 chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
23183 return true;
23184 }
23185 return false;
23186 }
23187 /**
23188 * Detects support for options object argument in addEventListener.
23189 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
23190 * @private
23191 */ const supportsEventListenerOptions = function() {
23192 let passiveSupported = false;
23193 try {
23194 const options = {
23195 get passive () {
23196 passiveSupported = true;
23197 return false;
23198 }
23199 };
23200 if (_isDomSupported()) {
23201 window.addEventListener('test', null, options);
23202 window.removeEventListener('test', null, options);
23203 }
23204 } catch (e) {
23205 // continue regardless of error
23206 }
23207 return passiveSupported;
23208 }();
23209 /**
23210 * The "used" size is the final value of a dimension property after all calculations have
23211 * been performed. This method uses the computed style of `element` but returns undefined
23212 * if the computed style is not expressed in pixels. That can happen in some cases where
23213 * `element` has a size relative to its parent and this last one is not yet displayed,
23214 * for example because of `display: none` on a parent node.
23215 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
23216 * @returns Size in pixels or undefined if unknown.
23217 */ function readUsedSize(element, property) {
23218 const value = getStyle(element, property);
23219 const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
23220 return matches ? +matches[1] : undefined;
23221 }
23222
23223 /**
23224 * @private
23225 */ function _pointInLine(p1, p2, t, mode) {
23226 return {
23227 x: p1.x + t * (p2.x - p1.x),
23228 y: p1.y + t * (p2.y - p1.y)
23229 };
23230 }
23231 /**
23232 * @private
23233 */ function _steppedInterpolation(p1, p2, t, mode) {
23234 return {
23235 x: p1.x + t * (p2.x - p1.x),
23236 y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y
23237 };
23238 }
23239 /**
23240 * @private
23241 */ function _bezierInterpolation(p1, p2, t, mode) {
23242 const cp1 = {
23243 x: p1.cp2x,
23244 y: p1.cp2y
23245 };
23246 const cp2 = {
23247 x: p2.cp1x,
23248 y: p2.cp1y
23249 };
23250 const a = _pointInLine(p1, cp1, t);
23251 const b = _pointInLine(cp1, cp2, t);
23252 const c = _pointInLine(cp2, p2, t);
23253 const d = _pointInLine(a, b, t);
23254 const e = _pointInLine(b, c, t);
23255 return _pointInLine(d, e, t);
23256 }
23257
23258 const getRightToLeftAdapter = function(rectX, width) {
23259 return {
23260 x (x) {
23261 return rectX + rectX + width - x;
23262 },
23263 setWidth (w) {
23264 width = w;
23265 },
23266 textAlign (align) {
23267 if (align === 'center') {
23268 return align;
23269 }
23270 return align === 'right' ? 'left' : 'right';
23271 },
23272 xPlus (x, value) {
23273 return x - value;
23274 },
23275 leftForLtr (x, itemWidth) {
23276 return x - itemWidth;
23277 }
23278 };
23279 };
23280 const getLeftToRightAdapter = function() {
23281 return {
23282 x (x) {
23283 return x;
23284 },
23285 setWidth (w) {},
23286 textAlign (align) {
23287 return align;
23288 },
23289 xPlus (x, value) {
23290 return x + value;
23291 },
23292 leftForLtr (x, _itemWidth) {
23293 return x;
23294 }
23295 };
23296 };
23297 function getRtlAdapter(rtl, rectX, width) {
23298 return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
23299 }
23300 function overrideTextDirection(ctx, direction) {
23301 let style, original;
23302 if (direction === 'ltr' || direction === 'rtl') {
23303 style = ctx.canvas.style;
23304 original = [
23305 style.getPropertyValue('direction'),
23306 style.getPropertyPriority('direction')
23307 ];
23308 style.setProperty('direction', direction, 'important');
23309 ctx.prevTextDirection = original;
23310 }
23311 }
23312 function restoreTextDirection(ctx, original) {
23313 if (original !== undefined) {
23314 delete ctx.prevTextDirection;
23315 ctx.canvas.style.setProperty('direction', original[0], original[1]);
23316 }
23317 }
23318
23319 function propertyFn(property) {
23320 if (property === 'angle') {
23321 return {
23322 between: _angleBetween,
23323 compare: _angleDiff,
23324 normalize: _normalizeAngle
23325 };
23326 }
23327 return {
23328 between: _isBetween,
23329 compare: (a, b)=>a - b,
23330 normalize: (x)=>x
23331 };
23332 }
23333 function normalizeSegment({ start , end , count , loop , style }) {
23334 return {
23335 start: start % count,
23336 end: end % count,
23337 loop: loop && (end - start + 1) % count === 0,
23338 style
23339 };
23340 }
23341 function getSegment(segment, points, bounds) {
23342 const { property , start: startBound , end: endBound } = bounds;
23343 const { between , normalize } = propertyFn(property);
23344 const count = points.length;
23345 let { start , end , loop } = segment;
23346 let i, ilen;
23347 if (loop) {
23348 start += count;
23349 end += count;
23350 for(i = 0, ilen = count; i < ilen; ++i){
23351 if (!between(normalize(points[start % count][property]), startBound, endBound)) {
23352 break;
23353 }
23354 start--;
23355 end--;
23356 }
23357 start %= count;
23358 end %= count;
23359 }
23360 if (end < start) {
23361 end += count;
23362 }
23363 return {
23364 start,
23365 end,
23366 loop,
23367 style: segment.style
23368 };
23369 }
23370 function _boundSegment(segment, points, bounds) {
23371 if (!bounds) {
23372 return [
23373 segment
23374 ];
23375 }
23376 const { property , start: startBound , end: endBound } = bounds;
23377 const count = points.length;
23378 const { compare , between , normalize } = propertyFn(property);
23379 const { start , end , loop , style } = getSegment(segment, points, bounds);
23380 const result = [];
23381 let inside = false;
23382 let subStart = null;
23383 let value, point, prevValue;
23384 const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
23385 const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);
23386 const shouldStart = ()=>inside || startIsBefore();
23387 const shouldStop = ()=>!inside || endIsBefore();
23388 for(let i = start, prev = start; i <= end; ++i){
23389 point = points[i % count];
23390 if (point.skip) {
23391 continue;
23392 }
23393 value = normalize(point[property]);
23394 if (value === prevValue) {
23395 continue;
23396 }
23397 inside = between(value, startBound, endBound);
23398 if (subStart === null && shouldStart()) {
23399 subStart = compare(value, startBound) === 0 ? i : prev;
23400 }
23401 if (subStart !== null && shouldStop()) {
23402 result.push(normalizeSegment({
23403 start: subStart,
23404 end: i,
23405 loop,
23406 count,
23407 style
23408 }));
23409 subStart = null;
23410 }
23411 prev = i;
23412 prevValue = value;
23413 }
23414 if (subStart !== null) {
23415 result.push(normalizeSegment({
23416 start: subStart,
23417 end,
23418 loop,
23419 count,
23420 style
23421 }));
23422 }
23423 return result;
23424 }
23425 function _boundSegments(line, bounds) {
23426 const result = [];
23427 const segments = line.segments;
23428 for(let i = 0; i < segments.length; i++){
23429 const sub = _boundSegment(segments[i], line.points, bounds);
23430 if (sub.length) {
23431 result.push(...sub);
23432 }
23433 }
23434 return result;
23435 }
23436 function findStartAndEnd(points, count, loop, spanGaps) {
23437 let start = 0;
23438 let end = count - 1;
23439 if (loop && !spanGaps) {
23440 while(start < count && !points[start].skip){
23441 start++;
23442 }
23443 }
23444 while(start < count && points[start].skip){
23445 start++;
23446 }
23447 start %= count;
23448 if (loop) {
23449 end += start;
23450 }
23451 while(end > start && points[end % count].skip){
23452 end--;
23453 }
23454 end %= count;
23455 return {
23456 start,
23457 end
23458 };
23459 }
23460 function solidSegments(points, start, max, loop) {
23461 const count = points.length;
23462 const result = [];
23463 let last = start;
23464 let prev = points[start];
23465 let end;
23466 for(end = start + 1; end <= max; ++end){
23467 const cur = points[end % count];
23468 if (cur.skip || cur.stop) {
23469 if (!prev.skip) {
23470 loop = false;
23471 result.push({
23472 start: start % count,
23473 end: (end - 1) % count,
23474 loop
23475 });
23476 start = last = cur.stop ? end : null;
23477 }
23478 } else {
23479 last = end;
23480 if (prev.skip) {
23481 start = end;
23482 }
23483 }
23484 prev = cur;
23485 }
23486 if (last !== null) {
23487 result.push({
23488 start: start % count,
23489 end: last % count,
23490 loop
23491 });
23492 }
23493 return result;
23494 }
23495 function _computeSegments(line, segmentOptions) {
23496 const points = line.points;
23497 const spanGaps = line.options.spanGaps;
23498 const count = points.length;
23499 if (!count) {
23500 return [];
23501 }
23502 const loop = !!line._loop;
23503 const { start , end } = findStartAndEnd(points, count, loop, spanGaps);
23504 if (spanGaps === true) {
23505 return splitByStyles(line, [
23506 {
23507 start,
23508 end,
23509 loop
23510 }
23511 ], points, segmentOptions);
23512 }
23513 const max = end < start ? end + count : end;
23514 const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
23515 return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
23516 }
23517 function splitByStyles(line, segments, points, segmentOptions) {
23518 if (!segmentOptions || !segmentOptions.setContext || !points) {
23519 return segments;
23520 }
23521 return doSplitByStyles(line, segments, points, segmentOptions);
23522 }
23523 function doSplitByStyles(line, segments, points, segmentOptions) {
23524 const chartContext = line._chart.getContext();
23525 const baseStyle = readStyle(line.options);
23526 const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;
23527 const count = points.length;
23528 const result = [];
23529 let prevStyle = baseStyle;
23530 let start = segments[0].start;
23531 let i = start;
23532 function addStyle(s, e, l, st) {
23533 const dir = spanGaps ? -1 : 1;
23534 if (s === e) {
23535 return;
23536 }
23537 s += count;
23538 while(points[s % count].skip){
23539 s -= dir;
23540 }
23541 while(points[e % count].skip){
23542 e += dir;
23543 }
23544 if (s % count !== e % count) {
23545 result.push({
23546 start: s % count,
23547 end: e % count,
23548 loop: l,
23549 style: st
23550 });
23551 prevStyle = st;
23552 start = e % count;
23553 }
23554 }
23555 for (const segment of segments){
23556 start = spanGaps ? start : segment.start;
23557 let prev = points[start % count];
23558 let style;
23559 for(i = start + 1; i <= segment.end; i++){
23560 const pt = points[i % count];
23561 style = readStyle(segmentOptions.setContext(createContext(chartContext, {
23562 type: 'segment',
23563 p0: prev,
23564 p1: pt,
23565 p0DataIndex: (i - 1) % count,
23566 p1DataIndex: i % count,
23567 datasetIndex
23568 })));
23569 if (styleChanged(style, prevStyle)) {
23570 addStyle(start, i - 1, segment.loop, prevStyle);
23571 }
23572 prev = pt;
23573 prevStyle = style;
23574 }
23575 if (start < i - 1) {
23576 addStyle(start, i - 1, segment.loop, prevStyle);
23577 }
23578 }
23579 return result;
23580 }
23581 function readStyle(options) {
23582 return {
23583 backgroundColor: options.backgroundColor,
23584 borderCapStyle: options.borderCapStyle,
23585 borderDash: options.borderDash,
23586 borderDashOffset: options.borderDashOffset,
23587 borderJoinStyle: options.borderJoinStyle,
23588 borderWidth: options.borderWidth,
23589 borderColor: options.borderColor
23590 };
23591 }
23592 function styleChanged(style, prevStyle) {
23593 if (!prevStyle) {
23594 return false;
23595 }
23596 const cache = [];
23597 const replacer = function(key, value) {
23598 if (!isPatternOrGradient(value)) {
23599 return value;
23600 }
23601 if (!cache.includes(value)) {
23602 cache.push(value);
23603 }
23604 return cache.indexOf(value);
23605 };
23606 return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);
23607 }
23608
23609 function getSizeForArea(scale, chartArea, field) {
23610 return scale.options.clip ? scale[field] : chartArea[field];
23611 }
23612 function getDatasetArea(meta, chartArea) {
23613 const { xScale , yScale } = meta;
23614 if (xScale && yScale) {
23615 return {
23616 left: getSizeForArea(xScale, chartArea, 'left'),
23617 right: getSizeForArea(xScale, chartArea, 'right'),
23618 top: getSizeForArea(yScale, chartArea, 'top'),
23619 bottom: getSizeForArea(yScale, chartArea, 'bottom')
23620 };
23621 }
23622 return chartArea;
23623 }
23624 function getDatasetClipArea(chart, meta) {
23625 const clip = meta._clip;
23626 if (clip.disabled) {
23627 return false;
23628 }
23629 const area = getDatasetArea(meta, chart.chartArea);
23630 return {
23631 left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left),
23632 right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right),
23633 top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top),
23634 bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom)
23635 };
23636 }
23637
23638
23639 //# sourceMappingURL=helpers.dataset.js.map
23640
23641
23642 /***/ }
23643
23644 /******/ });
23645 /************************************************************************/
23646 /******/ // The module cache
23647 /******/ const __webpack_module_cache__ = {};
23648 /******/
23649 /******/ // The require function
23650 /******/ function __webpack_require__(moduleId) {
23651 /******/ // Check if module is in cache
23652 /******/ const cachedModule = __webpack_module_cache__[moduleId];
23653 /******/ if (cachedModule !== undefined) {
23654 /******/ return cachedModule.exports;
23655 /******/ }
23656 /******/ // Create a new module (and put it into the cache)
23657 /******/ const module = __webpack_module_cache__[moduleId] = {
23658 /******/ // no module.id needed
23659 /******/ // no module.loaded needed
23660 /******/ exports: {}
23661 /******/ };
23662 /******/
23663 /******/ // Execute the module function
23664 /******/ if (!(moduleId in __webpack_modules__)) {
23665 /******/ delete __webpack_module_cache__[moduleId];
23666 /******/ const e = new Error("Cannot find module '" + moduleId + "'");
23667 /******/ e.code = 'MODULE_NOT_FOUND';
23668 /******/ throw e;
23669 /******/ }
23670 /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
23671 /******/
23672 /******/ // Return the exports of the module
23673 /******/ return module.exports;
23674 /******/ }
23675 /******/
23676 /************************************************************************/
23677 /******/ /* webpack/runtime/compat get default export */
23678 /******/ (() => {
23679 /******/ // getDefaultExport function for compatibility with non-harmony modules
23680 /******/ __webpack_require__.n = (module) => {
23681 /******/ const getter = module && module.__esModule ?
23682 /******/ () => (module['default']) :
23683 /******/ () => (module);
23684 /******/ __webpack_require__.d(getter, { a: getter });
23685 /******/ return getter;
23686 /******/ };
23687 /******/ })();
23688 /******/
23689 /******/ /* webpack/runtime/define property getters */
23690 /******/ (() => {
23691 /******/ // define getter/value functions for harmony exports
23692 /******/ __webpack_require__.d = (exports, definition) => {
23693 /******/ if(Array.isArray(definition)) {
23694 /******/ var i = 0;
23695 /******/ while(i < definition.length) {
23696 /******/ var key = definition[i++];
23697 /******/ var binding = definition[i++];
23698 /******/ if(!__webpack_require__.o(exports, key)) {
23699 /******/ if(binding === 0) {
23700 /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
23701 /******/ } else {
23702 /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
23703 /******/ }
23704 /******/ } else if(binding === 0) { i++; }
23705 /******/ }
23706 /******/ } else {
23707 /******/ for(var key in definition) {
23708 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
23709 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
23710 /******/ }
23711 /******/ }
23712 /******/ }
23713 /******/ };
23714 /******/ })();
23715 /******/
23716 /******/ /* webpack/runtime/hasOwnProperty shorthand */
23717 /******/ (() => {
23718 /******/ __webpack_require__.o = (obj, prop) => (Object.hasOwn(obj, prop))
23719 /******/ })();
23720 /******/
23721 /******/ /* webpack/runtime/make namespace object */
23722 /******/ (() => {
23723 /******/ // define __esModule on exports
23724 /******/ __webpack_require__.r = (exports) => {
23725 /******/ if(Symbol.toStringTag) {
23726 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
23727 /******/ }
23728 /******/ Object.defineProperty(exports, '__esModule', { value: true });
23729 /******/ };
23730 /******/ })();
23731 /******/
23732 /************************************************************************/
23733 let __webpack_exports__ = {};
23734 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
23735 (() => {
23736 "use strict";
23737 /*!************************************************!*\
23738 !*** ./assets/src/js/admin/admin-statistic.js ***!
23739 \************************************************/
23740 __webpack_require__.r(__webpack_exports__);
23741 /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js");
23742 /* 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");
23743 /* 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");
23744 /* 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");
23745 /* 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");
23746 /* 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");
23747 /* 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");
23748 /* 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");
23749 /**
23750 * Statistics dashboard entry — bootstraps the per-tab modules.
23751 *
23752 * All four tabs run on the statistics/* module stack (state, api, chart,
23753 * data-table, report-modal); the legacy per-tab loaders are gone.
23754 *
23755 * @since 4.2.5.5
23756 * @version 2.0.0
23757 */
23758
23759
23760
23761
23762
23763
23764
23765
23766
23767 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.LpStatsFilterBar.selectors.elContainer, () => {
23768 _statistics_filter_bar_js__WEBPACK_IMPORTED_MODULE_1__.lpStatsFilterBar.init();
23769 });
23770 // SweetAlert2 popup: delegated events only, no rendered container to wait for.
23771 _statistics_report_modal_js__WEBPACK_IMPORTED_MODULE_2__.lpStatsReportModal.init();
23772 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.LpStatsTabOverview.selectors.elContainer, () => {
23773 _statistics_tab_overview_js__WEBPACK_IMPORTED_MODULE_3__.lpStatsTabOverview.init();
23774 });
23775 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.LpStatsTabOrders.selectors.elContainer, () => {
23776 _statistics_tab_orders_js__WEBPACK_IMPORTED_MODULE_4__.lpStatsTabOrders.init();
23777 });
23778 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.LpStatsTabCourses.selectors.elContainer, () => {
23779 _statistics_tab_courses_js__WEBPACK_IMPORTED_MODULE_5__.lpStatsTabCourses.init();
23780 });
23781 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.LpStatsTabUsers.selectors.elContainer, () => {
23782 _statistics_tab_users_js__WEBPACK_IMPORTED_MODULE_6__.lpStatsTabUsers.init();
23783 });
23784 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(_statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.LpStatsTabInstructors.selectors.elContainer, () => {
23785 _statistics_tab_instructors_js__WEBPACK_IMPORTED_MODULE_7__.lpStatsTabInstructors.init();
23786 });
23787 })();
23788
23789 /******/ })()
23790 ;
23791 //# sourceMappingURL=admin-statistic.js.map