UNPKG

@embedthis/devcore

Version:

Devcore UI Framework

1,831 lines 729 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { reactive, ref, onMounted, onBeforeUnmount, openBlock, createElementBlock, createElementVNode, normalizeClass } from "vue"; /*! * @kurkle/color v0.3.4 * https://github.com/kurkle/color#readme * (c) 2024 Jukka Kurkela * Released under the MIT License */ function round(v) { return v + 0.5 | 0; } const lim = (v, l, h4) => Math.max(Math.min(v, h4), l); function p2b(v) { return lim(round(v * 2.55), 0, 255); } function n2b(v) { return lim(round(v * 255), 0, 255); } function b2n(v) { return lim(round(v / 2.55) / 100, 0, 1); } function n2p(v) { return lim(round(v * 100), 0, 100); } const map$1 = { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 }; const hex = [..."0123456789ABCDEF"]; const h1 = (b2) => hex[b2 & 15]; const h2 = (b2) => hex[(b2 & 240) >> 4] + hex[b2 & 15]; const eq = (b2) => (b2 & 240) >> 4 === (b2 & 15); const isShort = (v) => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); function hexParse(str) { var len = str.length; var ret; if (str[0] === "#") { if (len === 4 || len === 5) { ret = { r: 255 & map$1[str[1]] * 17, g: 255 & map$1[str[2]] * 17, b: 255 & map$1[str[3]] * 17, a: len === 5 ? map$1[str[4]] * 17 : 255 }; } else if (len === 7 || len === 9) { ret = { r: map$1[str[1]] << 4 | map$1[str[2]], g: map$1[str[3]] << 4 | map$1[str[4]], b: map$1[str[5]] << 4 | map$1[str[6]], a: len === 9 ? map$1[str[7]] << 4 | map$1[str[8]] : 255 }; } } return ret; } const alpha = (a3, f) => a3 < 255 ? f(a3) : ""; function hexString(v) { var f = isShort(v) ? h1 : h2; return v ? "#" + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f) : void 0; } const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; function hsl2rgbn(h4, s3, l) { const a3 = s3 * Math.min(l, 1 - l); const f = (n, k2 = (n + h4 / 30) % 12) => l - a3 * Math.max(Math.min(k2 - 3, 9 - k2, 1), -1); return [f(0), f(8), f(4)]; } function hsv2rgbn(h4, s3, v) { const f = (n, k2 = (n + h4 / 60) % 6) => v - v * s3 * Math.max(Math.min(k2, 4 - k2, 1), 0); return [f(5), f(3), f(1)]; } function hwb2rgbn(h4, w2, b2) { const rgb = hsl2rgbn(h4, 1, 0.5); let i2; if (w2 + b2 > 1) { i2 = 1 / (w2 + b2); w2 *= i2; b2 *= i2; } for (i2 = 0; i2 < 3; i2++) { rgb[i2] *= 1 - w2 - b2; rgb[i2] += w2; } return rgb; } function hueValue(r, g, b2, d3, max) { if (r === max) { return (g - b2) / d3 + (g < b2 ? 6 : 0); } if (g === max) { return (b2 - r) / d3 + 2; } return (r - g) / d3 + 4; } function rgb2hsl(v) { const range = 255; const r = v.r / range; const g = v.g / range; const b2 = v.b / range; const max = Math.max(r, g, b2); const min = Math.min(r, g, b2); const l = (max + min) / 2; let h4, s3, d3; if (max !== min) { d3 = max - min; s3 = l > 0.5 ? d3 / (2 - max - min) : d3 / (max + min); h4 = hueValue(r, g, b2, d3, max); h4 = h4 * 60 + 0.5; } return [h4 | 0, s3 || 0, l]; } function calln(f, a3, b2, c2) { return (Array.isArray(a3) ? f(a3[0], a3[1], a3[2]) : f(a3, b2, c2)).map(n2b); } function hsl2rgb(h4, s3, l) { return calln(hsl2rgbn, h4, s3, l); } function hwb2rgb(h4, w2, b2) { return calln(hwb2rgbn, h4, w2, b2); } function hsv2rgb(h4, s3, v) { return calln(hsv2rgbn, h4, s3, v); } function hue(h4) { return (h4 % 360 + 360) % 360; } function hueParse(str) { const m3 = HUE_RE.exec(str); let a3 = 255; let v; if (!m3) { return; } if (m3[5] !== v) { a3 = m3[6] ? p2b(+m3[5]) : n2b(+m3[5]); } const h4 = hue(+m3[2]); const p1 = +m3[3] / 100; const p2 = +m3[4] / 100; if (m3[1] === "hwb") { v = hwb2rgb(h4, p1, p2); } else if (m3[1] === "hsv") { v = hsv2rgb(h4, p1, p2); } else { v = hsl2rgb(h4, p1, p2); } return { r: v[0], g: v[1], b: v[2], a: a3 }; } function rotate(v, deg) { var h4 = rgb2hsl(v); h4[0] = hue(h4[0] + deg); h4 = hsl2rgb(h4); v.r = h4[0]; v.g = h4[1]; v.b = h4[2]; } function hslString(v) { if (!v) { return; } const a3 = rgb2hsl(v); const h4 = a3[0]; const s3 = n2p(a3[1]); const l = n2p(a3[2]); return v.a < 255 ? `hsla(${h4}, ${s3}%, ${l}%, ${b2n(v.a)})` : `hsl(${h4}, ${s3}%, ${l}%)`; } const map = { x: "dark", Z: "light", Y: "re", X: "blu", W: "gr", V: "medium", U: "slate", A: "ee", T: "ol", S: "or", B: "ra", C: "lateg", D: "ights", R: "in", Q: "turquois", E: "hi", P: "ro", O: "al", N: "le", M: "de", L: "yello", F: "en", K: "ch", G: "arks", H: "ea", I: "ightg", J: "wh" }; const names$1 = { OiceXe: "f0f8ff", antiquewEte: "faebd7", aqua: "ffff", aquamarRe: "7fffd4", azuY: "f0ffff", beige: "f5f5dc", bisque: "ffe4c4", black: "0", blanKedOmond: "ffebcd", Xe: "ff", XeviTet: "8a2be2", bPwn: "a52a2a", burlywood: "deb887", caMtXe: "5f9ea0", KartYuse: "7fff00", KocTate: "d2691e", cSO: "ff7f50", cSnflowerXe: "6495ed", cSnsilk: "fff8dc", crimson: "dc143c", cyan: "ffff", xXe: "8b", xcyan: "8b8b", xgTMnPd: "b8860b", xWay: "a9a9a9", xgYF: "6400", xgYy: "a9a9a9", xkhaki: "bdb76b", xmagFta: "8b008b", xTivegYF: "556b2f", xSange: "ff8c00", xScEd: "9932cc", xYd: "8b0000", xsOmon: "e9967a", xsHgYF: "8fbc8f", xUXe: "483d8b", xUWay: "2f4f4f", xUgYy: "2f4f4f", xQe: "ced1", xviTet: "9400d3", dAppRk: "ff1493", dApskyXe: "bfff", dimWay: "696969", dimgYy: "696969", dodgerXe: "1e90ff", fiYbrick: "b22222", flSOwEte: "fffaf0", foYstWAn: "228b22", fuKsia: "ff00ff", gaRsbSo: "dcdcdc", ghostwEte: "f8f8ff", gTd: "ffd700", gTMnPd: "daa520", Way: "808080", gYF: "8000", gYFLw: "adff2f", gYy: "808080", honeyMw: "f0fff0", hotpRk: "ff69b4", RdianYd: "cd5c5c", Rdigo: "4b0082", ivSy: "fffff0", khaki: "f0e68c", lavFMr: "e6e6fa", lavFMrXsh: "fff0f5", lawngYF: "7cfc00", NmoncEffon: "fffacd", ZXe: "add8e6", ZcSO: "f08080", Zcyan: "e0ffff", ZgTMnPdLw: "fafad2", ZWay: "d3d3d3", ZgYF: "90ee90", ZgYy: "d3d3d3", ZpRk: "ffb6c1", ZsOmon: "ffa07a", ZsHgYF: "20b2aa", ZskyXe: "87cefa", ZUWay: "778899", ZUgYy: "778899", ZstAlXe: "b0c4de", ZLw: "ffffe0", lime: "ff00", limegYF: "32cd32", lRF: "faf0e6", magFta: "ff00ff", maPon: "800000", VaquamarRe: "66cdaa", VXe: "cd", VScEd: "ba55d3", VpurpN: "9370db", VsHgYF: "3cb371", VUXe: "7b68ee", VsprRggYF: "fa9a", VQe: "48d1cc", VviTetYd: "c71585", midnightXe: "191970", mRtcYam: "f5fffa", mistyPse: "ffe4e1", moccasR: "ffe4b5", navajowEte: "ffdead", navy: "80", Tdlace: "fdf5e6", Tive: "808000", TivedBb: "6b8e23", Sange: "ffa500", SangeYd: "ff4500", ScEd: "da70d6", pOegTMnPd: "eee8aa", pOegYF: "98fb98", pOeQe: "afeeee", pOeviTetYd: "db7093", papayawEp: "ffefd5", pHKpuff: "ffdab9", peru: "cd853f", pRk: "ffc0cb", plum: "dda0dd", powMrXe: "b0e0e6", purpN: "800080", YbeccapurpN: "663399", Yd: "ff0000", Psybrown: "bc8f8f", PyOXe: "4169e1", saddNbPwn: "8b4513", sOmon: "fa8072", sandybPwn: "f4a460", sHgYF: "2e8b57", sHshell: "fff5ee", siFna: "a0522d", silver: "c0c0c0", skyXe: "87ceeb", UXe: "6a5acd", UWay: "708090", UgYy: "708090", snow: "fffafa", sprRggYF: "ff7f", stAlXe: "4682b4", tan: "d2b48c", teO: "8080", tEstN: "d8bfd8", tomato: "ff6347", Qe: "40e0d0", viTet: "ee82ee", JHt: "f5deb3", wEte: "ffffff", wEtesmoke: "f5f5f5", Lw: "ffff00", LwgYF: "9acd32" }; function unpack() { const unpacked = {}; const keys = Object.keys(names$1); const tkeys = Object.keys(map); let i2, j, k2, ok, nk; for (i2 = 0; i2 < keys.length; i2++) { ok = nk = keys[i2]; for (j = 0; j < tkeys.length; j++) { k2 = tkeys[j]; nk = nk.replace(k2, map[k2]); } k2 = parseInt(names$1[ok], 16); unpacked[nk] = [k2 >> 16 & 255, k2 >> 8 & 255, k2 & 255]; } return unpacked; } let names; function nameParse(str) { if (!names) { names = unpack(); names.transparent = [0, 0, 0, 0]; } const a3 = names[str.toLowerCase()]; return a3 && { r: a3[0], g: a3[1], b: a3[2], a: a3.length === 4 ? a3[3] : 255 }; } const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; function rgbParse(str) { const m3 = RGB_RE.exec(str); let a3 = 255; let r, g, b2; if (!m3) { return; } if (m3[7] !== r) { const v = +m3[7]; a3 = m3[8] ? p2b(v) : lim(v * 255, 0, 255); } r = +m3[1]; g = +m3[3]; b2 = +m3[5]; r = 255 & (m3[2] ? p2b(r) : lim(r, 0, 255)); g = 255 & (m3[4] ? p2b(g) : lim(g, 0, 255)); b2 = 255 & (m3[6] ? p2b(b2) : lim(b2, 0, 255)); return { r, g, b: b2, a: a3 }; } function rgbString(v) { return v && (v.a < 255 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` : `rgb(${v.r}, ${v.g}, ${v.b})`); } const to = (v) => v <= 31308e-7 ? v * 12.92 : Math.pow(v, 1 / 2.4) * 1.055 - 0.055; const from = (v) => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); function interpolate$1(rgb1, rgb2, t2) { const r = from(b2n(rgb1.r)); const g = from(b2n(rgb1.g)); const b2 = from(b2n(rgb1.b)); return { r: n2b(to(r + t2 * (from(b2n(rgb2.r)) - r))), g: n2b(to(g + t2 * (from(b2n(rgb2.g)) - g))), b: n2b(to(b2 + t2 * (from(b2n(rgb2.b)) - b2))), a: rgb1.a + t2 * (rgb2.a - rgb1.a) }; } function modHSL(v, i2, ratio) { if (v) { let tmp = rgb2hsl(v); tmp[i2] = Math.max(0, Math.min(tmp[i2] + tmp[i2] * ratio, i2 === 0 ? 360 : 1)); tmp = hsl2rgb(tmp); v.r = tmp[0]; v.g = tmp[1]; v.b = tmp[2]; } } function clone$1(v, proto) { return v ? Object.assign(proto || {}, v) : v; } function fromObject(input) { var v = { r: 0, g: 0, b: 0, a: 255 }; if (Array.isArray(input)) { if (input.length >= 3) { v = { r: input[0], g: input[1], b: input[2], a: 255 }; if (input.length > 3) { v.a = n2b(input[3]); } } } else { v = clone$1(input, { r: 0, g: 0, b: 0, a: 1 }); v.a = n2b(v.a); } return v; } function functionParse(str) { if (str.charAt(0) === "r") { return rgbParse(str); } return hueParse(str); } class Color { constructor(input) { if (input instanceof Color) { return input; } const type = typeof input; let v; if (type === "object") { v = fromObject(input); } else if (type === "string") { v = hexParse(input) || nameParse(input) || functionParse(input); } this._rgb = v; this._valid = !!v; } get valid() { return this._valid; } get rgb() { var v = clone$1(this._rgb); if (v) { v.a = b2n(v.a); } return v; } set rgb(obj) { this._rgb = fromObject(obj); } rgbString() { return this._valid ? rgbString(this._rgb) : void 0; } hexString() { return this._valid ? hexString(this._rgb) : void 0; } hslString() { return this._valid ? hslString(this._rgb) : void 0; } mix(color2, weight) { if (color2) { const c1 = this.rgb; const c2 = color2.rgb; let w2; const p = weight === w2 ? 0.5 : weight; const w3 = 2 * p - 1; const a3 = c1.a - c2.a; const w1 = ((w3 * a3 === -1 ? w3 : (w3 + a3) / (1 + w3 * a3)) + 1) / 2; w2 = 1 - w1; c1.r = 255 & w1 * c1.r + w2 * c2.r + 0.5; c1.g = 255 & w1 * c1.g + w2 * c2.g + 0.5; c1.b = 255 & w1 * c1.b + w2 * c2.b + 0.5; c1.a = p * c1.a + (1 - p) * c2.a; this.rgb = c1; } return this; } interpolate(color2, t2) { if (color2) { this._rgb = interpolate$1(this._rgb, color2._rgb, t2); } return this; } clone() { return new Color(this.rgb); } alpha(a3) { this._rgb.a = n2b(a3); return this; } clearer(ratio) { const rgb = this._rgb; rgb.a *= 1 - ratio; return this; } greyscale() { const rgb = this._rgb; const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); rgb.r = rgb.g = rgb.b = val; return this; } opaquer(ratio) { const rgb = this._rgb; rgb.a *= 1 + ratio; return this; } negate() { const v = this._rgb; v.r = 255 - v.r; v.g = 255 - v.g; v.b = 255 - v.b; return this; } lighten(ratio) { modHSL(this._rgb, 2, ratio); return this; } darken(ratio) { modHSL(this._rgb, 2, -ratio); return this; } saturate(ratio) { modHSL(this._rgb, 1, ratio); return this; } desaturate(ratio) { modHSL(this._rgb, 1, -ratio); return this; } rotate(deg) { rotate(this._rgb, deg); return this; } } /*! * Chart.js v4.4.7 * https://www.chartjs.org * (c) 2024 Chart.js Contributors * Released under the MIT License */ function noop() { } const uid = /* @__PURE__ */ (() => { let id = 0; return () => id++; })(); function isNullOrUndef(value) { return value === null || value === void 0; } function isArray(value) { if (Array.isArray && Array.isArray(value)) { return true; } const type = Object.prototype.toString.call(value); if (type.slice(0, 7) === "[object" && type.slice(-6) === "Array]") { return true; } return false; } function isObject(value) { return value !== null && Object.prototype.toString.call(value) === "[object Object]"; } function isNumberFinite(value) { return (typeof value === "number" || value instanceof Number) && isFinite(+value); } function finiteOrDefault(value, defaultValue) { return isNumberFinite(value) ? value : defaultValue; } function valueOrDefault(value, defaultValue) { return typeof value === "undefined" ? defaultValue : value; } const toDimension = (value, dimension) => typeof value === "string" && value.endsWith("%") ? parseFloat(value) / 100 * dimension : +value; function callback(fn, args, thisArg) { if (fn && typeof fn.call === "function") { return fn.apply(thisArg, args); } } function each(loopable, fn, thisArg, reverse) { let i2, len, keys; if (isArray(loopable)) { len = loopable.length; { for (i2 = 0; i2 < len; i2++) { fn.call(thisArg, loopable[i2], i2); } } } else if (isObject(loopable)) { keys = Object.keys(loopable); len = keys.length; for (i2 = 0; i2 < len; i2++) { fn.call(thisArg, loopable[keys[i2]], keys[i2]); } } } function _elementsEqual(a0, a1) { let i2, ilen, v0, v1; if (!a0 || !a1 || a0.length !== a1.length) { return false; } for (i2 = 0, ilen = a0.length; i2 < ilen; ++i2) { v0 = a0[i2]; v1 = a1[i2]; if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { return false; } } return true; } function clone(source) { if (isArray(source)) { return source.map(clone); } if (isObject(source)) { const target = /* @__PURE__ */ Object.create(null); const keys = Object.keys(source); const klen = keys.length; let k2 = 0; for (; k2 < klen; ++k2) { target[keys[k2]] = clone(source[keys[k2]]); } return target; } return source; } function isValidKey(key) { return [ "__proto__", "prototype", "constructor" ].indexOf(key) === -1; } function _merger(key, target, source, options) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { merge(tval, sval, options); } else { target[key] = clone(sval); } } function merge(target, source, options) { const sources = isArray(source) ? source : [ source ]; const ilen = sources.length; if (!isObject(target)) { return target; } options = options || {}; const merger = options.merger || _merger; let current; for (let i2 = 0; i2 < ilen; ++i2) { current = sources[i2]; if (!isObject(current)) { continue; } const keys = Object.keys(current); for (let k2 = 0, klen = keys.length; k2 < klen; ++k2) { merger(keys[k2], target, current, options); } } return target; } function mergeIf(target, source) { return merge(target, source, { merger: _mergerIf }); } function _mergerIf(key, target, source) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { mergeIf(tval, sval); } else if (!Object.prototype.hasOwnProperty.call(target, key)) { target[key] = clone(sval); } } const keyResolvers = { // Chart.helpers.core resolveObjectKey should resolve empty key to root object "": (v) => v, // default resolvers x: (o) => o.x, y: (o) => o.y }; function _splitKey(key) { const parts = key.split("."); const keys = []; let tmp = ""; for (const part of parts) { tmp += part; if (tmp.endsWith("\\")) { tmp = tmp.slice(0, -1) + "."; } else { keys.push(tmp); tmp = ""; } } return keys; } function _getKeyResolver(key) { const keys = _splitKey(key); return (obj) => { for (const k2 of keys) { if (k2 === "") { break; } obj = obj && obj[k2]; } return obj; }; } function resolveObjectKey(obj, key) { const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key)); return resolver(obj); } function _capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } const defined = (value) => typeof value !== "undefined"; const isFunction = (value) => typeof value === "function"; const setsEqual = (a3, b2) => { if (a3.size !== b2.size) { return false; } for (const item of a3) { if (!b2.has(item)) { return false; } } return true; }; function _isClickEvent(e2) { return e2.type === "mouseup" || e2.type === "click" || e2.type === "contextmenu"; } const PI = Math.PI; const TAU = 2 * PI; const PITAU = TAU + PI; const INFINITY = Number.POSITIVE_INFINITY; const RAD_PER_DEG = PI / 180; const HALF_PI = PI / 2; const QUARTER_PI = PI / 4; const TWO_THIRDS_PI = PI * 2 / 3; const log10 = Math.log10; const sign = Math.sign; function almostEquals(x2, y3, epsilon) { return Math.abs(x2 - y3) < epsilon; } function niceNum(range) { const roundedRange = Math.round(range); range = almostEquals(range, roundedRange, range / 1e3) ? roundedRange : range; const niceRange = Math.pow(10, Math.floor(log10(range))); const fraction = range / niceRange; const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; return niceFraction * niceRange; } function _factorize(value) { const result = []; const sqrt = Math.sqrt(value); let i2; for (i2 = 1; i2 < sqrt; i2++) { if (value % i2 === 0) { result.push(i2); result.push(value / i2); } } if (sqrt === (sqrt | 0)) { result.push(sqrt); } result.sort((a3, b2) => a3 - b2).pop(); return result; } function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function almostWhole(x2, epsilon) { const rounded = Math.round(x2); return rounded - epsilon <= x2 && rounded + epsilon >= x2; } function _setMinAndMaxByKey(array, target, property) { let i2, ilen, value; for (i2 = 0, ilen = array.length; i2 < ilen; i2++) { value = array[i2][property]; if (!isNaN(value)) { target.min = Math.min(target.min, value); target.max = Math.max(target.max, value); } } } function toRadians(degrees) { return degrees * (PI / 180); } function toDegrees(radians) { return radians * (180 / PI); } function _decimalPlaces(x2) { if (!isNumberFinite(x2)) { return; } let e2 = 1; let p = 0; while (Math.round(x2 * e2) / e2 !== x2) { e2 *= 10; p++; } return p; } function getAngleFromPoint(centrePoint, anglePoint) { const distanceFromXCenter = anglePoint.x - centrePoint.x; const distanceFromYCenter = anglePoint.y - centrePoint.y; const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); if (angle < -0.5 * PI) { angle += TAU; } return { angle, distance: radialDistanceFromCenter }; } function distanceBetweenPoints(pt1, pt2) { return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); } function _angleDiff(a3, b2) { return (a3 - b2 + PITAU) % TAU - PI; } function _normalizeAngle(a3) { return (a3 % TAU + TAU) % TAU; } function _angleBetween(angle, start, end, sameAngleIsFullCircle) { const a3 = _normalizeAngle(angle); const s3 = _normalizeAngle(start); const e2 = _normalizeAngle(end); const angleToStart = _normalizeAngle(s3 - a3); const angleToEnd = _normalizeAngle(e2 - a3); const startToAngle = _normalizeAngle(a3 - s3); const endToAngle = _normalizeAngle(a3 - e2); return a3 === s3 || a3 === e2 || sameAngleIsFullCircle && s3 === e2 || angleToStart > angleToEnd && startToAngle < endToAngle; } function _limitValue(value, min, max) { return Math.max(min, Math.min(max, value)); } function _int16Range(value) { return _limitValue(value, -32768, 32767); } function _isBetween(value, start, end, epsilon = 1e-6) { return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; } function _lookup(table, value, cmp) { cmp = cmp || ((index2) => table[index2] < value); let hi = table.length - 1; let lo = 0; let mid; while (hi - lo > 1) { mid = lo + hi >> 1; if (cmp(mid)) { lo = mid; } else { hi = mid; } } return { lo, hi }; } const _lookupByKey = (table, key, value, last) => _lookup(table, value, last ? (index2) => { const ti = table[index2][key]; return ti < value || ti === value && table[index2 + 1][key] === value; } : (index2) => table[index2][key] < value); const _rlookupByKey = (table, key, value) => _lookup(table, value, (index2) => table[index2][key] >= value); function _filterBetween(values, min, max) { let start = 0; let end = values.length; while (start < end && values[start] < min) { start++; } while (end > start && values[end - 1] > max) { end--; } return start > 0 || end < values.length ? values.slice(start, end) : values; } const arrayEvents = [ "push", "pop", "shift", "splice", "unshift" ]; function listenArrayEvents(array, listener) { if (array._chartjs) { array._chartjs.listeners.push(listener); return; } Object.defineProperty(array, "_chartjs", { configurable: true, enumerable: false, value: { listeners: [ listener ] } }); arrayEvents.forEach((key) => { const method = "_onData" + _capitalize(key); const base = array[key]; Object.defineProperty(array, key, { configurable: true, enumerable: false, value(...args) { const res = base.apply(this, args); array._chartjs.listeners.forEach((object) => { if (typeof object[method] === "function") { object[method](...args); } }); return res; } }); }); } function unlistenArrayEvents(array, listener) { const stub = array._chartjs; if (!stub) { return; } const listeners = stub.listeners; const index2 = listeners.indexOf(listener); if (index2 !== -1) { listeners.splice(index2, 1); } if (listeners.length > 0) { return; } arrayEvents.forEach((key) => { delete array[key]; }); delete array._chartjs; } function _arrayUnique(items) { const set2 = new Set(items); if (set2.size === items.length) { return items; } return Array.from(set2); } const requestAnimFrame = function() { if (typeof window === "undefined") { return function(callback2) { return callback2(); }; } return window.requestAnimationFrame; }(); function throttled(fn, thisArg) { let argsToUse = []; let ticking = false; return function(...args) { argsToUse = args; if (!ticking) { ticking = true; requestAnimFrame.call(window, () => { ticking = false; fn.apply(thisArg, argsToUse); }); } }; } function debounce(fn, delay) { let timeout; return function(...args) { if (delay) { clearTimeout(timeout); timeout = setTimeout(fn, delay, args); } else { fn.apply(this, args); } return delay; }; } const _toLeftRightCenter = (align) => align === "start" ? "left" : align === "end" ? "right" : "center"; const _alignStartEnd = (align, start, end) => align === "start" ? start : align === "end" ? end : (start + end) / 2; function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { const pointCount = points.length; let start = 0; let count = pointCount; if (meta._sorted) { const { iScale, _parsed } = meta; const axis = iScale.axis; const { min, max, minDefined, maxDefined } = iScale.getUserBounds(); if (minDefined) { start = _limitValue(Math.min( // @ts-expect-error Need to type _parsed _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo ), 0, pointCount - 1); } if (maxDefined) { count = _limitValue(Math.max( // @ts-expect-error Need to type _parsed _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1 ), start, pointCount) - start; } else { count = pointCount - start; } } return { start, count }; } function _scaleRangesChanged(meta) { const { xScale, yScale, _scaleRanges } = meta; const newRanges = { xmin: xScale.min, xmax: xScale.max, ymin: yScale.min, ymax: yScale.max }; if (!_scaleRanges) { meta._scaleRanges = newRanges; return true; } const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max; Object.assign(_scaleRanges, newRanges); return changed; } const atEdge = (t2) => t2 === 0 || t2 === 1; const elasticIn = (t2, s3, p) => -(Math.pow(2, 10 * (t2 -= 1)) * Math.sin((t2 - s3) * TAU / p)); const elasticOut = (t2, s3, p) => Math.pow(2, -10 * t2) * Math.sin((t2 - s3) * TAU / p) + 1; const effects = { linear: (t2) => t2, easeInQuad: (t2) => t2 * t2, easeOutQuad: (t2) => -t2 * (t2 - 2), easeInOutQuad: (t2) => (t2 /= 0.5) < 1 ? 0.5 * t2 * t2 : -0.5 * (--t2 * (t2 - 2) - 1), easeInCubic: (t2) => t2 * t2 * t2, easeOutCubic: (t2) => (t2 -= 1) * t2 * t2 + 1, easeInOutCubic: (t2) => (t2 /= 0.5) < 1 ? 0.5 * t2 * t2 * t2 : 0.5 * ((t2 -= 2) * t2 * t2 + 2), easeInQuart: (t2) => t2 * t2 * t2 * t2, easeOutQuart: (t2) => -((t2 -= 1) * t2 * t2 * t2 - 1), easeInOutQuart: (t2) => (t2 /= 0.5) < 1 ? 0.5 * t2 * t2 * t2 * t2 : -0.5 * ((t2 -= 2) * t2 * t2 * t2 - 2), easeInQuint: (t2) => t2 * t2 * t2 * t2 * t2, easeOutQuint: (t2) => (t2 -= 1) * t2 * t2 * t2 * t2 + 1, easeInOutQuint: (t2) => (t2 /= 0.5) < 1 ? 0.5 * t2 * t2 * t2 * t2 * t2 : 0.5 * ((t2 -= 2) * t2 * t2 * t2 * t2 + 2), easeInSine: (t2) => -Math.cos(t2 * HALF_PI) + 1, easeOutSine: (t2) => Math.sin(t2 * HALF_PI), easeInOutSine: (t2) => -0.5 * (Math.cos(PI * t2) - 1), easeInExpo: (t2) => t2 === 0 ? 0 : Math.pow(2, 10 * (t2 - 1)), easeOutExpo: (t2) => t2 === 1 ? 1 : -Math.pow(2, -10 * t2) + 1, easeInOutExpo: (t2) => atEdge(t2) ? t2 : t2 < 0.5 ? 0.5 * Math.pow(2, 10 * (t2 * 2 - 1)) : 0.5 * (-Math.pow(2, -10 * (t2 * 2 - 1)) + 2), easeInCirc: (t2) => t2 >= 1 ? t2 : -(Math.sqrt(1 - t2 * t2) - 1), easeOutCirc: (t2) => Math.sqrt(1 - (t2 -= 1) * t2), easeInOutCirc: (t2) => (t2 /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t2 * t2) - 1) : 0.5 * (Math.sqrt(1 - (t2 -= 2) * t2) + 1), easeInElastic: (t2) => atEdge(t2) ? t2 : elasticIn(t2, 0.075, 0.3), easeOutElastic: (t2) => atEdge(t2) ? t2 : elasticOut(t2, 0.075, 0.3), easeInOutElastic(t2) { const s3 = 0.1125; const p = 0.45; return atEdge(t2) ? t2 : t2 < 0.5 ? 0.5 * elasticIn(t2 * 2, s3, p) : 0.5 + 0.5 * elasticOut(t2 * 2 - 1, s3, p); }, easeInBack(t2) { const s3 = 1.70158; return t2 * t2 * ((s3 + 1) * t2 - s3); }, easeOutBack(t2) { const s3 = 1.70158; return (t2 -= 1) * t2 * ((s3 + 1) * t2 + s3) + 1; }, easeInOutBack(t2) { let s3 = 1.70158; if ((t2 /= 0.5) < 1) { return 0.5 * (t2 * t2 * (((s3 *= 1.525) + 1) * t2 - s3)); } return 0.5 * ((t2 -= 2) * t2 * (((s3 *= 1.525) + 1) * t2 + s3) + 2); }, easeInBounce: (t2) => 1 - effects.easeOutBounce(1 - t2), easeOutBounce(t2) { const m3 = 7.5625; const d3 = 2.75; if (t2 < 1 / d3) { return m3 * t2 * t2; } if (t2 < 2 / d3) { return m3 * (t2 -= 1.5 / d3) * t2 + 0.75; } if (t2 < 2.5 / d3) { return m3 * (t2 -= 2.25 / d3) * t2 + 0.9375; } return m3 * (t2 -= 2.625 / d3) * t2 + 0.984375; }, easeInOutBounce: (t2) => t2 < 0.5 ? effects.easeInBounce(t2 * 2) * 0.5 : effects.easeOutBounce(t2 * 2 - 1) * 0.5 + 0.5 }; function isPatternOrGradient(value) { if (value && typeof value === "object") { const type = value.toString(); return type === "[object CanvasPattern]" || type === "[object CanvasGradient]"; } return false; } function color(value) { return isPatternOrGradient(value) ? value : new Color(value); } function getHoverColor(value) { return isPatternOrGradient(value) ? value : new Color(value).saturate(0.5).darken(0.1).hexString(); } const numbers = [ "x", "y", "borderWidth", "radius", "tension" ]; const colors = [ "color", "borderColor", "backgroundColor" ]; function applyAnimationsDefaults(defaults2) { defaults2.set("animation", { delay: void 0, duration: 1e3, easing: "easeOutQuart", fn: void 0, from: void 0, loop: void 0, to: void 0, type: void 0 }); defaults2.describe("animation", { _fallback: false, _indexable: false, _scriptable: (name) => name !== "onProgress" && name !== "onComplete" && name !== "fn" }); defaults2.set("animations", { colors: { type: "color", properties: colors }, numbers: { type: "number", properties: numbers } }); defaults2.describe("animations", { _fallback: "animation" }); defaults2.set("transitions", { active: { animation: { duration: 400 } }, resize: { animation: { duration: 0 } }, show: { animations: { colors: { from: "transparent" }, visible: { type: "boolean", duration: 0 } } }, hide: { animations: { colors: { to: "transparent" }, visible: { type: "boolean", easing: "linear", fn: (v) => v | 0 } } } }); } function applyLayoutsDefaults(defaults2) { defaults2.set("layout", { autoPadding: true, padding: { top: 0, right: 0, bottom: 0, left: 0 } }); } const intlCache = /* @__PURE__ */ new Map(); function getNumberFormat(locale2, options) { options = options || {}; const cacheKey = locale2 + JSON.stringify(options); let formatter = intlCache.get(cacheKey); if (!formatter) { formatter = new Intl.NumberFormat(locale2, options); intlCache.set(cacheKey, formatter); } return formatter; } function formatNumber(num, locale2, options) { return getNumberFormat(locale2, options).format(num); } const formatters$2 = { values(value) { return isArray(value) ? value : "" + value; }, numeric(tickValue, index2, ticks) { if (tickValue === 0) { return "0"; } const locale2 = this.chart.options.locale; let notation; let delta = tickValue; if (ticks.length > 1) { const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); if (maxTick < 1e-4 || maxTick > 1e15) { notation = "scientific"; } delta = calculateDelta(tickValue, ticks); } const logDelta = log10(Math.abs(delta)); const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); const options = { notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal }; Object.assign(options, this.options.ticks.format); return formatNumber(tickValue, locale2, options); }, logarithmic(tickValue, index2, ticks) { if (tickValue === 0) { return "0"; } const remain = ticks[index2].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue))); if ([ 1, 2, 3, 5, 10, 15 ].includes(remain) || index2 > 0.8 * ticks.length) { return formatters$2.numeric.call(this, tickValue, index2, ticks); } return ""; } }; function calculateDelta(tickValue, ticks) { let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { delta = tickValue - Math.floor(tickValue); } return delta; } var Ticks = { formatters: formatters$2 }; function applyScaleDefaults(defaults2) { defaults2.set("scale", { display: true, offset: false, reverse: false, beginAtZero: false, bounds: "ticks", clip: true, grace: 0, grid: { display: true, lineWidth: 1, drawOnChartArea: true, drawTicks: true, tickLength: 8, tickWidth: (_ctx, options) => options.lineWidth, tickColor: (_ctx, options) => options.color, offset: false }, border: { display: true, dash: [], dashOffset: 0, width: 1 }, title: { display: false, text: "", padding: { top: 4, bottom: 4 } }, ticks: { minRotation: 0, maxRotation: 50, mirror: false, textStrokeWidth: 0, textStrokeColor: "", padding: 3, display: true, autoSkip: true, autoSkipPadding: 3, labelOffset: 0, callback: Ticks.formatters.values, minor: {}, major: {}, align: "center", crossAlign: "near", showLabelBackdrop: false, backdropColor: "rgba(255, 255, 255, 0.75)", backdropPadding: 2 } }); defaults2.route("scale.ticks", "color", "", "color"); defaults2.route("scale.grid", "color", "", "borderColor"); defaults2.route("scale.border", "color", "", "borderColor"); defaults2.route("scale.title", "color", "", "color"); defaults2.describe("scale", { _fallback: false, _scriptable: (name) => !name.startsWith("before") && !name.startsWith("after") && name !== "callback" && name !== "parser", _indexable: (name) => name !== "borderDash" && name !== "tickBorderDash" && name !== "dash" }); defaults2.describe("scales", { _fallback: "scale" }); defaults2.describe("scale.ticks", { _scriptable: (name) => name !== "backdropPadding" && name !== "callback", _indexable: (name) => name !== "backdropPadding" }); } const overrides = /* @__PURE__ */ Object.create(null); const descriptors = /* @__PURE__ */ Object.create(null); function getScope$1(node, key) { if (!key) { return node; } const keys = key.split("."); for (let i2 = 0, n = keys.length; i2 < n; ++i2) { const k2 = keys[i2]; node = node[k2] || (node[k2] = /* @__PURE__ */ Object.create(null)); } return node; } function set(root, scope, values) { if (typeof scope === "string") { return merge(getScope$1(root, scope), values); } return merge(getScope$1(root, ""), scope); } class Defaults { constructor(_descriptors2, _appliers) { this.animation = void 0; this.backgroundColor = "rgba(0,0,0,0.1)"; this.borderColor = "rgba(0,0,0,0.1)"; this.color = "#666"; this.datasets = {}; this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); this.elements = {}; this.events = [ "mousemove", "mouseout", "click", "touchstart", "touchmove" ]; this.font = { family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", size: 12, style: "normal", lineHeight: 1.2, weight: null }; this.hover = {}; this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); this.hoverColor = (ctx, options) => getHoverColor(options.color); this.indexAxis = "x"; this.interaction = { mode: "nearest", intersect: true, includeInvisible: false }; this.maintainAspectRatio = true; this.onHover = null; this.onClick = null; this.parsing = true; this.plugins = {}; this.responsive = true; this.scale = void 0; this.scales = {}; this.showLine = true; this.drawActiveElementsOnTop = true; this.describe(_descriptors2); this.apply(_appliers); } set(scope, values) { return set(this, scope, values); } get(scope) { return getScope$1(this, scope); } describe(scope, values) { return set(descriptors, scope, values); } override(scope, values) { return set(overrides, scope, values); } route(scope, name, targetScope, targetName) { const scopeObject = getScope$1(this, scope); const targetScopeObject = getScope$1(this, targetScope); const privateName = "_" + name; Object.defineProperties(scopeObject, { [privateName]: { value: scopeObject[name], writable: true }, [name]: { enumerable: true, get() { const local = this[privateName]; const target = targetScopeObject[targetName]; if (isObject(local)) { return Object.assign({}, target, local); } return valueOrDefault(local, target); }, set(value) { this[privateName] = value; } } }); } apply(appliers) { appliers.forEach((apply) => apply(this)); } } var defaults = /* @__PURE__ */ new Defaults({ _scriptable: (name) => !name.startsWith("on"), _indexable: (name) => name !== "events", hover: { _fallback: "interaction" }, interaction: { _scriptable: false, _indexable: false } }, [ applyAnimationsDefaults, applyLayoutsDefaults, applyScaleDefaults ]); function toFontString(font) { if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { return null; } return (font.style ? font.style + " " : "") + (font.weight ? font.weight + " " : "") + font.size + "px " + font.family; } function _measureText(ctx, data, gc, longest, string) { let textWidth = data[string]; if (!textWidth) { textWidth = data[string] = ctx.measureText(string).width; gc.push(string); } if (textWidth > longest) { longest = textWidth; } return longest; } function _alignPixel(chart, pixel, width) { const devicePixelRatio = chart.currentDevicePixelRatio; const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; } function clearCanvas(canvas, ctx) { if (!ctx && !canvas) { return; } ctx = ctx || canvas.getContext("2d"); ctx.save(); ctx.resetTransform(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.restore(); } function drawPoint(ctx, options, x2, y3) { drawPointLegend(ctx, options, x2, y3); } function drawPointLegend(ctx, options, x2, y3, w2) { let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW; const style = options.pointStyle; const rotation = options.rotation; const radius = options.radius; let rad = (rotation || 0) * RAD_PER_DEG; if (style && typeof style === "object") { type = style.toString(); if (type === "[object HTMLImageElement]" || type === "[object HTMLCanvasElement]") { ctx.save(); ctx.translate(x2, y3); ctx.rotate(rad); ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); ctx.restore(); return; } } if (isNaN(radius) || radius <= 0) { return; } ctx.beginPath(); switch (style) { // Default includes circle default: { ctx.arc(x2, y3, radius, 0, TAU); } ctx.closePath(); break; case "triangle": width = radius; ctx.moveTo(x2 + Math.sin(rad) * width, y3 - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x2 + Math.sin(rad) * width, y3 - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x2 + Math.sin(rad) * width, y3 - Math.cos(rad) * radius); ctx.closePath(); break; case "rectRounded": cornerRadius = radius * 0.516; size = radius - cornerRadius; xOffset = Math.cos(rad + QUARTER_PI) * size; xOffsetW = Math.cos(rad + QUARTER_PI) * size; yOffset = Math.sin(rad + QUARTER_PI) * size; yOffsetW = Math.sin(rad + QUARTER_PI) * size; ctx.arc(x2 - xOffsetW, y3 - yOffset, cornerRadius, rad - PI, rad - HALF_PI); ctx.arc(x2 + yOffsetW, y3 - xOffset, cornerRadius, rad - HALF_PI, rad); ctx.arc(x2 + xOffsetW, y3 + yOffset, cornerRadius, rad, rad + HALF_PI); ctx.arc(x2 - yOffsetW, y3 + xOffset, cornerRadius, rad + HALF_PI, rad + PI); ctx.closePath(); break; case "rect": if (!rotation) { size = Math.SQRT1_2 * radius; width = size; ctx.rect(x2 - width, y3 - size, 2 * width, 2 * size); break; } rad += QUARTER_PI; /* falls through */ case "rectRot": xOffsetW = Math.cos(rad) * radius; xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * radius; ctx.moveTo(x2 - xOffsetW, y3 - yOffset); ctx.lineTo(x2 + yOffsetW, y3 - xOffset); ctx.lineTo(x2 + xOffsetW, y3 + yOffset); ctx.lineTo(x2 - yOffsetW, y3 + xOffset); ctx.closePath(); break; case "crossRot": rad += QUARTER_PI; /* falls through */ case "cross": xOffsetW = Math.cos(rad) * radius; xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * radius; ctx.moveTo(x2 - xOffsetW, y3 - yOffset); ctx.lineTo(x2 + xOffsetW, y3 + yOffset); ctx.moveTo(x2 + yOffsetW, y3 - xOffset); ctx.lineTo(x2 - yOffsetW, y3 + xOffset); break; case "star": xOffsetW = Math.cos(rad) * radius; xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * radius; ctx.moveTo(x2 - xOffsetW, y3 - yOffset); ctx.lineTo(x2 + xOffsetW, y3 + yOffset); ctx.moveTo(x2 + yOffsetW, y3 - xOffset); ctx.lineTo(x2 - yOffsetW, y3 + xOffset); rad += QUARTER_PI; xOffsetW = Math.cos(rad) * radius; xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * radius; ctx.moveTo(x2 - xOffsetW, y3 - yOffset); ctx.lineTo(x2 + xOffsetW, y3 + yOffset); ctx.moveTo(x2 + yOffsetW, y3 - xOffset); ctx.lineTo(x2 - yOffsetW, y3 + xOffset); break; case "line": xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; ctx.moveTo(x2 - xOffset, y3 - yOffset); ctx.lineTo(x2 + xOffset, y3 + yOffset); break; case "dash": ctx.moveTo(x2, y3); ctx.lineTo(x2 + Math.cos(rad) * radius, y3 + Math.sin(rad) * radius); break; case false: ctx.closePath(); break; } ctx.fill(); if (options.borderWidth > 0) { ctx.stroke(); } } function _isPointInArea(point, area, margin) { margin = margin || 0.5; return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin; } function clipArea(ctx, area) { ctx.save(); ctx.beginPath(); ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); ctx.clip(); } function unclipArea(ctx) { ctx.restore(); } function _steppedLineTo(ctx, previous, target, flip, mode) { if (!previous) { return ctx.lineTo(target.x, target.y); } if (mode === "middle") { const midpoint = (previous.x + target.x) / 2; ctx.lineTo(midpoint, previous.y); ctx.lineTo(midpoint, target.y); } else if (mode === "after" !== !!flip) { ctx.lineTo(previous.x, target.y); } else { ctx.lineTo(target.x, previous.y); } ctx.lineTo(target.x, target.y); } function _bezierCurveTo(ctx, previous, target, flip) { if (!previous) { return ctx.lineTo(target.x, target.y); } ctx.bezierCurveTo(flip ? previous.cp1x : previous.cp2x, flip ? previous.cp1y : previous.cp2y, flip ? target.cp2x : target.cp1x, flip ? target.cp2y : target.cp1y, target.x, target.y); } function setRenderOpts(ctx, opts) { if (opts.translation) { ctx.translate(opts.translation[0], opts.translation[1]); } if (!isNullOrUndef(opts.rotation)) { ctx.rotate(opts.rotation); } if (opts.color) { ctx.fillStyle = opts.color; } if (opts.textAlign) { ctx.textAlign = opts.textAlign; } if (opts.textBaseline) { ctx.textBaseline = opts.textBaseline; } } function decorateText(ctx, x2, y3, line, opts) { if (opts.strikethrough || opts.underline) { const metrics = ctx.measureText(line); const left = x2 - metrics.actualBoundingBoxLeft; const right = x2 + metrics.actualBoundingBoxRight; const top = y3 - metrics.actualBoundingBoxAscent; const bottom = y3 + metrics.actualBoundingBoxDescent; const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; ctx.strokeStyle = ctx.fillStyle; ctx.beginPath(); ctx.lineWidth = opts.decorationWidth || 2; ctx.moveTo(left, yDecoration); ctx.lineTo(right, yDecoration); ctx.stroke(); } } function drawBackdrop(ctx, opts) { const oldColor = ctx.fillStyle; ctx.fillStyle = opts.color; ctx.fillRect(opts.left, opts.top, opts.width, opts.height); ctx.fillStyle = oldColor; } function renderText(ctx, text, x2, y3, font, opts = {}) { const lines = isArray(text) ? text : [ text ]; const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ""; let i2, line; ctx.save(); ctx.font = font.string; setRenderOpts(ctx, opts); for (i2 = 0; i2 < lines.length; ++i2) { line = lines[i2]; if (opts.backdrop) { drawBackdrop(ctx, opts.backdrop); } if (stroke) { if (opts.strokeColor) { ctx.strokeStyle = opts.strokeColor; } if (!isNullOrUndef(opts.strokeWidth)) { ctx.lineWidth = opts.strokeWidth; } ctx.strokeText(line, x2, y3, opts.maxWidth); } ctx.fillText(line, x2, y3, opts.maxWidth); decorateText(ctx, x2, y3, line, opts); y3 += Number(font.lineHeight); } ctx.restore(); } function addRoundedRectPath(ctx, rect) { const { x: x2, y: y3, w: w2, h: h4, radius } = rect; ctx.arc(x2 + radius.topLeft, y3 + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true); ctx.lineTo(x2, y3 + h4 - radius.bottomLeft); ctx.arc(x2 + radius.bottomLeft, y3 + h4 - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); ctx.lineTo(x2 + w2 - radius.bottomRight, y3 + h4); ctx.arc(x2 + w2 - radius.bottomRight, y3 + h4 - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); ctx.lineTo(x2 + w2, y3 + radius.topRight); ctx.arc(x2 + w2 - radius.topRight, y3 + radius.topRight, radius.topRight, 0, -HALF_PI, true); ctx.lineTo(x2 + radius.topLeft, y3); } const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/; const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/; function toLineHeight(value, size) { const matches = ("" + value).match(LINE_HEIGHT); if (!matches || matches[1] === "normal") { return size * 1.2; } value = +matches[2]; switch (matches[3]) { case "px": return value; case "%": value /= 100; break; } return size * value; } const numberOrZero = (v) => +v || 0; function _readValueToProps(value, props) { const ret = {}; const objProps = isObject(props); const keys = objProps ? Object.keys(props) : props; const read = isObject(value) ? objProps ? (prop) => valueOrDefault(value[prop], value[props[prop]]) : (prop) => value[prop] : () => value; for (const prop of keys) { ret[prop] = numberOrZero(read(prop)); } return ret; } function toTRBL(value) { return _readValueToProps(value, { top: "y", right: "x", bottom: "y", left: "x" }); } function toTRBLCorners(value) { return _readValueToProps(value, [ "topLeft", "topRight", "bottomLeft", "bottomRight" ]); } function toPadding(value) { const obj = toTRBL(value); obj.width = obj.left + obj.right; obj.height = obj.top + obj.bottom; return obj; } function toFont(options, fallback) { options = options || {}; fallback = fallback || defaults.font; let size = valueOrDefault(options.size, fallback.size); if (typeof size === "string") { size = parseInt(size, 10); } let style = valueOrDefault(options.style, fallback.style); if (style && !("" + style).match(FONT_STYLE)) { console.warn('Invalid font style specified: "' + style + '"'); style = void 0; } const font = { family: valueOrDefault(options.family, fallback.family), lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), size, style,