]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Handle incoming model values on element transition
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Sat, 25 Feb 2017 12:06:36 +0000 (13:06 +0100)
committerEvert Timberg <evert.timberg+github@gmail.com>
Fri, 3 Mar 2017 11:49:32 +0000 (06:49 -0500)
If a value is set on the model after `pivot()` has been called, the view wasn't initialized and the animation started from 0. Now, `_start` and incomplete `_view` are initialized to the model value during the transition (no initial implicit transition).

Also remove exception handling when animating a string (color), which is faster when string are not valid colors (e.g. tooltip position). It requires to update `chartjs-color` to version 2.1.0.

package.json
src/core/core.element.js
src/core/core.helpers.js
test/core.element.tests.js

index 1dd362e95135973ef08f79bf82b7ad029083a4f4..6a3a28ea9b29cfa240c18fac7f83e697cd54a3eb 100644 (file)
@@ -46,7 +46,7 @@
     "main": "Chart.js"
   },
   "dependencies": {
-    "chartjs-color": "~2.0.0",
+    "chartjs-color": "^2.1.0",
     "moment": "^2.10.6"
   }
 }
index d8dc57208a40f3c602d0bac9f8ae0432df81168e..4fecfb33887f01dce77957142dfdd3d54449a618 100644 (file)
@@ -1,9 +1,60 @@
 'use strict';
 
+var color = require('chartjs-color');
+
 module.exports = function(Chart) {
 
        var helpers = Chart.helpers;
 
+       function interpolate(start, view, model, ease) {
+               var keys = Object.keys(model);
+               var i, ilen, key, actual, origin, target, type, c0, c1;
+
+               for (i=0, ilen=keys.length; i<ilen; ++i) {
+                       key = keys[i];
+
+                       target = model[key];
+
+                       // if a value is added to the model after pivot() has been called, the view
+                       // doesn't contain it, so let's initialize the view to the target value.
+                       if (!view.hasOwnProperty(key)) {
+                               view[key] = target;
+                       }
+
+                       actual = view[key];
+
+                       if (actual === target || key[0] === '_') {
+                               continue;
+                       }
+
+                       if (!start.hasOwnProperty(key)) {
+                               start[key] = actual;
+                       }
+
+                       origin = start[key];
+
+                       type = typeof(target);
+
+                       if (type === typeof(origin)) {
+                               if (type === 'string') {
+                                       c0 = color(origin);
+                                       if (c0.valid) {
+                                               c1 = color(target);
+                                               if (c1.valid) {
+                                                       view[key] = c1.mix(c0, ease).rgbString();
+                                                       continue;
+                                               }
+                                       }
+                               } else if (type === 'number' && isFinite(origin) && isFinite(target)) {
+                                       view[key] = origin + (target - origin) * ease;
+                                       continue;
+                               }
+                       }
+
+                       view[key] = target;
+               }
+       }
+
        Chart.elements = {};
 
        Chart.Element = function(configuration) {
@@ -22,59 +73,32 @@ module.exports = function(Chart) {
                        if (!me._view) {
                                me._view = helpers.clone(me._model);
                        }
-                       me._start = helpers.clone(me._view);
+                       me._start = {};
                        return me;
                },
 
                transition: function(ease) {
                        var me = this;
-
-                       if (!me._view) {
-                               me._view = helpers.clone(me._model);
-                       }
+                       var model = me._model;
+                       var start = me._start;
+                       var view = me._view;
 
                        // No animation -> No Transition
-                       if (ease === 1) {
-                               me._view = me._model;
+                       if (!model || ease === 1) {
+                               me._view = model;
                                me._start = null;
                                return me;
                        }
 
-                       if (!me._start) {
-                               me.pivot();
+                       if (!view) {
+                               view = me._view = {};
                        }
 
-                       helpers.each(me._model, function(value, key) {
+                       if (!start) {
+                               start = me._start = {};
+                       }
 
-                               if (key[0] === '_') {
-                                       // Only non-underscored properties
-                               // Init if doesn't exist
-                               } else if (!me._view.hasOwnProperty(key)) {
-                                       if (typeof value === 'number' && !isNaN(me._view[key])) {
-                                               me._view[key] = value * ease;
-                                       } else {
-                                               me._view[key] = value;
-                                       }
-                               // No unnecessary computations
-                               } else if (value === me._view[key]) {
-                                       // It's the same! Woohoo!
-                               // Color transitions if possible
-                               } else if (typeof value === 'string') {
-                                       try {
-                                               var color = helpers.color(me._model[key]).mix(helpers.color(me._start[key]), ease);
-                                               me._view[key] = color.rgbString();
-                                       } catch (err) {
-                                               me._view[key] = value;
-                                       }
-                               // Number transitions
-                               } else if (typeof value === 'number') {
-                                       var startVal = me._start[key] !== undefined && isNaN(me._start[key]) === false ? me._start[key] : 0;
-                                       me._view[key] = ((me._model[key] - startVal) * ease) + startVal;
-                               // Everything else
-                               } else {
-                                       me._view[key] = value;
-                               }
-                       }, me);
+                       interpolate(start, view, model, ease);
 
                        return me;
                },
@@ -92,5 +116,4 @@ module.exports = function(Chart) {
        });
 
        Chart.Element.extend = helpers.inherits;
-
 };
index f95af269f6bfb829fd59938c62259958fa025c75..c32e9a76c1c4778483cb65491314683b26a7a65e 100644 (file)
@@ -911,19 +911,21 @@ module.exports = function(Chart) {
                ctx.quadraticCurveTo(x, y, x + radius, y);
                ctx.closePath();
        };
-       helpers.color = function(c) {
-               if (!color) {
+
+       helpers.color = !color?
+               function(value) {
                        console.error('Color.js not found!');
-                       return c;
-               }
+                       return value;
+               } :
+               function(value) {
+                       /* global CanvasGradient */
+                       if (value instanceof CanvasGradient) {
+                               value = Chart.defaults.global.defaultColor;
+                       }
 
-               /* global CanvasGradient */
-               if (c instanceof CanvasGradient) {
-                       return color(Chart.defaults.global.defaultColor);
-               }
+                       return color(value);
+               };
 
-               return color(c);
-       };
        helpers.isArray = Array.isArray?
                function(obj) {
                        return Array.isArray(obj);
index 7d194562e73bd890bf9daa46653da35344f47f9e..ca8f9b03e7cf1da4fffb1a1901f32a14259dd53d 100644 (file)
@@ -16,11 +16,9 @@ describe('Core element tests', function() {
 
                // First transition clones model into view
                element.transition(0.25);
-               expect(element._view).toEqual(element._model);
-               expect(element._start).toEqual(element._model); // also cloned
 
+               expect(element._view).toEqual(element._model);
                expect(element._view.objectProp).toBe(element._model.objectProp); // not cloned
-               expect(element._start.objectProp).toEqual(element._model.objectProp); // not cloned
 
                element._model.numberProp = 100;
                element._model.numberProp2 = 250;
@@ -30,6 +28,7 @@ describe('Core element tests', function() {
                element._model.colorProp = 'rgb(255, 255, 0)';
 
                element.transition(0.25);
+
                expect(element._view).toEqual({
                        numberProp: 25,
                        numberProp2: 137.5,