From: Jukka Kurkela Date: Thu, 11 Mar 2021 23:06:55 +0000 (+0200) Subject: Fix some animation issues (#8616) X-Git-Tag: v3.0.0-beta.14~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b98974f5b2be666a6510b29e98f78994ce757704;p=thirdparty%2FChart.js.git Fix some animation issues (#8616) * Fix some animation issues * Stop animating shared options on reset * cc --- diff --git a/samples/advanced/progress-bar.html b/samples/advanced/progress-bar.html index b4283e2cd..905d04661 100644 --- a/samples/advanced/progress-bar.html +++ b/samples/advanced/progress-bar.html @@ -6,9 +6,7 @@ @@ -58,23 +56,26 @@ }] }, options: { - plugins: { - title: { - display: true, - text: 'Chart.js Line Chart - Animation Progress Bar' - } - }, animation: { duration: 2000, onProgress: function(animation) { progress.value = animation.currentStep / animation.numSteps; }, onComplete: function() { - window.setTimeout(function() { - progress.value = 0; - }, 2000); + // + } + }, + interaction: { + mode: 'nearest', + axis: 'x', + intersect: false + }, + plugins: { + title: { + display: true, + text: 'Chart.js Line Chart - Animation Progress Bar' } - } + }, } }; diff --git a/src/core/core.animation.js b/src/core/core.animation.js index dc78afd79..853ba97c5 100644 --- a/src/core/core.animation.js +++ b/src/core/core.animation.js @@ -30,7 +30,7 @@ export default class Animation { this._fn = cfg.fn || interpolators[cfg.type || typeof from]; this._easing = effects[cfg.easing] || effects.linear; this._start = Math.floor(Date.now() + (cfg.delay || 0)); - this._duration = Math.floor(cfg.duration); + this._duration = this._total = Math.floor(cfg.duration); this._loop = !!cfg.loop; this._target = target; this._prop = prop; @@ -53,6 +53,7 @@ export default class Animation { const remain = me._duration - elapsed; me._start = date; me._duration = Math.floor(Math.max(remain, cfg.duration)); + me._total += elapsed; me._loop = !!cfg.loop; me._to = resolve([cfg.to, to, currentValue, cfg.from]); me._from = resolve([cfg.from, currentValue, to]); diff --git a/src/core/core.animator.js b/src/core/core.animator.js index 918eddad7..32d2934f2 100644 --- a/src/core/core.animator.js +++ b/src/core/core.animator.js @@ -72,6 +72,11 @@ export class Animator { item = items[i]; if (item._active) { + if (item._total > anims.duration) { + // if the animation has been updated and its duration prolonged, + // update to total duration of current animations run (for progress event) + anims.duration = item._total; + } item.tick(date); draw = true; } else { diff --git a/src/core/core.config.js b/src/core/core.config.js index a9e937ce9..d54b42aa0 100644 --- a/src/core/core.config.js +++ b/src/core/core.config.js @@ -167,14 +167,14 @@ export default class Config { * Returns the option scope keys for resolving dataset options. * These keys do not include the dataset itself, because it is not under options. * @param {string} datasetType - * @return {string[]} + * @return {string[][]} */ datasetScopeKeys(datasetType) { return cachedKeys(datasetType, - () => [ + () => [[ `datasets.${datasetType}`, '' - ]); + ]]); } /** @@ -182,16 +182,20 @@ export default class Config { * These keys do not include the dataset itself, because it is not under options. * @param {string} datasetType * @param {string} transition - * @return {string[]} + * @return {string[][]} */ datasetAnimationScopeKeys(datasetType, transition) { return cachedKeys(`${datasetType}.transition.${transition}`, () => [ - `datasets.${datasetType}.transitions.${transition}`, - `transitions.${transition}`, + [ + `datasets.${datasetType}.transitions.${transition}`, + `transitions.${transition}`, + ], // The following are used for looking up the `animations` and `animation` keys - `datasets.${datasetType}`, - '' + [ + `datasets.${datasetType}`, + '' + ] ]); } @@ -201,65 +205,76 @@ export default class Config { * is not under options. * @param {string} datasetType * @param {string} elementType - * @return {string[]} + * @return {string[][]} */ datasetElementScopeKeys(datasetType, elementType) { return cachedKeys(`${datasetType}-${elementType}`, - () => [ + () => [[ `datasets.${datasetType}.elements.${elementType}`, `datasets.${datasetType}`, `elements.${elementType}`, '' - ]); + ]]); } /** * Returns the options scope keys for resolving plugin options. * @param {{id: string, additionalOptionScopes?: string[]}} plugin - * @return {string[]} + * @return {string[][]} */ pluginScopeKeys(plugin) { const id = plugin.id; const type = this.type; return cachedKeys(`${type}-plugin-${id}`, - () => [ + () => [[ `plugins.${id}`, ...plugin.additionalOptionScopes || [], - ]); + ]]); } /** - * Resolves the objects from options and defaults for option value resolution. - * @param {object} mainScope - The main scope object for options - * @param {string[]} scopeKeys - The keys in resolution order - * @param {boolean} [resetCache] - reset the cache for this mainScope + * @private */ - getOptionScopes(mainScope, scopeKeys, resetCache) { - const {_scopeCache, options, type} = this; + _cachedScopes(mainScope, resetCache) { + const _scopeCache = this._scopeCache; let cache = _scopeCache.get(mainScope); if (!cache || resetCache) { cache = new Map(); _scopeCache.set(mainScope, cache); } - const cached = cache.get(scopeKeys); + return cache; + } + + /** + * Resolves the objects from options and defaults for option value resolution. + * @param {object} mainScope - The main scope object for options + * @param {string[][]} keyLists - The arrays of keys in resolution order + * @param {boolean} [resetCache] - reset the cache for this mainScope + */ + getOptionScopes(mainScope, keyLists, resetCache) { + const {options, type} = this; + const cache = this._cachedScopes(mainScope, resetCache); + const cached = cache.get(keyLists); if (cached) { return cached; } const scopes = new Set(); - if (mainScope) { - scopes.add(mainScope); - scopeKeys.forEach(key => addIfFound(scopes, mainScope, key)); - } - scopeKeys.forEach(key => addIfFound(scopes, options, key)); - scopeKeys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); - scopeKeys.forEach(key => addIfFound(scopes, defaults, key)); - scopeKeys.forEach(key => addIfFound(scopes, descriptors, key)); + keyLists.forEach(keys => { + if (mainScope) { + scopes.add(mainScope); + keys.forEach(key => addIfFound(scopes, mainScope, key)); + } + keys.forEach(key => addIfFound(scopes, options, key)); + keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); + keys.forEach(key => addIfFound(scopes, defaults, key)); + keys.forEach(key => addIfFound(scopes, descriptors, key)); + }); const array = [...scopes]; - if (keysCached.has(scopeKeys)) { - cache.set(scopeKeys, array); + if (keysCached.has(keyLists)) { + cache.set(keyLists, array); } return array; } diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index e4c5b0574..c02f90cc4 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -830,7 +830,7 @@ export default class DatasetController { * @protected */ updateSharedOptions(sharedOptions, mode, newOptions) { - if (sharedOptions) { + if (sharedOptions && !isDirectUpdateMode(mode)) { this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); } } diff --git a/src/helpers/helpers.core.js b/src/helpers/helpers.core.js index cf3170ea9..0b5ecf8f8 100644 --- a/src/helpers/helpers.core.js +++ b/src/helpers/helpers.core.js @@ -306,11 +306,8 @@ export function resolveObjectKey(obj, key) { } let pos = 0; let idx = indexOfDotOrLength(key, pos); - while (idx > pos) { + while (obj && idx > pos) { obj = obj[key.substr(pos, idx - pos)]; - if (!obj) { - break; - } pos = idx + 1; idx = indexOfDotOrLength(key, pos); }