1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875 |
- /*!
- * Chart.js v4.4.4
- * https://www.chartjs.org
- * (c) 2024 Chart.js Contributors
- * Released under the MIT License
- */
- 'use strict';
-
- var color$1 = require('@kurkle/color');
-
- /**
- * @namespace Chart.helpers
- */ /**
- * An empty function that can be used, for example, for optional callback.
- */ function noop() {
- /* noop */ }
- /**
- * Returns a unique id, sequentially generated from a global variable.
- */ const uid = (()=>{
- let id = 0;
- return ()=>id++;
- })();
- /**
- * Returns true if `value` is neither null nor undefined, else returns false.
- * @param value - The value to test.
- * @since 2.7.0
- */ function isNullOrUndef(value) {
- return value === null || typeof value === 'undefined';
- }
- /**
- * Returns true if `value` is an array (including typed arrays), else returns false.
- * @param value - The value to test.
- * @function
- */ 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;
- }
- /**
- * Returns true if `value` is an object (excluding null), else returns false.
- * @param value - The value to test.
- * @since 2.7.0
- */ function isObject(value) {
- return value !== null && Object.prototype.toString.call(value) === '[object Object]';
- }
- /**
- * Returns true if `value` is a finite number, else returns false
- * @param value - The value to test.
- */ function isNumberFinite(value) {
- return (typeof value === 'number' || value instanceof Number) && isFinite(+value);
- }
- /**
- * Returns `value` if finite, else returns `defaultValue`.
- * @param value - The value to return if defined.
- * @param defaultValue - The value to return if `value` is not finite.
- */ function finiteOrDefault(value, defaultValue) {
- return isNumberFinite(value) ? value : defaultValue;
- }
- /**
- * Returns `value` if defined, else returns `defaultValue`.
- * @param value - The value to return if defined.
- * @param defaultValue - The value to return if `value` is undefined.
- */ function valueOrDefault(value, defaultValue) {
- return typeof value === 'undefined' ? defaultValue : value;
- }
- const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;
- const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;
- /**
- * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
- * value returned by `fn`. If `fn` is not a function, this method returns undefined.
- * @param fn - The function to call.
- * @param args - The arguments with which `fn` should be called.
- * @param [thisArg] - The value of `this` provided for the call to `fn`.
- */ function callback(fn, args, thisArg) {
- if (fn && typeof fn.call === 'function') {
- return fn.apply(thisArg, args);
- }
- }
- function each(loopable, fn, thisArg, reverse) {
- let i, len, keys;
- if (isArray(loopable)) {
- len = loopable.length;
- if (reverse) {
- for(i = len - 1; i >= 0; i--){
- fn.call(thisArg, loopable[i], i);
- }
- } else {
- for(i = 0; i < len; i++){
- fn.call(thisArg, loopable[i], i);
- }
- }
- } else if (isObject(loopable)) {
- keys = Object.keys(loopable);
- len = keys.length;
- for(i = 0; i < len; i++){
- fn.call(thisArg, loopable[keys[i]], keys[i]);
- }
- }
- }
- /**
- * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
- * @param a0 - The array to compare
- * @param a1 - The array to compare
- * @private
- */ function _elementsEqual(a0, a1) {
- let i, ilen, v0, v1;
- if (!a0 || !a1 || a0.length !== a1.length) {
- return false;
- }
- for(i = 0, ilen = a0.length; i < ilen; ++i){
- v0 = a0[i];
- v1 = a1[i];
- if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
- return false;
- }
- }
- return true;
- }
- /**
- * Returns a deep copy of `source` without keeping references on objects and arrays.
- * @param source - The value to clone.
- */ function clone(source) {
- if (isArray(source)) {
- return source.map(clone);
- }
- if (isObject(source)) {
- const target = Object.create(null);
- const keys = Object.keys(source);
- const klen = keys.length;
- let k = 0;
- for(; k < klen; ++k){
- target[keys[k]] = clone(source[keys[k]]);
- }
- return target;
- }
- return source;
- }
- function isValidKey(key) {
- return [
- '__proto__',
- 'prototype',
- 'constructor'
- ].indexOf(key) === -1;
- }
- /**
- * The default merger when Chart.helpers.merge is called without merger option.
- * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
- * @private
- */ function _merger(key, target, source, options) {
- if (!isValidKey(key)) {
- return;
- }
- const tval = target[key];
- const sval = source[key];
- if (isObject(tval) && isObject(sval)) {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- 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 i = 0; i < ilen; ++i){
- current = sources[i];
- if (!isObject(current)) {
- continue;
- }
- const keys = Object.keys(current);
- for(let k = 0, klen = keys.length; k < klen; ++k){
- merger(keys[k], target, current, options);
- }
- }
- return target;
- }
- function mergeIf(target, source) {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- return merge(target, source, {
- merger: _mergerIf
- });
- }
- /**
- * Merges source[key] in target[key] only if target[key] is undefined.
- * @private
- */ 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);
- }
- }
- /**
- * @private
- */ function _deprecated(scope, value, previous, current) {
- if (value !== undefined) {
- console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead');
- }
- }
- // resolveObjectKey resolver cache
- 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
- };
- /**
- * @private
- */ 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 k of keys){
- if (k === '') {
- break;
- }
- obj = obj && obj[k];
- }
- return obj;
- };
- }
- function resolveObjectKey(obj, key) {
- const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
- return resolver(obj);
- }
- /**
- * @private
- */ function _capitalize(str) {
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
- const defined = (value)=>typeof value !== 'undefined';
- const isFunction = (value)=>typeof value === 'function';
- // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
- const setsEqual = (a, b)=>{
- if (a.size !== b.size) {
- return false;
- }
- for (const item of a){
- if (!b.has(item)) {
- return false;
- }
- }
- return true;
- };
- /**
- * @param e - The event
- * @private
- */ function _isClickEvent(e) {
- return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
- }
-
- /**
- * @alias Chart.helpers.math
- * @namespace
- */ 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(x, y, epsilon) {
- return Math.abs(x - y) < epsilon;
- }
- /**
- * Implementation of the nice number algorithm used in determining where axis labels will go
- */ function niceNum(range) {
- const roundedRange = Math.round(range);
- range = almostEquals(range, roundedRange, range / 1000) ? 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;
- }
- /**
- * Returns an array of factors sorted from 1 to sqrt(value)
- * @private
- */ function _factorize(value) {
- const result = [];
- const sqrt = Math.sqrt(value);
- let i;
- for(i = 1; i < sqrt; i++){
- if (value % i === 0) {
- result.push(i);
- result.push(value / i);
- }
- }
- if (sqrt === (sqrt | 0)) {
- result.push(sqrt);
- }
- result.sort((a, b)=>a - b).pop();
- return result;
- }
- function isNumber(n) {
- return !isNaN(parseFloat(n)) && isFinite(n);
- }
- function almostWhole(x, epsilon) {
- const rounded = Math.round(x);
- return rounded - epsilon <= x && rounded + epsilon >= x;
- }
- /**
- * @private
- */ function _setMinAndMaxByKey(array, target, property) {
- let i, ilen, value;
- for(i = 0, ilen = array.length; i < ilen; i++){
- value = array[i][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);
- }
- /**
- * Returns the number of decimal places
- * i.e. the number of digits after the decimal point, of the value of this Number.
- * @param x - A number.
- * @returns The number of decimal places.
- * @private
- */ function _decimalPlaces(x) {
- if (!isNumberFinite(x)) {
- return;
- }
- let e = 1;
- let p = 0;
- while(Math.round(x * e) / e !== x){
- e *= 10;
- p++;
- }
- return p;
- }
- // Gets the angle from vertical upright to the point about a centre.
- 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; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
- }
- 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));
- }
- /**
- * Shortest distance between angles, in either direction.
- * @private
- */ function _angleDiff(a, b) {
- return (a - b + PITAU) % TAU - PI;
- }
- /**
- * Normalize angle to be between 0 and 2*PI
- * @private
- */ function _normalizeAngle(a) {
- return (a % TAU + TAU) % TAU;
- }
- /**
- * @private
- */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
- const a = _normalizeAngle(angle);
- const s = _normalizeAngle(start);
- const e = _normalizeAngle(end);
- const angleToStart = _normalizeAngle(s - a);
- const angleToEnd = _normalizeAngle(e - a);
- const startToAngle = _normalizeAngle(a - s);
- const endToAngle = _normalizeAngle(a - e);
- return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;
- }
- /**
- * Limit `value` between `min` and `max`
- * @param value
- * @param min
- * @param max
- * @private
- */ function _limitValue(value, min, max) {
- return Math.max(min, Math.min(max, value));
- }
- /**
- * @param {number} value
- * @private
- */ function _int16Range(value) {
- return _limitValue(value, -32768, 32767);
- }
- /**
- * @param value
- * @param start
- * @param end
- * @param [epsilon]
- * @private
- */ 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 || ((index)=>table[index] < 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
- };
- }
- /**
- * Binary search
- * @param table - the table search. must be sorted!
- * @param key - property name for the value in each entry
- * @param value - value to find
- * @param last - lookup last index
- * @private
- */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{
- const ti = table[index][key];
- return ti < value || ti === value && table[index + 1][key] === value;
- } : (index)=>table[index][key] < value);
- /**
- * Reverse binary search
- * @param table - the table search. must be sorted!
- * @param key - property name for the value in each entry
- * @param value - value to find
- * @private
- */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);
- /**
- * Return subset of `values` between `min` and `max` inclusive.
- * Values are assumed to be in sorted order.
- * @param values - sorted array of values
- * @param min - min value
- * @param max - max 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 index = listeners.indexOf(listener);
- if (index !== -1) {
- listeners.splice(index, 1);
- }
- if (listeners.length > 0) {
- return;
- }
- arrayEvents.forEach((key)=>{
- delete array[key];
- });
- delete array._chartjs;
- }
- /**
- * @param items
- */ function _arrayUnique(items) {
- const set = new Set(items);
- if (set.size === items.length) {
- return items;
- }
- return Array.from(set);
- }
-
- function fontString(pixelSize, fontStyle, fontFamily) {
- return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
- }
- /**
- * Request animation polyfill
- */ const requestAnimFrame = function() {
- if (typeof window === 'undefined') {
- return function(callback) {
- return callback();
- };
- }
- return window.requestAnimationFrame;
- }();
- /**
- * Throttles calling `fn` once per animation frame
- * Latest arguments are used on the actual call
- */ function throttled(fn, thisArg) {
- let argsToUse = [];
- let ticking = false;
- return function(...args) {
- // Save the args for use later
- argsToUse = args;
- if (!ticking) {
- ticking = true;
- requestAnimFrame.call(window, ()=>{
- ticking = false;
- fn.apply(thisArg, argsToUse);
- });
- }
- };
- }
- /**
- * Debounces calling `fn` for `delay` ms
- */ 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;
- };
- }
- /**
- * Converts 'start' to 'left', 'end' to 'right' and others to 'center'
- * @private
- */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
- /**
- * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`
- * @private
- */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
- /**
- * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`
- * @private
- */ const _textX = (align, left, right, rtl)=>{
- const check = rtl ? 'left' : 'right';
- return align === check ? right : align === 'center' ? (left + right) / 2 : left;
- };
- /**
- * Return start and count of visible points.
- * @private
- */ 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
- };
- }
- /**
- * Checks if the scale ranges have changed.
- * @param {object} meta - dataset meta.
- * @returns {boolean}
- * @private
- */ 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 = (t)=>t === 0 || t === 1;
- const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
- const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
- /**
- * Easing functions adapted from Robert Penner's easing equations.
- * @namespace Chart.helpers.easing.effects
- * @see http://www.robertpenner.com/easing/
- */ const effects = {
- linear: (t)=>t,
- easeInQuad: (t)=>t * t,
- easeOutQuad: (t)=>-t * (t - 2),
- easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),
- easeInCubic: (t)=>t * t * t,
- easeOutCubic: (t)=>(t -= 1) * t * t + 1,
- easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),
- easeInQuart: (t)=>t * t * t * t,
- easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),
- easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),
- easeInQuint: (t)=>t * t * t * t * t,
- easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,
- easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),
- easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,
- easeOutSine: (t)=>Math.sin(t * HALF_PI),
- easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),
- easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
- easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,
- 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),
- easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),
- easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),
- easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
- easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
- easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
- easeInOutElastic (t) {
- const s = 0.1125;
- const p = 0.45;
- return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
- },
- easeInBack (t) {
- const s = 1.70158;
- return t * t * ((s + 1) * t - s);
- },
- easeOutBack (t) {
- const s = 1.70158;
- return (t -= 1) * t * ((s + 1) * t + s) + 1;
- },
- easeInOutBack (t) {
- let s = 1.70158;
- if ((t /= 0.5) < 1) {
- return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
- }
- return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
- },
- easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),
- easeOutBounce (t) {
- const m = 7.5625;
- const d = 2.75;
- if (t < 1 / d) {
- return m * t * t;
- }
- if (t < 2 / d) {
- return m * (t -= 1.5 / d) * t + 0.75;
- }
- if (t < 2.5 / d) {
- return m * (t -= 2.25 / d) * t + 0.9375;
- }
- return m * (t -= 2.625 / d) * t + 0.984375;
- },
- easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 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$1.Color(value);
- }
- function getHoverColor(value) {
- return isPatternOrGradient(value) ? value : new color$1.Color(value).saturate(0.5).darken(0.1).hexString();
- }
-
- const numbers = [
- 'x',
- 'y',
- 'borderWidth',
- 'radius',
- 'tension'
- ];
- const colors = [
- 'color',
- 'borderColor',
- 'backgroundColor'
- ];
- function applyAnimationsDefaults(defaults) {
- defaults.set('animation', {
- delay: undefined,
- duration: 1000,
- easing: 'easeOutQuart',
- fn: undefined,
- from: undefined,
- loop: undefined,
- to: undefined,
- type: undefined
- });
- defaults.describe('animation', {
- _fallback: false,
- _indexable: false,
- _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'
- });
- defaults.set('animations', {
- colors: {
- type: 'color',
- properties: colors
- },
- numbers: {
- type: 'number',
- properties: numbers
- }
- });
- defaults.describe('animations', {
- _fallback: 'animation'
- });
- defaults.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(defaults) {
- defaults.set('layout', {
- autoPadding: true,
- padding: {
- top: 0,
- right: 0,
- bottom: 0,
- left: 0
- }
- });
- }
-
- const intlCache = new Map();
- function getNumberFormat(locale, options) {
- options = options || {};
- const cacheKey = locale + JSON.stringify(options);
- let formatter = intlCache.get(cacheKey);
- if (!formatter) {
- formatter = new Intl.NumberFormat(locale, options);
- intlCache.set(cacheKey, formatter);
- }
- return formatter;
- }
- function formatNumber(num, locale, options) {
- return getNumberFormat(locale, options).format(num);
- }
-
- const formatters = {
- values (value) {
- return isArray(value) ? value : '' + value;
- },
- numeric (tickValue, index, ticks) {
- if (tickValue === 0) {
- return '0';
- }
- const locale = 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 > 1e+15) {
- 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, locale, options);
- },
- logarithmic (tickValue, index, ticks) {
- if (tickValue === 0) {
- return '0';
- }
- const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
- if ([
- 1,
- 2,
- 3,
- 5,
- 10,
- 15
- ].includes(remain) || index > 0.8 * ticks.length) {
- return formatters.numeric.call(this, tickValue, index, 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
- };
-
- function applyScaleDefaults(defaults) {
- defaults.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.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
- }
- });
- defaults.route('scale.ticks', 'color', '', 'color');
- defaults.route('scale.grid', 'color', '', 'borderColor');
- defaults.route('scale.border', 'color', '', 'borderColor');
- defaults.route('scale.title', 'color', '', 'color');
- defaults.describe('scale', {
- _fallback: false,
- _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
- _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'
- });
- defaults.describe('scales', {
- _fallback: 'scale'
- });
- defaults.describe('scale.ticks', {
- _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',
- _indexable: (name)=>name !== 'backdropPadding'
- });
- }
-
- const overrides = Object.create(null);
- const descriptors = Object.create(null);
- function getScope$1(node, key) {
- if (!key) {
- return node;
- }
- const keys = key.split('.');
- for(let i = 0, n = keys.length; i < n; ++i){
- const k = keys[i];
- node = node[k] || (node[k] = 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(_descriptors, _appliers){
- this.animation = undefined;
- 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 = undefined;
- this.scales = {};
- this.showLine = true;
- this.drawActiveElementsOnTop = true;
- this.describe(_descriptors);
- 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
- ]);
-
- /**
- * Converts the given font object into a CSS font string.
- * @param font - A font object.
- * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
- * @private
- */ 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;
- }
- /**
- * @private
- */ 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;
- }
- /**
- * @private
- */ // eslint-disable-next-line complexity
- function _longestText(ctx, font, arrayOfThings, cache) {
- cache = cache || {};
- let data = cache.data = cache.data || {};
- let gc = cache.garbageCollect = cache.garbageCollect || [];
- if (cache.font !== font) {
- data = cache.data = {};
- gc = cache.garbageCollect = [];
- cache.font = font;
- }
- ctx.save();
- ctx.font = font;
- let longest = 0;
- const ilen = arrayOfThings.length;
- let i, j, jlen, thing, nestedThing;
- for(i = 0; i < ilen; i++){
- thing = arrayOfThings[i];
- // Undefined strings and arrays should not be measured
- if (thing !== undefined && thing !== null && !isArray(thing)) {
- longest = _measureText(ctx, data, gc, longest, thing);
- } else if (isArray(thing)) {
- // if it is an array lets measure each element
- // to do maybe simplify this function a bit so we can do this more recursively?
- for(j = 0, jlen = thing.length; j < jlen; j++){
- nestedThing = thing[j];
- // Undefined strings and arrays should not be measured
- if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
- longest = _measureText(ctx, data, gc, longest, nestedThing);
- }
- }
- }
- }
- ctx.restore();
- const gcLen = gc.length / 2;
- if (gcLen > arrayOfThings.length) {
- for(i = 0; i < gcLen; i++){
- delete data[gc[i]];
- }
- gc.splice(0, gcLen);
- }
- return longest;
- }
- /**
- * Returns the aligned pixel value to avoid anti-aliasing blur
- * @param chart - The chart instance.
- * @param pixel - A pixel value.
- * @param width - The width of the element.
- * @returns The aligned pixel value.
- * @private
- */ 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;
- }
- /**
- * Clears the entire canvas.
- */ function clearCanvas(canvas, ctx) {
- if (!ctx && !canvas) {
- return;
- }
- ctx = ctx || canvas.getContext('2d');
- ctx.save();
- // canvas.width and canvas.height do not consider the canvas transform,
- // while clearRect does
- ctx.resetTransform();
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- ctx.restore();
- }
- function drawPoint(ctx, options, x, y) {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- drawPointLegend(ctx, options, x, y, null);
- }
- // eslint-disable-next-line complexity
- function drawPointLegend(ctx, options, x, y, w) {
- 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(x, y);
- 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:
- if (w) {
- ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);
- } else {
- ctx.arc(x, y, radius, 0, TAU);
- }
- ctx.closePath();
- break;
- case 'triangle':
- width = w ? w / 2 : radius;
- ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
- rad += TWO_THIRDS_PI;
- ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
- rad += TWO_THIRDS_PI;
- ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);
- ctx.closePath();
- break;
- case 'rectRounded':
- // NOTE: the rounded rect implementation changed to use `arc` instead of
- // `quadraticCurveTo` since it generates better results when rect is
- // almost a circle. 0.516 (instead of 0.5) produces results with visually
- // closer proportion to the previous impl and it is inscribed in the
- // circle with `radius`. For more details, see the following PRs:
- // https://github.com/chartjs/Chart.js/issues/5597
- // https://github.com/chartjs/Chart.js/issues/5858
- cornerRadius = radius * 0.516;
- size = radius - cornerRadius;
- xOffset = Math.cos(rad + QUARTER_PI) * size;
- xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
- yOffset = Math.sin(rad + QUARTER_PI) * size;
- yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);
- ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
- ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);
- ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);
- ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
- ctx.closePath();
- break;
- case 'rect':
- if (!rotation) {
- size = Math.SQRT1_2 * radius;
- width = w ? w / 2 : size;
- ctx.rect(x - width, y - size, 2 * width, 2 * size);
- break;
- }
- rad += QUARTER_PI;
- /* falls through */ case 'rectRot':
- xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
- xOffset = Math.cos(rad) * radius;
- yOffset = Math.sin(rad) * radius;
- yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
- ctx.moveTo(x - xOffsetW, y - yOffset);
- ctx.lineTo(x + yOffsetW, y - xOffset);
- ctx.lineTo(x + xOffsetW, y + yOffset);
- ctx.lineTo(x - yOffsetW, y + xOffset);
- ctx.closePath();
- break;
- case 'crossRot':
- rad += QUARTER_PI;
- /* falls through */ case 'cross':
- xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
- xOffset = Math.cos(rad) * radius;
- yOffset = Math.sin(rad) * radius;
- yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
- ctx.moveTo(x - xOffsetW, y - yOffset);
- ctx.lineTo(x + xOffsetW, y + yOffset);
- ctx.moveTo(x + yOffsetW, y - xOffset);
- ctx.lineTo(x - yOffsetW, y + xOffset);
- break;
- case 'star':
- xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
- xOffset = Math.cos(rad) * radius;
- yOffset = Math.sin(rad) * radius;
- yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
- ctx.moveTo(x - xOffsetW, y - yOffset);
- ctx.lineTo(x + xOffsetW, y + yOffset);
- ctx.moveTo(x + yOffsetW, y - xOffset);
- ctx.lineTo(x - yOffsetW, y + xOffset);
- rad += QUARTER_PI;
- xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);
- xOffset = Math.cos(rad) * radius;
- yOffset = Math.sin(rad) * radius;
- yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);
- ctx.moveTo(x - xOffsetW, y - yOffset);
- ctx.lineTo(x + xOffsetW, y + yOffset);
- ctx.moveTo(x + yOffsetW, y - xOffset);
- ctx.lineTo(x - yOffsetW, y + xOffset);
- break;
- case 'line':
- xOffset = w ? w / 2 : Math.cos(rad) * radius;
- yOffset = Math.sin(rad) * radius;
- ctx.moveTo(x - xOffset, y - yOffset);
- ctx.lineTo(x + xOffset, y + yOffset);
- break;
- case 'dash':
- ctx.moveTo(x, y);
- ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);
- break;
- case false:
- ctx.closePath();
- break;
- }
- ctx.fill();
- if (options.borderWidth > 0) {
- ctx.stroke();
- }
- }
- /**
- * Returns true if the point is inside the rectangle
- * @param point - The point to test
- * @param area - The rectangle
- * @param margin - allowed margin
- * @private
- */ function _isPointInArea(point, area, margin) {
- margin = margin || 0.5; // margin - default is to match rounded decimals
- 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();
- }
- /**
- * @private
- */ 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.0;
- 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);
- }
- /**
- * @private
- */ 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, x, y, line, opts) {
- if (opts.strikethrough || opts.underline) {
- /**
- * Now that IE11 support has been dropped, we can use more
- * of the TextMetrics object. The actual bounding boxes
- * are unflagged in Chrome, Firefox, Edge, and Safari so they
- * can be safely used.
- * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
- */ const metrics = ctx.measureText(line);
- const left = x - metrics.actualBoundingBoxLeft;
- const right = x + metrics.actualBoundingBoxRight;
- const top = y - metrics.actualBoundingBoxAscent;
- const bottom = y + 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;
- }
- /**
- * Render text onto the canvas
- */ function renderText(ctx, text, x, y, font, opts = {}) {
- const lines = isArray(text) ? text : [
- text
- ];
- const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
- let i, line;
- ctx.save();
- ctx.font = font.string;
- setRenderOpts(ctx, opts);
- for(i = 0; i < lines.length; ++i){
- line = lines[i];
- 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, x, y, opts.maxWidth);
- }
- ctx.fillText(line, x, y, opts.maxWidth);
- decorateText(ctx, x, y, line, opts);
- y += Number(font.lineHeight);
- }
- ctx.restore();
- }
- /**
- * Add a path of a rectangle with rounded corners to the current sub-path
- * @param ctx - Context
- * @param rect - Bounding rect
- */ function addRoundedRectPath(ctx, rect) {
- const { x , y , w , h , radius } = rect;
- // top left arc
- ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
- // line from top left to bottom left
- ctx.lineTo(x, y + h - radius.bottomLeft);
- // bottom left arc
- ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
- // line from bottom left to bottom right
- ctx.lineTo(x + w - radius.bottomRight, y + h);
- // bottom right arc
- ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
- // line from bottom right to top right
- ctx.lineTo(x + w, y + radius.topRight);
- // top right arc
- ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
- // line from top right to top left
- ctx.lineTo(x + radius.topLeft, y);
- }
-
- const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
- const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
- /**
- * @alias Chart.helpers.options
- * @namespace
- */ /**
- * Converts the given line height `value` in pixels for a specific font `size`.
- * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
- * @param size - The font size (in pixels) used to resolve relative `value`.
- * @returns The effective line height in pixels (size * 1.2 if value is invalid).
- * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
- * @since 2.7.0
- */ 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;
- }
- /**
- * Converts the given value into a TRBL object.
- * @param value - If a number, set the value to all TRBL component,
- * else, if an object, use defined properties and sets undefined ones to 0.
- * x / y are shorthands for same value for left/right and top/bottom.
- * @returns The padding values (top, right, bottom, left)
- * @since 3.0.0
- */ function toTRBL(value) {
- return _readValueToProps(value, {
- top: 'y',
- right: 'x',
- bottom: 'y',
- left: 'x'
- });
- }
- /**
- * Converts the given value into a TRBL corners object (similar with css border-radius).
- * @param value - If a number, set the value to all TRBL corner components,
- * else, if an object, use defined properties and sets undefined ones to 0.
- * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)
- * @since 3.0.0
- */ function toTRBLCorners(value) {
- return _readValueToProps(value, [
- 'topLeft',
- 'topRight',
- 'bottomLeft',
- 'bottomRight'
- ]);
- }
- /**
- * Converts the given value into a padding object with pre-computed width/height.
- * @param value - If a number, set the value to all TRBL component,
- * else, if an object, use defined properties and sets undefined ones to 0.
- * x / y are shorthands for same value for left/right and top/bottom.
- * @returns The padding values (top, right, bottom, left, width, height)
- * @since 2.7.0
- */ function toPadding(value) {
- const obj = toTRBL(value);
- obj.width = obj.left + obj.right;
- obj.height = obj.top + obj.bottom;
- return obj;
- }
- /**
- * Parses font options and returns the font object.
- * @param options - A object that contains font options to be parsed.
- * @param fallback - A object that contains fallback font options.
- * @return The font object.
- * @private
- */ 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 = undefined;
- }
- const font = {
- family: valueOrDefault(options.family, fallback.family),
- lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
- size,
- style,
- weight: valueOrDefault(options.weight, fallback.weight),
- string: ''
- };
- font.string = toFontString(font);
- return font;
- }
- /**
- * Evaluates the given `inputs` sequentially and returns the first defined value.
- * @param inputs - An array of values, falling back to the last value.
- * @param context - If defined and the current value is a function, the value
- * is called with `context` as first argument and the result becomes the new input.
- * @param index - If defined and the current value is an array, the value
- * at `index` become the new input.
- * @param info - object to return information about resolution in
- * @param info.cacheable - Will be set to `false` if option is not cacheable.
- * @since 2.7.0
- */ function resolve(inputs, context, index, info) {
- let cacheable = true;
- let i, ilen, value;
- for(i = 0, ilen = inputs.length; i < ilen; ++i){
- value = inputs[i];
- if (value === undefined) {
- continue;
- }
- if (context !== undefined && typeof value === 'function') {
- value = value(context);
- cacheable = false;
- }
- if (index !== undefined && isArray(value)) {
- value = value[index % value.length];
- cacheable = false;
- }
- if (value !== undefined) {
- if (info && !cacheable) {
- info.cacheable = false;
- }
- return value;
- }
- }
- }
- /**
- * @param minmax
- * @param grace
- * @param beginAtZero
- * @private
- */ function _addGrace(minmax, grace, beginAtZero) {
- const { min , max } = minmax;
- const change = toDimension(grace, (max - min) / 2);
- const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;
- return {
- min: keepZero(min, -Math.abs(change)),
- max: keepZero(max, change)
- };
- }
- function createContext(parentContext, context) {
- return Object.assign(Object.create(parentContext), context);
- }
-
- /**
- * Creates a Proxy for resolving raw values for options.
- * @param scopes - The option scopes to look for values, in resolution order
- * @param prefixes - The prefixes for values, in resolution order.
- * @param rootScopes - The root option scopes
- * @param fallback - Parent scopes fallback
- * @param getTarget - callback for getting the target for changed values
- * @returns Proxy
- * @private
- */ function _createResolver(scopes, prefixes = [
- ''
- ], rootScopes, fallback, getTarget = ()=>scopes[0]) {
- const finalRootScopes = rootScopes || scopes;
- if (typeof fallback === 'undefined') {
- fallback = _resolve('_fallback', scopes);
- }
- const cache = {
- [Symbol.toStringTag]: 'Object',
- _cacheable: true,
- _scopes: scopes,
- _rootScopes: finalRootScopes,
- _fallback: fallback,
- _getTarget: getTarget,
- override: (scope)=>_createResolver([
- scope,
- ...scopes
- ], prefixes, finalRootScopes, fallback)
- };
- return new Proxy(cache, {
- /**
- * A trap for the delete operator.
- */ deleteProperty (target, prop) {
- delete target[prop]; // remove from cache
- delete target._keys; // remove cached keys
- delete scopes[0][prop]; // remove from top level scope
- return true;
- },
- /**
- * A trap for getting property values.
- */ get (target, prop) {
- return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));
- },
- /**
- * A trap for Object.getOwnPropertyDescriptor.
- * Also used by Object.hasOwnProperty.
- */ getOwnPropertyDescriptor (target, prop) {
- return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
- },
- /**
- * A trap for Object.getPrototypeOf.
- */ getPrototypeOf () {
- return Reflect.getPrototypeOf(scopes[0]);
- },
- /**
- * A trap for the in operator.
- */ has (target, prop) {
- return getKeysFromAllScopes(target).includes(prop);
- },
- /**
- * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
- */ ownKeys (target) {
- return getKeysFromAllScopes(target);
- },
- /**
- * A trap for setting property values.
- */ set (target, prop, value) {
- const storage = target._storage || (target._storage = getTarget());
- target[prop] = storage[prop] = value; // set to top level scope + cache
- delete target._keys; // remove cached keys
- return true;
- }
- });
- }
- /**
- * Returns an Proxy for resolving option values with context.
- * @param proxy - The Proxy returned by `_createResolver`
- * @param context - Context object for scriptable/indexable options
- * @param subProxy - The proxy provided for scriptable options
- * @param descriptorDefaults - Defaults for descriptors
- * @private
- */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {
- const cache = {
- _cacheable: false,
- _proxy: proxy,
- _context: context,
- _subProxy: subProxy,
- _stack: new Set(),
- _descriptors: _descriptors(proxy, descriptorDefaults),
- setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),
- override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
- };
- return new Proxy(cache, {
- /**
- * A trap for the delete operator.
- */ deleteProperty (target, prop) {
- delete target[prop]; // remove from cache
- delete proxy[prop]; // remove from proxy
- return true;
- },
- /**
- * A trap for getting property values.
- */ get (target, prop, receiver) {
- return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));
- },
- /**
- * A trap for Object.getOwnPropertyDescriptor.
- * Also used by Object.hasOwnProperty.
- */ getOwnPropertyDescriptor (target, prop) {
- return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
- enumerable: true,
- configurable: true
- } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);
- },
- /**
- * A trap for Object.getPrototypeOf.
- */ getPrototypeOf () {
- return Reflect.getPrototypeOf(proxy);
- },
- /**
- * A trap for the in operator.
- */ has (target, prop) {
- return Reflect.has(proxy, prop);
- },
- /**
- * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
- */ ownKeys () {
- return Reflect.ownKeys(proxy);
- },
- /**
- * A trap for setting property values.
- */ set (target, prop, value) {
- proxy[prop] = value; // set to proxy
- delete target[prop]; // remove from cache
- return true;
- }
- });
- }
- /**
- * @private
- */ function _descriptors(proxy, defaults = {
- scriptable: true,
- indexable: true
- }) {
- const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;
- return {
- allKeys: _allKeys,
- scriptable: _scriptable,
- indexable: _indexable,
- isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,
- isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable
- };
- }
- const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;
- const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);
- function _cached(target, prop, resolve) {
- if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {
- return target[prop];
- }
- const value = resolve();
- // cache the resolved value
- target[prop] = value;
- return value;
- }
- function _resolveWithContext(target, prop, receiver) {
- const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
- let value = _proxy[prop]; // resolve from proxy
- // resolve with context
- if (isFunction(value) && descriptors.isScriptable(prop)) {
- value = _resolveScriptable(prop, value, target, receiver);
- }
- if (isArray(value) && value.length) {
- value = _resolveArray(prop, value, target, descriptors.isIndexable);
- }
- if (needsSubResolver(prop, value)) {
- // if the resolved value is an object, create a sub resolver for it
- value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
- }
- return value;
- }
- function _resolveScriptable(prop, getValue, target, receiver) {
- const { _proxy , _context , _subProxy , _stack } = target;
- if (_stack.has(prop)) {
- throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
- }
- _stack.add(prop);
- let value = getValue(_context, _subProxy || receiver);
- _stack.delete(prop);
- if (needsSubResolver(prop, value)) {
- // When scriptable option returns an object, create a resolver on that.
- value = createSubResolver(_proxy._scopes, _proxy, prop, value);
- }
- return value;
- }
- function _resolveArray(prop, value, target, isIndexable) {
- const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;
- if (typeof _context.index !== 'undefined' && isIndexable(prop)) {
- return value[_context.index % value.length];
- } else if (isObject(value[0])) {
- // Array of objects, return array or resolvers
- const arr = value;
- const scopes = _proxy._scopes.filter((s)=>s !== arr);
- value = [];
- for (const item of arr){
- const resolver = createSubResolver(scopes, _proxy, prop, item);
- value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
- }
- }
- return value;
- }
- function resolveFallback(fallback, prop, value) {
- return isFunction(fallback) ? fallback(prop, value) : fallback;
- }
- const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
- function addScopes(set, parentScopes, key, parentFallback, value) {
- for (const parent of parentScopes){
- const scope = getScope(key, parent);
- if (scope) {
- set.add(scope);
- const fallback = resolveFallback(scope._fallback, key, value);
- if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {
- // When we reach the descriptor that defines a new _fallback, return that.
- // The fallback will resume to that new scope.
- return fallback;
- }
- } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {
- // Fallback to `false` results to `false`, when falling back to different key.
- // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`
- return null;
- }
- }
- return false;
- }
- function createSubResolver(parentScopes, resolver, prop, value) {
- const rootScopes = resolver._rootScopes;
- const fallback = resolveFallback(resolver._fallback, prop, value);
- const allScopes = [
- ...parentScopes,
- ...rootScopes
- ];
- const set = new Set();
- set.add(value);
- let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
- if (key === null) {
- return false;
- }
- if (typeof fallback !== 'undefined' && fallback !== prop) {
- key = addScopesFromKey(set, allScopes, fallback, key, value);
- if (key === null) {
- return false;
- }
- }
- return _createResolver(Array.from(set), [
- ''
- ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));
- }
- function addScopesFromKey(set, allScopes, key, fallback, item) {
- while(key){
- key = addScopes(set, allScopes, key, fallback, item);
- }
- return key;
- }
- function subGetTarget(resolver, prop, value) {
- const parent = resolver._getTarget();
- if (!(prop in parent)) {
- parent[prop] = {};
- }
- const target = parent[prop];
- if (isArray(target) && isObject(value)) {
- // For array of objects, the object is used to store updated values
- return value;
- }
- return target || {};
- }
- function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
- let value;
- for (const prefix of prefixes){
- value = _resolve(readKey(prefix, prop), scopes);
- if (typeof value !== 'undefined') {
- return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
- }
- }
- }
- function _resolve(key, scopes) {
- for (const scope of scopes){
- if (!scope) {
- continue;
- }
- const value = scope[key];
- if (typeof value !== 'undefined') {
- return value;
- }
- }
- }
- function getKeysFromAllScopes(target) {
- let keys = target._keys;
- if (!keys) {
- keys = target._keys = resolveKeysFromAllScopes(target._scopes);
- }
- return keys;
- }
- function resolveKeysFromAllScopes(scopes) {
- const set = new Set();
- for (const scope of scopes){
- for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){
- set.add(key);
- }
- }
- return Array.from(set);
- }
- function _parseObjectDataRadialScale(meta, data, start, count) {
- const { iScale } = meta;
- const { key ='r' } = this._parsing;
- const parsed = new Array(count);
- let i, ilen, index, item;
- for(i = 0, ilen = count; i < ilen; ++i){
- index = i + start;
- item = data[index];
- parsed[i] = {
- r: iScale.parse(resolveObjectKey(item, key), index)
- };
- }
- return parsed;
- }
-
- const EPSILON = Number.EPSILON || 1e-14;
- const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];
- const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';
- function splineCurve(firstPoint, middlePoint, afterPoint, t) {
- // Props to Rob Spencer at scaled innovation for his post on splining between points
- // http://scaledinnovation.com/analytics/splines/aboutSplines.html
- // This function must also respect "skipped" points
- const previous = firstPoint.skip ? middlePoint : firstPoint;
- const current = middlePoint;
- const next = afterPoint.skip ? middlePoint : afterPoint;
- const d01 = distanceBetweenPoints(current, previous);
- const d12 = distanceBetweenPoints(next, current);
- let s01 = d01 / (d01 + d12);
- let s12 = d12 / (d01 + d12);
- // If all points are the same, s01 & s02 will be inf
- s01 = isNaN(s01) ? 0 : s01;
- s12 = isNaN(s12) ? 0 : s12;
- const fa = t * s01; // scaling factor for triangle Ta
- const fb = t * s12;
- return {
- previous: {
- x: current.x - fa * (next.x - previous.x),
- y: current.y - fa * (next.y - previous.y)
- },
- next: {
- x: current.x + fb * (next.x - previous.x),
- y: current.y + fb * (next.y - previous.y)
- }
- };
- }
- /**
- * Adjust tangents to ensure monotonic properties
- */ function monotoneAdjust(points, deltaK, mK) {
- const pointsLen = points.length;
- let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
- let pointAfter = getPoint(points, 0);
- for(let i = 0; i < pointsLen - 1; ++i){
- pointCurrent = pointAfter;
- pointAfter = getPoint(points, i + 1);
- if (!pointCurrent || !pointAfter) {
- continue;
- }
- if (almostEquals(deltaK[i], 0, EPSILON)) {
- mK[i] = mK[i + 1] = 0;
- continue;
- }
- alphaK = mK[i] / deltaK[i];
- betaK = mK[i + 1] / deltaK[i];
- squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
- if (squaredMagnitude <= 9) {
- continue;
- }
- tauK = 3 / Math.sqrt(squaredMagnitude);
- mK[i] = alphaK * tauK * deltaK[i];
- mK[i + 1] = betaK * tauK * deltaK[i];
- }
- }
- function monotoneCompute(points, mK, indexAxis = 'x') {
- const valueAxis = getValueAxis(indexAxis);
- const pointsLen = points.length;
- let delta, pointBefore, pointCurrent;
- let pointAfter = getPoint(points, 0);
- for(let i = 0; i < pointsLen; ++i){
- pointBefore = pointCurrent;
- pointCurrent = pointAfter;
- pointAfter = getPoint(points, i + 1);
- if (!pointCurrent) {
- continue;
- }
- const iPixel = pointCurrent[indexAxis];
- const vPixel = pointCurrent[valueAxis];
- if (pointBefore) {
- delta = (iPixel - pointBefore[indexAxis]) / 3;
- pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
- pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
- }
- if (pointAfter) {
- delta = (pointAfter[indexAxis] - iPixel) / 3;
- pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
- pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
- }
- }
- }
- /**
- * This function calculates Bézier control points in a similar way than |splineCurve|,
- * but preserves monotonicity of the provided data and ensures no local extremums are added
- * between the dataset discrete points due to the interpolation.
- * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
- */ function splineCurveMonotone(points, indexAxis = 'x') {
- const valueAxis = getValueAxis(indexAxis);
- const pointsLen = points.length;
- const deltaK = Array(pointsLen).fill(0);
- const mK = Array(pointsLen);
- // Calculate slopes (deltaK) and initialize tangents (mK)
- let i, pointBefore, pointCurrent;
- let pointAfter = getPoint(points, 0);
- for(i = 0; i < pointsLen; ++i){
- pointBefore = pointCurrent;
- pointCurrent = pointAfter;
- pointAfter = getPoint(points, i + 1);
- if (!pointCurrent) {
- continue;
- }
- if (pointAfter) {
- const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
- // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
- deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
- }
- mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;
- }
- monotoneAdjust(points, deltaK, mK);
- monotoneCompute(points, mK, indexAxis);
- }
- function capControlPoint(pt, min, max) {
- return Math.max(Math.min(pt, max), min);
- }
- function capBezierPoints(points, area) {
- let i, ilen, point, inArea, inAreaPrev;
- let inAreaNext = _isPointInArea(points[0], area);
- for(i = 0, ilen = points.length; i < ilen; ++i){
- inAreaPrev = inArea;
- inArea = inAreaNext;
- inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
- if (!inArea) {
- continue;
- }
- point = points[i];
- if (inAreaPrev) {
- point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
- point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
- }
- if (inAreaNext) {
- point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
- point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
- }
- }
- }
- /**
- * @private
- */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
- let i, ilen, point, controlPoints;
- // Only consider points that are drawn in case the spanGaps option is used
- if (options.spanGaps) {
- points = points.filter((pt)=>!pt.skip);
- }
- if (options.cubicInterpolationMode === 'monotone') {
- splineCurveMonotone(points, indexAxis);
- } else {
- let prev = loop ? points[points.length - 1] : points[0];
- for(i = 0, ilen = points.length; i < ilen; ++i){
- point = points[i];
- controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);
- point.cp1x = controlPoints.previous.x;
- point.cp1y = controlPoints.previous.y;
- point.cp2x = controlPoints.next.x;
- point.cp2y = controlPoints.next.y;
- prev = point;
- }
- }
- if (options.capBezierPoints) {
- capBezierPoints(points, area);
- }
- }
-
- /**
- * Note: typedefs are auto-exported, so use a made-up `dom` namespace where
- * necessary to avoid duplicates with `export * from './helpers`; see
- * https://github.com/microsoft/TypeScript/issues/46011
- * @typedef { import('../core/core.controller.js').default } dom.Chart
- * @typedef { import('../../types').ChartEvent } ChartEvent
- */ /**
- * @private
- */ function _isDomSupported() {
- return typeof window !== 'undefined' && typeof document !== 'undefined';
- }
- /**
- * @private
- */ function _getParentNode(domNode) {
- let parent = domNode.parentNode;
- if (parent && parent.toString() === '[object ShadowRoot]') {
- parent = parent.host;
- }
- return parent;
- }
- /**
- * convert max-width/max-height values that may be percentages into a number
- * @private
- */ function parseMaxStyle(styleValue, node, parentProperty) {
- let valueInPixels;
- if (typeof styleValue === 'string') {
- valueInPixels = parseInt(styleValue, 10);
- if (styleValue.indexOf('%') !== -1) {
- // percentage * size in dimension
- valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
- }
- } else {
- valueInPixels = styleValue;
- }
- return valueInPixels;
- }
- const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);
- function getStyle(el, property) {
- return getComputedStyle(el).getPropertyValue(property);
- }
- const positions = [
- 'top',
- 'right',
- 'bottom',
- 'left'
- ];
- function getPositionedStyle(styles, style, suffix) {
- const result = {};
- suffix = suffix ? '-' + suffix : '';
- for(let i = 0; i < 4; i++){
- const pos = positions[i];
- result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
- }
- result.width = result.left + result.right;
- result.height = result.top + result.bottom;
- return result;
- }
- const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);
- /**
- * @param e
- * @param canvas
- * @returns Canvas position
- */ function getCanvasPosition(e, canvas) {
- const touches = e.touches;
- const source = touches && touches.length ? touches[0] : e;
- const { offsetX , offsetY } = source;
- let box = false;
- let x, y;
- if (useOffsetPos(offsetX, offsetY, e.target)) {
- x = offsetX;
- y = offsetY;
- } else {
- const rect = canvas.getBoundingClientRect();
- x = source.clientX - rect.left;
- y = source.clientY - rect.top;
- box = true;
- }
- return {
- x,
- y,
- box
- };
- }
- /**
- * Gets an event's x, y coordinates, relative to the chart area
- * @param event
- * @param chart
- * @returns x and y coordinates of the event
- */ function getRelativePosition(event, chart) {
- if ('native' in event) {
- return event;
- }
- const { canvas , currentDevicePixelRatio } = chart;
- const style = getComputedStyle(canvas);
- const borderBox = style.boxSizing === 'border-box';
- const paddings = getPositionedStyle(style, 'padding');
- const borders = getPositionedStyle(style, 'border', 'width');
- const { x , y , box } = getCanvasPosition(event, canvas);
- const xOffset = paddings.left + (box && borders.left);
- const yOffset = paddings.top + (box && borders.top);
- let { width , height } = chart;
- if (borderBox) {
- width -= paddings.width + borders.width;
- height -= paddings.height + borders.height;
- }
- return {
- x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
- y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
- };
- }
- function getContainerSize(canvas, width, height) {
- let maxWidth, maxHeight;
- if (width === undefined || height === undefined) {
- const container = canvas && _getParentNode(canvas);
- if (!container) {
- width = canvas.clientWidth;
- height = canvas.clientHeight;
- } else {
- const rect = container.getBoundingClientRect(); // this is the border box of the container
- const containerStyle = getComputedStyle(container);
- const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
- const containerPadding = getPositionedStyle(containerStyle, 'padding');
- width = rect.width - containerPadding.width - containerBorder.width;
- height = rect.height - containerPadding.height - containerBorder.height;
- maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
- maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
- }
- }
- return {
- width,
- height,
- maxWidth: maxWidth || INFINITY,
- maxHeight: maxHeight || INFINITY
- };
- }
- const round1 = (v)=>Math.round(v * 10) / 10;
- // eslint-disable-next-line complexity
- function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
- const style = getComputedStyle(canvas);
- const margins = getPositionedStyle(style, 'margin');
- const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
- const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
- const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
- let { width , height } = containerSize;
- if (style.boxSizing === 'content-box') {
- const borders = getPositionedStyle(style, 'border', 'width');
- const paddings = getPositionedStyle(style, 'padding');
- width -= paddings.width + borders.width;
- height -= paddings.height + borders.height;
- }
- width = Math.max(0, width - margins.width);
- height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
- width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
- height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
- if (width && !height) {
- // https://github.com/chartjs/Chart.js/issues/4659
- // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)
- height = round1(width / 2);
- }
- const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;
- if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
- height = containerSize.height;
- width = round1(Math.floor(height * aspectRatio));
- }
- return {
- width,
- height
- };
- }
- /**
- * @param chart
- * @param forceRatio
- * @param forceStyle
- * @returns True if the canvas context size or transformation has changed.
- */ function retinaScale(chart, forceRatio, forceStyle) {
- const pixelRatio = forceRatio || 1;
- const deviceHeight = Math.floor(chart.height * pixelRatio);
- const deviceWidth = Math.floor(chart.width * pixelRatio);
- chart.height = Math.floor(chart.height);
- chart.width = Math.floor(chart.width);
- const canvas = chart.canvas;
- // If no style has been set on the canvas, the render size is used as display size,
- // making the chart visually bigger, so let's enforce it to the "correct" values.
- // See https://github.com/chartjs/Chart.js/issues/3575
- if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
- canvas.style.height = `${chart.height}px`;
- canvas.style.width = `${chart.width}px`;
- }
- if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
- chart.currentDevicePixelRatio = pixelRatio;
- canvas.height = deviceHeight;
- canvas.width = deviceWidth;
- chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
- return true;
- }
- return false;
- }
- /**
- * Detects support for options object argument in addEventListener.
- * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
- * @private
- */ const supportsEventListenerOptions = function() {
- let passiveSupported = false;
- try {
- const options = {
- get passive () {
- passiveSupported = true;
- return false;
- }
- };
- if (_isDomSupported()) {
- window.addEventListener('test', null, options);
- window.removeEventListener('test', null, options);
- }
- } catch (e) {
- // continue regardless of error
- }
- return passiveSupported;
- }();
- /**
- * The "used" size is the final value of a dimension property after all calculations have
- * been performed. This method uses the computed style of `element` but returns undefined
- * if the computed style is not expressed in pixels. That can happen in some cases where
- * `element` has a size relative to its parent and this last one is not yet displayed,
- * for example because of `display: none` on a parent node.
- * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
- * @returns Size in pixels or undefined if unknown.
- */ function readUsedSize(element, property) {
- const value = getStyle(element, property);
- const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
- return matches ? +matches[1] : undefined;
- }
-
- /**
- * @private
- */ function _pointInLine(p1, p2, t, mode) {
- return {
- x: p1.x + t * (p2.x - p1.x),
- y: p1.y + t * (p2.y - p1.y)
- };
- }
- /**
- * @private
- */ function _steppedInterpolation(p1, p2, t, mode) {
- return {
- x: p1.x + t * (p2.x - p1.x),
- y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y
- };
- }
- /**
- * @private
- */ function _bezierInterpolation(p1, p2, t, mode) {
- const cp1 = {
- x: p1.cp2x,
- y: p1.cp2y
- };
- const cp2 = {
- x: p2.cp1x,
- y: p2.cp1y
- };
- const a = _pointInLine(p1, cp1, t);
- const b = _pointInLine(cp1, cp2, t);
- const c = _pointInLine(cp2, p2, t);
- const d = _pointInLine(a, b, t);
- const e = _pointInLine(b, c, t);
- return _pointInLine(d, e, t);
- }
-
- const getRightToLeftAdapter = function(rectX, width) {
- return {
- x (x) {
- return rectX + rectX + width - x;
- },
- setWidth (w) {
- width = w;
- },
- textAlign (align) {
- if (align === 'center') {
- return align;
- }
- return align === 'right' ? 'left' : 'right';
- },
- xPlus (x, value) {
- return x - value;
- },
- leftForLtr (x, itemWidth) {
- return x - itemWidth;
- }
- };
- };
- const getLeftToRightAdapter = function() {
- return {
- x (x) {
- return x;
- },
- setWidth (w) {},
- textAlign (align) {
- return align;
- },
- xPlus (x, value) {
- return x + value;
- },
- leftForLtr (x, _itemWidth) {
- return x;
- }
- };
- };
- function getRtlAdapter(rtl, rectX, width) {
- return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
- }
- function overrideTextDirection(ctx, direction) {
- let style, original;
- if (direction === 'ltr' || direction === 'rtl') {
- style = ctx.canvas.style;
- original = [
- style.getPropertyValue('direction'),
- style.getPropertyPriority('direction')
- ];
- style.setProperty('direction', direction, 'important');
- ctx.prevTextDirection = original;
- }
- }
- function restoreTextDirection(ctx, original) {
- if (original !== undefined) {
- delete ctx.prevTextDirection;
- ctx.canvas.style.setProperty('direction', original[0], original[1]);
- }
- }
-
- function propertyFn(property) {
- if (property === 'angle') {
- return {
- between: _angleBetween,
- compare: _angleDiff,
- normalize: _normalizeAngle
- };
- }
- return {
- between: _isBetween,
- compare: (a, b)=>a - b,
- normalize: (x)=>x
- };
- }
- function normalizeSegment({ start , end , count , loop , style }) {
- return {
- start: start % count,
- end: end % count,
- loop: loop && (end - start + 1) % count === 0,
- style
- };
- }
- function getSegment(segment, points, bounds) {
- const { property , start: startBound , end: endBound } = bounds;
- const { between , normalize } = propertyFn(property);
- const count = points.length;
- let { start , end , loop } = segment;
- let i, ilen;
- if (loop) {
- start += count;
- end += count;
- for(i = 0, ilen = count; i < ilen; ++i){
- if (!between(normalize(points[start % count][property]), startBound, endBound)) {
- break;
- }
- start--;
- end--;
- }
- start %= count;
- end %= count;
- }
- if (end < start) {
- end += count;
- }
- return {
- start,
- end,
- loop,
- style: segment.style
- };
- }
- function _boundSegment(segment, points, bounds) {
- if (!bounds) {
- return [
- segment
- ];
- }
- const { property , start: startBound , end: endBound } = bounds;
- const count = points.length;
- const { compare , between , normalize } = propertyFn(property);
- const { start , end , loop , style } = getSegment(segment, points, bounds);
- const result = [];
- let inside = false;
- let subStart = null;
- let value, point, prevValue;
- const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
- const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);
- const shouldStart = ()=>inside || startIsBefore();
- const shouldStop = ()=>!inside || endIsBefore();
- for(let i = start, prev = start; i <= end; ++i){
- point = points[i % count];
- if (point.skip) {
- continue;
- }
- value = normalize(point[property]);
- if (value === prevValue) {
- continue;
- }
- inside = between(value, startBound, endBound);
- if (subStart === null && shouldStart()) {
- subStart = compare(value, startBound) === 0 ? i : prev;
- }
- if (subStart !== null && shouldStop()) {
- result.push(normalizeSegment({
- start: subStart,
- end: i,
- loop,
- count,
- style
- }));
- subStart = null;
- }
- prev = i;
- prevValue = value;
- }
- if (subStart !== null) {
- result.push(normalizeSegment({
- start: subStart,
- end,
- loop,
- count,
- style
- }));
- }
- return result;
- }
- function _boundSegments(line, bounds) {
- const result = [];
- const segments = line.segments;
- for(let i = 0; i < segments.length; i++){
- const sub = _boundSegment(segments[i], line.points, bounds);
- if (sub.length) {
- result.push(...sub);
- }
- }
- return result;
- }
- function findStartAndEnd(points, count, loop, spanGaps) {
- let start = 0;
- let end = count - 1;
- if (loop && !spanGaps) {
- while(start < count && !points[start].skip){
- start++;
- }
- }
- while(start < count && points[start].skip){
- start++;
- }
- start %= count;
- if (loop) {
- end += start;
- }
- while(end > start && points[end % count].skip){
- end--;
- }
- end %= count;
- return {
- start,
- end
- };
- }
- function solidSegments(points, start, max, loop) {
- const count = points.length;
- const result = [];
- let last = start;
- let prev = points[start];
- let end;
- for(end = start + 1; end <= max; ++end){
- const cur = points[end % count];
- if (cur.skip || cur.stop) {
- if (!prev.skip) {
- loop = false;
- result.push({
- start: start % count,
- end: (end - 1) % count,
- loop
- });
- start = last = cur.stop ? end : null;
- }
- } else {
- last = end;
- if (prev.skip) {
- start = end;
- }
- }
- prev = cur;
- }
- if (last !== null) {
- result.push({
- start: start % count,
- end: last % count,
- loop
- });
- }
- return result;
- }
- function _computeSegments(line, segmentOptions) {
- const points = line.points;
- const spanGaps = line.options.spanGaps;
- const count = points.length;
- if (!count) {
- return [];
- }
- const loop = !!line._loop;
- const { start , end } = findStartAndEnd(points, count, loop, spanGaps);
- if (spanGaps === true) {
- return splitByStyles(line, [
- {
- start,
- end,
- loop
- }
- ], points, segmentOptions);
- }
- const max = end < start ? end + count : end;
- const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
- return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
- }
- function splitByStyles(line, segments, points, segmentOptions) {
- if (!segmentOptions || !segmentOptions.setContext || !points) {
- return segments;
- }
- return doSplitByStyles(line, segments, points, segmentOptions);
- }
- function doSplitByStyles(line, segments, points, segmentOptions) {
- const chartContext = line._chart.getContext();
- const baseStyle = readStyle(line.options);
- const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;
- const count = points.length;
- const result = [];
- let prevStyle = baseStyle;
- let start = segments[0].start;
- let i = start;
- function addStyle(s, e, l, st) {
- const dir = spanGaps ? -1 : 1;
- if (s === e) {
- return;
- }
- s += count;
- while(points[s % count].skip){
- s -= dir;
- }
- while(points[e % count].skip){
- e += dir;
- }
- if (s % count !== e % count) {
- result.push({
- start: s % count,
- end: e % count,
- loop: l,
- style: st
- });
- prevStyle = st;
- start = e % count;
- }
- }
- for (const segment of segments){
- start = spanGaps ? start : segment.start;
- let prev = points[start % count];
- let style;
- for(i = start + 1; i <= segment.end; i++){
- const pt = points[i % count];
- style = readStyle(segmentOptions.setContext(createContext(chartContext, {
- type: 'segment',
- p0: prev,
- p1: pt,
- p0DataIndex: (i - 1) % count,
- p1DataIndex: i % count,
- datasetIndex
- })));
- if (styleChanged(style, prevStyle)) {
- addStyle(start, i - 1, segment.loop, prevStyle);
- }
- prev = pt;
- prevStyle = style;
- }
- if (start < i - 1) {
- addStyle(start, i - 1, segment.loop, prevStyle);
- }
- }
- return result;
- }
- function readStyle(options) {
- return {
- backgroundColor: options.backgroundColor,
- borderCapStyle: options.borderCapStyle,
- borderDash: options.borderDash,
- borderDashOffset: options.borderDashOffset,
- borderJoinStyle: options.borderJoinStyle,
- borderWidth: options.borderWidth,
- borderColor: options.borderColor
- };
- }
- function styleChanged(style, prevStyle) {
- if (!prevStyle) {
- return false;
- }
- const cache = [];
- const replacer = function(key, value) {
- if (!isPatternOrGradient(value)) {
- return value;
- }
- if (!cache.includes(value)) {
- cache.push(value);
- }
- return cache.indexOf(value);
- };
- return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);
- }
-
- exports.HALF_PI = HALF_PI;
- exports.INFINITY = INFINITY;
- exports.PI = PI;
- exports.PITAU = PITAU;
- exports.QUARTER_PI = QUARTER_PI;
- exports.RAD_PER_DEG = RAD_PER_DEG;
- exports.TAU = TAU;
- exports.TWO_THIRDS_PI = TWO_THIRDS_PI;
- exports.Ticks = Ticks;
- exports._addGrace = _addGrace;
- exports._alignPixel = _alignPixel;
- exports._alignStartEnd = _alignStartEnd;
- exports._angleBetween = _angleBetween;
- exports._angleDiff = _angleDiff;
- exports._arrayUnique = _arrayUnique;
- exports._attachContext = _attachContext;
- exports._bezierCurveTo = _bezierCurveTo;
- exports._bezierInterpolation = _bezierInterpolation;
- exports._boundSegment = _boundSegment;
- exports._boundSegments = _boundSegments;
- exports._capitalize = _capitalize;
- exports._computeSegments = _computeSegments;
- exports._createResolver = _createResolver;
- exports._decimalPlaces = _decimalPlaces;
- exports._deprecated = _deprecated;
- exports._descriptors = _descriptors;
- exports._elementsEqual = _elementsEqual;
- exports._factorize = _factorize;
- exports._filterBetween = _filterBetween;
- exports._getParentNode = _getParentNode;
- exports._getStartAndCountOfVisiblePoints = _getStartAndCountOfVisiblePoints;
- exports._int16Range = _int16Range;
- exports._isBetween = _isBetween;
- exports._isClickEvent = _isClickEvent;
- exports._isDomSupported = _isDomSupported;
- exports._isPointInArea = _isPointInArea;
- exports._limitValue = _limitValue;
- exports._longestText = _longestText;
- exports._lookup = _lookup;
- exports._lookupByKey = _lookupByKey;
- exports._measureText = _measureText;
- exports._merger = _merger;
- exports._mergerIf = _mergerIf;
- exports._normalizeAngle = _normalizeAngle;
- exports._parseObjectDataRadialScale = _parseObjectDataRadialScale;
- exports._pointInLine = _pointInLine;
- exports._readValueToProps = _readValueToProps;
- exports._rlookupByKey = _rlookupByKey;
- exports._scaleRangesChanged = _scaleRangesChanged;
- exports._setMinAndMaxByKey = _setMinAndMaxByKey;
- exports._splitKey = _splitKey;
- exports._steppedInterpolation = _steppedInterpolation;
- exports._steppedLineTo = _steppedLineTo;
- exports._textX = _textX;
- exports._toLeftRightCenter = _toLeftRightCenter;
- exports._updateBezierControlPoints = _updateBezierControlPoints;
- exports.addRoundedRectPath = addRoundedRectPath;
- exports.almostEquals = almostEquals;
- exports.almostWhole = almostWhole;
- exports.callback = callback;
- exports.clearCanvas = clearCanvas;
- exports.clipArea = clipArea;
- exports.clone = clone;
- exports.color = color;
- exports.createContext = createContext;
- exports.debounce = debounce;
- exports.defaults = defaults;
- exports.defined = defined;
- exports.descriptors = descriptors;
- exports.distanceBetweenPoints = distanceBetweenPoints;
- exports.drawPoint = drawPoint;
- exports.drawPointLegend = drawPointLegend;
- exports.each = each;
- exports.effects = effects;
- exports.finiteOrDefault = finiteOrDefault;
- exports.fontString = fontString;
- exports.formatNumber = formatNumber;
- exports.getAngleFromPoint = getAngleFromPoint;
- exports.getHoverColor = getHoverColor;
- exports.getMaximumSize = getMaximumSize;
- exports.getRelativePosition = getRelativePosition;
- exports.getRtlAdapter = getRtlAdapter;
- exports.getStyle = getStyle;
- exports.isArray = isArray;
- exports.isFunction = isFunction;
- exports.isNullOrUndef = isNullOrUndef;
- exports.isNumber = isNumber;
- exports.isNumberFinite = isNumberFinite;
- exports.isObject = isObject;
- exports.isPatternOrGradient = isPatternOrGradient;
- exports.listenArrayEvents = listenArrayEvents;
- exports.log10 = log10;
- exports.merge = merge;
- exports.mergeIf = mergeIf;
- exports.niceNum = niceNum;
- exports.noop = noop;
- exports.overrideTextDirection = overrideTextDirection;
- exports.overrides = overrides;
- exports.readUsedSize = readUsedSize;
- exports.renderText = renderText;
- exports.requestAnimFrame = requestAnimFrame;
- exports.resolve = resolve;
- exports.resolveObjectKey = resolveObjectKey;
- exports.restoreTextDirection = restoreTextDirection;
- exports.retinaScale = retinaScale;
- exports.setsEqual = setsEqual;
- exports.sign = sign;
- exports.splineCurve = splineCurve;
- exports.splineCurveMonotone = splineCurveMonotone;
- exports.supportsEventListenerOptions = supportsEventListenerOptions;
- exports.throttled = throttled;
- exports.toDegrees = toDegrees;
- exports.toDimension = toDimension;
- exports.toFont = toFont;
- exports.toFontString = toFontString;
- exports.toLineHeight = toLineHeight;
- exports.toPadding = toPadding;
- exports.toPercentage = toPercentage;
- exports.toRadians = toRadians;
- exports.toTRBL = toTRBL;
- exports.toTRBLCorners = toTRBLCorners;
- exports.uid = uid;
- exports.unclipArea = unclipArea;
- exports.unlistenArrayEvents = unlistenArrayEvents;
- exports.valueOrDefault = valueOrDefault;
- //# sourceMappingURL=helpers.segment.cjs.map
|