]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Refactor time scale methods into a common location
authorBen McCann <benjamin.j.mccann@gmail.com>
Fri, 5 May 2017 04:34:23 +0000 (21:34 -0700)
committerEvert Timberg <evert.timberg+github@gmail.com>
Fri, 26 May 2017 12:13:12 +0000 (08:13 -0400)
src/chart.js
src/core/core.ticks.js
src/helpers/helpers.time.js [new file with mode: 0644]
src/scales/scale.time.js

index 4771b6d65626e3c4499f1500f3a2293bcca6af1e..f36d240c2b855a03aa7a084c3ae085c56658ff65 100644 (file)
@@ -4,6 +4,8 @@
 var Chart = require('./core/core.js')();
 
 require('./core/core.helpers')(Chart);
+require('./helpers/helpers.time')(Chart);
+
 require('./platforms/platform.js')(Chart);
 require('./core/core.canvasHelpers')(Chart);
 require('./core/core.element')(Chart);
index 8d84f1f236a7c6c0e1c3ea73692213270b9452e6..6a67941922f6b97eefd1e8ba02f2349aef08075c 100644 (file)
@@ -141,7 +141,9 @@ module.exports = function(Chart) {
                                ticks.push(lastTick);
 
                                return ticks;
-                       }
+                       },
+
+                       time: helpers.time.generateTicks
                },
 
                /**
diff --git a/src/helpers/helpers.time.js b/src/helpers/helpers.time.js
new file mode 100644 (file)
index 0000000..e055fb2
--- /dev/null
@@ -0,0 +1,196 @@
+'use strict';
+
+var moment = require('moment');
+moment = typeof(moment) === 'function' ? moment : window.moment;
+
+module.exports = function(Chart) {
+
+       var interval = {
+               millisecond: {
+                       size: 1,
+                       steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+               },
+               second: {
+                       size: 1000,
+                       steps: [1, 2, 5, 10, 30]
+               },
+               minute: {
+                       size: 60000,
+                       steps: [1, 2, 5, 10, 30]
+               },
+               hour: {
+                       size: 3600000,
+                       steps: [1, 2, 3, 6, 12]
+               },
+               day: {
+                       size: 86400000,
+                       steps: [1, 2, 5]
+               },
+               week: {
+                       size: 604800000,
+                       maxStep: 4
+               },
+               month: {
+                       size: 2.628e9,
+                       maxStep: 3
+               },
+               quarter: {
+                       size: 7.884e9,
+                       maxStep: 4
+               },
+               year: {
+                       size: 3.154e10,
+                       maxStep: false
+               }
+       };
+
+       /**
+        * Helper for generating axis labels.
+        * @param options {ITimeGeneratorOptions} the options for generation
+        * @param dataRange {IRange} the data range
+        * @param niceRange {IRange} the pretty range to display
+        * @return {Number[]} ticks
+        */
+       function generateTicksNiceRange(options, dataRange, niceRange) {
+               var ticks = [];
+               if (options.maxTicks) {
+                       var stepSize = options.stepSize;
+                       ticks.push(options.min !== undefined ? options.min : niceRange.min);
+                       var cur = moment(niceRange.min);
+                       while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
+                               ticks.push(cur.valueOf());
+                       }
+                       var realMax = options.max || niceRange.max;
+                       if (ticks[ticks.length - 1] !== realMax) {
+                               ticks.push(realMax);
+                       }
+               }
+               return ticks;
+       }
+
+       Chart.helpers = Chart.helpers || {};
+
+       Chart.helpers.time = {
+
+               /**
+                * Helper function to parse time to a moment object
+                * @param axis {TimeAxis} the time axis
+                * @param label {Date|string|number|Moment} The thing to parse
+                * @return {Moment} parsed time
+                */
+               parseTime: function(axis, label) {
+                       var timeOpts = axis.options.time;
+                       if (typeof timeOpts.parser === 'string') {
+                               return moment(label, timeOpts.parser);
+                       }
+                       if (typeof timeOpts.parser === 'function') {
+                               return timeOpts.parser(label);
+                       }
+                       if (typeof label.getMonth === 'function' || typeof label === 'number') {
+                               // Date objects
+                               return moment(label);
+                       }
+                       if (label.isValid && label.isValid()) {
+                               // Moment support
+                               return label;
+                       }
+                       var format = timeOpts.format;
+                       if (typeof format !== 'string' && format.call) {
+                               // Custom parsing (return an instance of moment)
+                               console.warn('options.time.format is deprecated and replaced by options.time.parser.');
+                               return format(label);
+                       }
+                       // Moment format parsing
+                       return moment(label, format);
+               },
+
+               /**
+                * Figure out which is the best unit for the scale
+                * @param minUnit {String} minimum unit to use
+                * @param min {Number} scale minimum
+                * @param max {Number} scale maximum
+                * @return {String} the unit to use
+                */
+               determineUnit: function(minUnit, min, max, maxTicks) {
+                       var units = Object.keys(interval);
+                       var unit;
+                       var numUnits = units.length;
+
+                       for (var i = units.indexOf(minUnit); i < numUnits; i++) {
+                               unit = units[i];
+                               var unitDetails = interval[unit];
+                               var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
+                               if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
+                                       break;
+                               }
+                       }
+
+                       return unit;
+               },
+
+               /**
+                * Determines how we scale the unit
+                * @param min {Number} the scale minimum
+                * @param max {Number} the scale maximum
+                * @param unit {String} the unit determined by the {@see determineUnit} method
+                * @return {Number} the axis step size as a multiple of unit
+                */
+               determineStepSize: function(min, max, unit, maxTicks) {
+                       // Using our unit, figure out what we need to scale as
+                       var unitDefinition = interval[unit];
+                       var unitSizeInMilliSeconds = unitDefinition.size;
+                       var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
+                       var multiplier = 1;
+                       var range = max - min;
+
+                       if (unitDefinition.steps) {
+                               // Have an array of steps
+                               var numSteps = unitDefinition.steps.length;
+                               for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
+                                       multiplier = unitDefinition.steps[i];
+                                       sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+                               }
+                       } else {
+                               while (sizeInUnits > maxTicks && maxTicks > 0) {
+                                       ++multiplier;
+                                       sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+                               }
+                       }
+
+                       return multiplier;
+               },
+
+               /**
+                * @function generateTicks
+                * @param options {ITimeGeneratorOptions} the options for generation
+                * @param dataRange {IRange} the data range
+                * @return {Number[]} ticks
+                */
+               generateTicks: function(options, dataRange) {
+                       var niceMin;
+                       var niceMax;
+                       var isoWeekday = options.isoWeekday;
+                       if (options.unit === 'week' && isoWeekday !== false) {
+                               niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
+                               niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
+                               if (dataRange.max - niceMax > 0) {
+                                       niceMax.add(1, 'week');
+                               }
+                               niceMax = niceMax.valueOf();
+                       } else {
+                               niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
+                               niceMax = moment(dataRange.max).startOf(options.unit);
+                               if (dataRange.max - niceMax > 0) {
+                                       niceMax.add(1, options.unit);
+                               }
+                               niceMax = niceMax.valueOf();
+                       }
+                       return generateTicksNiceRange(options, dataRange, {
+                               min: niceMin,
+                               max: niceMax
+                       });
+               }
+
+       };
+
+};
index 0b356b3c100b06dad4e4e63ede5699dc48f50a38..1d726e1b35997c5382e95f264bcd1102349bc3cc 100644 (file)
@@ -7,44 +7,7 @@ moment = typeof(moment) === 'function' ? moment : window.moment;
 module.exports = function(Chart) {
 
        var helpers = Chart.helpers;
-       var interval = {
-               millisecond: {
-                       size: 1,
-                       steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
-               },
-               second: {
-                       size: 1000,
-                       steps: [1, 2, 5, 10, 30]
-               },
-               minute: {
-                       size: 60000,
-                       steps: [1, 2, 5, 10, 30]
-               },
-               hour: {
-                       size: 3600000,
-                       steps: [1, 2, 3, 6, 12]
-               },
-               day: {
-                       size: 86400000,
-                       steps: [1, 2, 5]
-               },
-               week: {
-                       size: 604800000,
-                       maxStep: 4
-               },
-               month: {
-                       size: 2.628e9,
-                       maxStep: 3
-               },
-               quarter: {
-                       size: 7.884e9,
-                       maxStep: 4
-               },
-               year: {
-                       size: 3.154e10,
-                       maxStep: false
-               }
-       };
+       var timeHelpers = helpers.time;
 
        var defaultConfig = {
                position: 'bottom',
@@ -76,149 +39,6 @@ module.exports = function(Chart) {
                }
        };
 
-       /**
-        * Helper function to parse time to a moment object
-        * @param axis {TimeAxis} the time axis
-        * @param label {Date|string|number|Moment} The thing to parse
-        * @return {Moment} parsed time
-        */
-       function parseTime(axis, label) {
-               var timeOpts = axis.options.time;
-               if (typeof timeOpts.parser === 'string') {
-                       return moment(label, timeOpts.parser);
-               }
-               if (typeof timeOpts.parser === 'function') {
-                       return timeOpts.parser(label);
-               }
-               if (typeof label.getMonth === 'function' || typeof label === 'number') {
-                       // Date objects
-                       return moment(label);
-               }
-               if (label.isValid && label.isValid()) {
-                       // Moment support
-                       return label;
-               }
-               var format = timeOpts.format;
-               if (typeof format !== 'string' && format.call) {
-                       // Custom parsing (return an instance of moment)
-                       console.warn('options.time.format is deprecated and replaced by options.time.parser.');
-                       return format(label);
-               }
-               // Moment format parsing
-               return moment(label, format);
-       }
-
-       /**
-        * Figure out which is the best unit for the scale
-        * @param minUnit {String} minimum unit to use
-        * @param min {Number} scale minimum
-        * @param max {Number} scale maximum
-        * @return {String} the unit to use
-        */
-       function determineUnit(minUnit, min, max, maxTicks) {
-               var units = Object.keys(interval);
-               var unit;
-               var numUnits = units.length;
-
-               for (var i = units.indexOf(minUnit); i < numUnits; i++) {
-                       unit = units[i];
-                       var unitDetails = interval[unit];
-                       var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
-                       if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
-                               break;
-                       }
-               }
-
-               return unit;
-       }
-
-       /**
-        * Determines how we scale the unit
-        * @param min {Number} the scale minimum
-        * @param max {Number} the scale maximum
-        * @param unit {String} the unit determined by the {@see determineUnit} method
-        * @return {Number} the axis step size as a multiple of unit
-        */
-       function determineStepSize(min, max, unit, maxTicks) {
-               // Using our unit, figoure out what we need to scale as
-               var unitDefinition = interval[unit];
-               var unitSizeInMilliSeconds = unitDefinition.size;
-               var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
-               var multiplier = 1;
-               var range = max - min;
-
-               if (unitDefinition.steps) {
-                       // Have an array of steps
-                       var numSteps = unitDefinition.steps.length;
-                       for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
-                               multiplier = unitDefinition.steps[i];
-                               sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
-                       }
-               } else {
-                       while (sizeInUnits > maxTicks && maxTicks > 0) {
-                               ++multiplier;
-                               sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
-                       }
-               }
-
-               return multiplier;
-       }
-
-       /**
-        * Helper for generating axis labels.
-        * @param options {ITimeGeneratorOptions} the options for generation
-        * @param dataRange {IRange} the data range
-        * @param niceRange {IRange} the pretty range to display
-        * @return {Number[]} ticks
-        */
-       function generateTicks(options, dataRange, niceRange) {
-               var ticks = [];
-               if (options.maxTicks) {
-                       var stepSize = options.stepSize;
-                       ticks.push(options.min !== undefined ? options.min : niceRange.min);
-                       var cur = moment(niceRange.min);
-                       while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
-                               ticks.push(cur.valueOf());
-                       }
-                       var realMax = options.max || niceRange.max;
-                       if (ticks[ticks.length - 1] !== realMax) {
-                               ticks.push(realMax);
-                       }
-               }
-               return ticks;
-       }
-
-       /**
-        * @function Chart.Ticks.generators.time
-        * @param options {ITimeGeneratorOptions} the options for generation
-        * @param dataRange {IRange} the data range
-        * @return {Number[]} ticks
-        */
-       Chart.Ticks.generators.time = function(options, dataRange) {
-               var niceMin;
-               var niceMax;
-               var isoWeekday = options.isoWeekday;
-               if (options.unit === 'week' && isoWeekday !== false) {
-                       niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
-                       niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
-                       if (dataRange.max - niceMax > 0) {
-                               niceMax.add(1, 'week');
-                       }
-                       niceMax = niceMax.valueOf();
-               } else {
-                       niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
-                       niceMax = moment(dataRange.max).startOf(options.unit);
-                       if (dataRange.max - niceMax > 0) {
-                               niceMax.add(1, options.unit);
-                       }
-                       niceMax = niceMax.valueOf();
-               }
-               return generateTicks(options, dataRange, {
-                       min: niceMin,
-                       max: niceMax
-               });
-       };
-
        var TimeScale = Chart.Scale.extend({
                initialize: function() {
                        if (!moment) {
@@ -244,7 +64,7 @@ module.exports = function(Chart) {
                        var timestamp;
 
                        helpers.each(chartData.labels, function(label, labelIndex) {
-                               var labelMoment = parseTime(me, label);
+                               var labelMoment = timeHelpers.parseTime(me, label);
 
                                if (labelMoment.isValid()) {
                                        // We need to round the time
@@ -267,7 +87,7 @@ module.exports = function(Chart) {
                                if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
                                        // We have potential point data, so we need to parse this
                                        helpers.each(dataset.data, function(value, dataIndex) {
-                                               var dataMoment = parseTime(me, me.getRightValue(value));
+                                               var dataMoment = timeHelpers.parseTime(me, me.getRightValue(value));
 
                                                if (dataMoment.isValid()) {
                                                        if (timeOpts.round) {
@@ -302,7 +122,7 @@ module.exports = function(Chart) {
                        var dataMax = me.dataMax;
 
                        if (timeOpts.min) {
-                               var minMoment = parseTime(me, timeOpts.min);
+                               var minMoment = timeHelpers.parseTime(me, timeOpts.min);
                                if (timeOpts.round) {
                                        minMoment.round(timeOpts.round);
                                }
@@ -310,15 +130,15 @@ module.exports = function(Chart) {
                        }
 
                        if (timeOpts.max) {
-                               maxTimestamp = parseTime(me, timeOpts.max).valueOf();
+                               maxTimestamp = timeHelpers.parseTime(me, timeOpts.max).valueOf();
                        }
 
                        var maxTicks = me.getLabelCapacity(minTimestamp || dataMin);
-                       var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
+                       var unit = timeOpts.unit || timeHelpers.determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
                        me.displayFormat = timeOpts.displayFormats[unit];
 
-                       var stepSize = timeOpts.stepSize || determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
-                       me.ticks = Chart.Ticks.generators.time({
+                       var stepSize = timeOpts.stepSize || timeHelpers.determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
+                       me.ticks = timeHelpers.generateTicks({
                                maxTicks: maxTicks,
                                min: minTimestamp,
                                max: maxTimestamp,
@@ -347,7 +167,7 @@ module.exports = function(Chart) {
 
                        // Format nicely
                        if (me.options.time.tooltipFormat) {
-                               label = parseTime(me, label).format(me.options.time.tooltipFormat);
+                               label = timeHelpers.parseTime(me, label).format(me.options.time.tooltipFormat);
                        }
 
                        return label;
@@ -393,7 +213,7 @@ module.exports = function(Chart) {
                        if (offset === null) {
                                if (!value || !value.isValid) {
                                        // not already a moment object
-                                       value = parseTime(me, me.getRightValue(value));
+                                       value = timeHelpers.parseTime(me, me.getRightValue(value));
                                }
 
                                if (value && value.isValid && value.isValid()) {