]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Fix some animation issues (#8616)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Thu, 11 Mar 2021 23:06:55 +0000 (01:06 +0200)
committerGitHub <noreply@github.com>
Thu, 11 Mar 2021 23:06:55 +0000 (18:06 -0500)
* Fix some animation issues

* Stop animating shared options on reset

* cc

samples/advanced/progress-bar.html
src/core/core.animation.js
src/core/core.animator.js
src/core/core.config.js
src/core/core.datasetController.js
src/helpers/helpers.core.js

index b4283e2cd639e90a36c5fd702bda537c4ae46d0b..905d04661259341a0844692070220c5a01e5b996 100644 (file)
@@ -6,9 +6,7 @@
        <script src="../utils.js"></script>
        <style>
                canvas {
-                       -moz-user-select: none;
-                       -webkit-user-select: none;
-                       -ms-user-select: none;
+                       user-select: none;
                }
        </style>
 </head>
                                }]
                        },
                        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'
                                        }
-                               }
+                               },
                        }
                };
 
index dc78afd79b0b110b77cb017376f3a51cf3936c87..853ba97c5a89b4b1d5669fc4d4bd5fee1e6588c8 100644 (file)
@@ -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]);
index 918eddad747edc7dd4e8024e2f7a969f74a5e702..32d2934f20ecc3e447de41771be043ccbd7c0b5e 100644 (file)
@@ -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 {
index a9e937ce9c78017780b66eb994de3f6f2ef90c71..d54b42aa0f144d41bfb62a1f7c0e9a3e3e32965a 100644 (file)
@@ -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;
   }
index e4c5b0574e339fcdf2cbe5426b954565d4825155..c02f90cc43f90306dbe2cd33070040789dd98a3c 100644 (file)
@@ -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);
     }
   }
index cf3170ea9ea18d79a5b2e279c84e408679dfa125..0b5ecf8f8be54fc02c416856fa745d47b2e13e26 100644 (file)
@@ -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);
   }