From c2cd00ca90a2a1e96c4ee4891b43d763c67e4658 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Fri, 19 Jun 2020 07:21:39 -0700 Subject: [PATCH] Split time scale into time and timeseries (#7525) * Split time scale into time and timeseries * Address comment --- docs/docs/axes/cartesian/time.md | 27 +- docs/docs/axes/cartesian/timeseries.md | 25 ++ docs/docs/getting-started/v3-migration.md | 2 + src/helpers/helpers.collection.js | 22 + src/scales/index.js | 1 + src/scales/scale.time.js | 408 +++++++----------- src/scales/scale.timeseries.js | 131 ++++++ .../fixtures/scale.time/source-auto-series.js | 5 +- .../source-data-series-offset-min-max.js | 5 +- .../fixtures/scale.time/source-data-series.js | 5 +- .../source-labels-series-offset-min-max.js | 5 +- .../scale.time/source-labels-series.js | 5 +- .../scale.time/ticks-reverse-series-max.js | 3 +- .../ticks-reverse-series-min-max.js | 3 +- .../scale.time/ticks-reverse-series-min.js | 3 +- .../scale.time/ticks-reverse-series.js | 3 +- test/specs/scale.time.tests.js | 29 +- 17 files changed, 360 insertions(+), 322 deletions(-) create mode 100644 docs/docs/axes/cartesian/timeseries.md create mode 100644 src/scales/scale.timeseries.js diff --git a/docs/docs/axes/cartesian/time.md b/docs/docs/axes/cartesian/time.md index 61b1b2cf2..7254725b1 100644 --- a/docs/docs/axes/cartesian/time.md +++ b/docs/docs/axes/cartesian/time.md @@ -2,7 +2,7 @@ title: Time Cartesian Axis --- -The time scale is used to display times and dates. When building its ticks, it will automatically calculate the most comfortable unit base on the size of the scale. +The time scale is used to display times and dates. Data are spread according to the amount of time between data points. When building its ticks, it will automatically calculate the most comfortable unit base on the size of the scale. ## Date Adapters @@ -25,7 +25,6 @@ The following options are provided by the time scale. You may also set options p | Name | Type | Default | Description | ---- | ---- | ------- | ----------- | `adapters.date` | `object` | `{}` | Options for adapter for external date library if that adapter needs or supports options -| `distribution` | `string` | `'linear'` | How data is plotted. [more...](#scale-distribution) | `bounds` | `string` | `'data'` | Determines the scale bounds. [more...](#scale-bounds) | `ticks.source` | `string` | `'auto'` | How ticks are generated. [more...](#ticks-source) | `time.displayFormats` | `object` | | Sets how different time units are displayed. [more...](#display-formats) @@ -107,30 +106,6 @@ var chart = new Chart(ctx, { }); ``` -### Scale Distribution - -The `distribution` property controls the data distribution along the scale: - -* `'linear'`: data are spread according to their time (distances can vary) -* `'series'`: data are spread at the same distance from each other - -```javascript -var chart = new Chart(ctx, { - type: 'line', - data: data, - options: { - scales: { - x: { - type: 'time', - distribution: 'series' - } - } - } -}); -``` - -When the scale is in `series` mode, the data indices are expected to be unique, sorted, and consistent across datasets. - ### Scale Bounds The `bounds` property controls the scale boundary strategy (bypassed by `min`/`max` time options). diff --git a/docs/docs/axes/cartesian/timeseries.md b/docs/docs/axes/cartesian/timeseries.md new file mode 100644 index 000000000..986c4dbff --- /dev/null +++ b/docs/docs/axes/cartesian/timeseries.md @@ -0,0 +1,25 @@ +--- +title: Time Series Axis +--- + +The time series scale extends from the time scale and supports all the same options. However, for the time series scale, each data point is spread equidistant. Also, the data indices are expected to be unique, sorted, and consistent across datasets. + +## Example + +```javascript +var chart = new Chart(ctx, { + type: 'line', + data: data, + options: { + scales: { + x: { + type: 'timeseries', + } + } + } +}); +``` + +## More details + +Please see [the time scale documentation](./time.md) for all other details. diff --git a/docs/docs/getting-started/v3-migration.md b/docs/docs/getting-started/v3-migration.md index c93c0fb01..3f0d3f5f5 100644 --- a/docs/docs/getting-started/v3-migration.md +++ b/docs/docs/getting-started/v3-migration.md @@ -156,6 +156,8 @@ options: { } ``` +Also, the time scale option `distribution: 'series'` was removed and a new scale type `timeseries` was introduced in its place. + #### Animations Animation system was completely rewritten in Chart.js v3. Each property can now be animated separately. Please see [animations](../configuration/animations.mdx) docs for details. diff --git a/src/helpers/helpers.collection.js b/src/helpers/helpers.collection.js index 95ee06b62..2671810c2 100644 --- a/src/helpers/helpers.collection.js +++ b/src/helpers/helpers.collection.js @@ -162,3 +162,25 @@ export function unlistenArrayEvents(array, listener) { delete array._chartjs; } + +/** + * @param {Array} items + */ +export function _arrayUnique(items) { + const set = new Set(); + let i, ilen; + + for (i = 0, ilen = items.length; i < ilen; ++i) { + set.add(items[i]); + } + + if (set.size === ilen) { + return items; + } + + const result = []; + set.forEach(item => { + result.push(item); + }); + return result; +} diff --git a/src/scales/index.js b/src/scales/index.js index a3f8c34cf..bc81fda45 100644 --- a/src/scales/index.js +++ b/src/scales/index.js @@ -3,3 +3,4 @@ export {default as LinearScale} from './scale.linear'; export {default as LogarithmicScale} from './scale.logarithmic'; export {default as RadialLinearScale} from './scale.radialLinear'; export {default as TimeScale} from './scale.time'; +export {default as TimeSeriesScale} from './scale.timeseries'; diff --git a/src/scales/scale.time.js b/src/scales/scale.time.js index 322a7c706..2f82656de 100644 --- a/src/scales/scale.time.js +++ b/src/scales/scale.time.js @@ -2,7 +2,7 @@ import adapters from '../core/core.adapters'; import {isFinite, isNullOrUndef, mergeIf, valueOrDefault} from '../helpers/helpers.core'; import {toRadians} from '../helpers/helpers.math'; import Scale from '../core/core.scale'; -import {_filterBetween, _lookup, _lookupByKey} from '../helpers/helpers.collection'; +import {_arrayUnique, _filterBetween, _lookup, _lookupByKey} from '../helpers/helpers.collection'; /** * @typedef { import("../core/core.adapters").Unit } Unit @@ -40,31 +40,10 @@ function sorter(a, b) { return a - b; } -/** - * @param {number[]} items - */ -function arrayUnique(items) { - const set = new Set(); - let i, ilen; - - for (i = 0, ilen = items.length; i < ilen; ++i) { - set.add(items[i]); - } - - if (set.size === ilen) { - return items; - } - - const result = []; - set.forEach(item => { - result.push(item); - }); - return result; -} - /** * @param {TimeScale} scale * @param {*} input + * @return {number} */ function parse(scale, input) { if (isNullOrUndef(input)) { @@ -100,133 +79,6 @@ function parse(scale, input) { return +value; } -/** - * @param {TimeScale} scale - */ -function getDataTimestamps(scale) { - const isSeries = scale.options.distribution === 'series'; - let timestamps = scale._cache.data || []; - let i, ilen; - - if (timestamps.length) { - return timestamps; - } - - const metas = scale.getMatchingVisibleMetas(); - - if (isSeries && metas.length) { - return metas[0].controller.getAllParsedValues(scale); - } - - for (i = 0, ilen = metas.length; i < ilen; ++i) { - timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(scale)); - } - - // We can not assume data is in order or unique - not even for single dataset - // It seems to be somewhat faster to do sorting first - return (scale._cache.data = arrayUnique(timestamps.sort(sorter))); -} - -/** - * @param {TimeScale} scale - */ -function getLabelTimestamps(scale) { - const isSeries = scale.options.distribution === 'series'; - const timestamps = scale._cache.labels || []; - let i, ilen; - - if (timestamps.length) { - return timestamps; - } - - const labels = scale.getLabels(); - for (i = 0, ilen = labels.length; i < ilen; ++i) { - timestamps.push(parse(scale, labels[i])); - } - - // We could assume labels are in order and unique - but let's not - return (scale._cache.labels = isSeries ? timestamps : arrayUnique(timestamps.sort(sorter))); -} - -/** - * @param {TimeScale} scale - */ -function getAllTimestamps(scale) { - let timestamps = scale._cache.all || []; - - if (timestamps.length) { - return timestamps; - } - - const data = getDataTimestamps(scale); - const label = getLabelTimestamps(scale); - if (data.length && label.length) { - // If combining labels and data (data might not contain all labels), - // we need to recheck uniqueness and sort - timestamps = arrayUnique(data.concat(label).sort(sorter)); - } else { - timestamps = data.length ? data : label; - } - timestamps = scale._cache.all = timestamps; - - return timestamps; -} - -/** - * Returns an array of {time, pos} objects used to interpolate a specific `time` or position - * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is - * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other - * extremity (left + width or top + height). Note that it would be more optimized to directly - * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need - * to create the lookup table. The table ALWAYS contains at least two items: min and max. - * - * @param {number[]} timestamps - timestamps sorted from lowest to highest. - * @param {string} distribution - If 'linear', timestamps will be spread linearly along the min - * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}. - * If 'series', timestamps will be positioned at the same distance from each other. In this - * case, only timestamps that break the time linearity are registered, meaning that in the - * best case, all timestamps are linear, the table contains only min and max. - * @param {number[]} timestamps - * @param {number} min - * @param {number} max - * @param {string} distribution - * @return {object[]} - */ -function buildLookupTable(timestamps, min, max, distribution) { - if (distribution === 'linear' || !timestamps.length) { - return [ - {time: min, pos: 0}, - {time: max, pos: 1} - ]; - } - - const table = []; - const items = [min]; - let i, ilen, prev, curr, next; - - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - curr = timestamps[i]; - if (curr > min && curr < max) { - items.push(curr); - } - } - - items.push(max); - - for (i = 0, ilen = items.length; i < ilen; ++i) { - next = items[i + 1]; - prev = items[i - 1]; - curr = items[i]; - - // only add points that breaks the scale linearity - if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) { - table.push({time: curr, pos: i / (ilen - 1)}); - } - } - - return table; -} - /** * Linearly interpolates the given source `value` using the table items `skey` values and * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos') @@ -321,64 +173,6 @@ function addTick(timestamps, ticks, time) { ticks[timestamp] = true; } -/** - * Generates a maximum of `capacity` timestamps between min and max, rounded to the - * `minor` unit using the given scale time `options`. - * Important: this method can return ticks outside the min and max range, it's the - * responsibility of the calling code to clamp values if needed. - * @param {TimeScale} scale - */ -function generate(scale) { - const adapter = scale._adapter; - const min = scale.min; - const max = scale.max; - const options = scale.options; - const timeOpts = options.time; - // @ts-ignore - const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, scale._getLabelCapacity(min)); - const stepSize = valueOrDefault(timeOpts.stepSize, 1); - const weekday = minor === 'week' ? timeOpts.isoWeekday : false; - const ticks = {}; - let first = min; - let time; - - // For 'week' unit, handle the first day of week option - if (weekday) { - first = +adapter.startOf(first, 'isoWeek', weekday); - } - - // Align first ticks on unit - first = +adapter.startOf(first, weekday ? 'day' : minor); - - // Prevent browser from freezing in case user options request millions of milliseconds - if (adapter.diff(max, min, minor) > 100000 * stepSize) { - throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); - } - - if (scale.options.ticks.source === 'data') { - // need to make sure ticks are in data in this case - const timestamps = getDataTimestamps(scale); - - for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { - addTick(timestamps, ticks, time); - } - - if (time === max || options.bounds === 'ticks') { - addTick(timestamps, ticks, time); - } - } else { - for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { - ticks[time] = true; - } - - if (time === max || options.bounds === 'ticks') { - ticks[time] = true; - } - } - - return Object.keys(ticks).map(x => +x); -} - /** * Returns the start and end offsets from edges in the form of {start, end} * where each value is a relative width to the scale and ranges between 0 and 1. @@ -464,50 +258,7 @@ function ticksFromTimestamps(scale, values, majorUnit) { return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); } -/** - * @param {TimeScale} scale - */ -function getTimestampsForTicks(scale) { - if (scale.options.ticks.source === 'labels') { - return getLabelTimestamps(scale); - } - - return generate(scale); -} - -/** - * @param {TimeScale} scale - */ -function getTimestampsForTable(scale) { - return scale.options.distribution === 'series' - ? getAllTimestamps(scale) - : [scale.min, scale.max]; -} - -/** - * @param {TimeScale} scale - */ -function getLabelBounds(scale) { - const arr = getLabelTimestamps(scale); - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - - if (arr.length) { - min = arr[0]; - max = arr[arr.length - 1]; - } - return {min, max}; -} - const defaultConfig = { - /** - * Data distribution along the scale: - * - 'linear': data are spread according to their time (distances can vary), - * - 'series': data are spread at the same distance from each other. - * @see https://github.com/chartjs/Chart.js/pull/4507 - * @since 2.7.0 - */ - distribution: 'linear', /** * Scale boundary strategy (bypassed by min/max time options) @@ -586,7 +337,7 @@ class TimeScale extends Scale { /** * @param {*} raw - * @param {number} index + * @param {number?} [index] * @return {number} */ parse(raw, index) { // eslint-disable-line no-unused-vars @@ -604,6 +355,13 @@ class TimeScale extends Scale { }; } + /** + * @protected + */ + getTimestampsForTable() { + return [this.min, this.max]; + } + determineDataLimits() { const me = this; const options = me.options; @@ -627,7 +385,7 @@ class TimeScale extends Scale { // If we have user provided `min` and `max` labels / data bounds can be ignored if (!minDefined || !maxDefined) { // Labels are always considered, when user did not force bounds - _applyBounds(getLabelBounds(me)); + _applyBounds(me._getLabelBounds()); // If `bounds` is `'ticks'` and `ticks.source` is `'labels'`, // data bounds are ignored (and don't need to be determined) @@ -644,6 +402,21 @@ class TimeScale extends Scale { me.max = Math.max(min + 1, max); } + /** + * @private + */ + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return {min, max}; + } + /** * @return {object[]} */ @@ -652,8 +425,7 @@ class TimeScale extends Scale { const options = me.options; const timeOpts = options.time; const tickOpts = options.ticks; - const distribution = options.distribution; - const timestamps = getTimestampsForTicks(me); + const timestamps = tickOpts.source === 'labels' ? me.getLabelTimestamps() : me._generate(); if (options.bounds === 'ticks' && timestamps.length) { me.min = me._userMin || timestamps[0]; @@ -673,7 +445,7 @@ class TimeScale extends Scale { : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max)); me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined : determineMajorUnit(me._unit); - me._table = buildLookupTable(getTimestampsForTable(me), min, max, distribution); + me._table = me.buildLookupTable(me.getTimestampsForTable(), min, max); me._offsets = computeOffsets(me._table, timestamps, min, max, options); if (options.reverse) { @@ -683,6 +455,86 @@ class TimeScale extends Scale { return ticksFromTimestamps(me, ticks, me._majorUnit); } + /** + * Generates a maximum of `capacity` timestamps between min and max, rounded to the + * `minor` unit using the given scale time `options`. + * Important: this method can return ticks outside the min and max range, it's the + * responsibility of the calling code to clamp values if needed. + * @private + */ + _generate() { + const me = this; + const adapter = me._adapter; + const min = me.min; + const max = me.max; + const options = me.options; + const timeOpts = options.time; + // @ts-ignore + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, me._getLabelCapacity(min)); + const stepSize = valueOrDefault(timeOpts.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const ticks = {}; + let first = min; + let time; + + // For 'week' unit, handle the first day of week option + if (weekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + + // Align first ticks on unit + first = +adapter.startOf(first, weekday ? 'day' : minor); + + // Prevent browser from freezing in case user options request millions of milliseconds + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + + if (me.options.ticks.source === 'data') { + // need to make sure ticks are in data in this case + const timestamps = me.getDataTimestamps(); + + for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { + addTick(timestamps, ticks, time); + } + + if (time === max || options.bounds === 'ticks') { + addTick(timestamps, ticks, time); + } + } else { + for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { + ticks[time] = true; + } + + if (time === max || options.bounds === 'ticks') { + ticks[time] = true; + } + } + + return Object.keys(ticks).map(x => +x); + } + + /** + * Returns an array of {time, pos} objects used to interpolate a specific `time` or position + * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is + * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other + * extremity (left + width or top + height). Note that it would be more optimized to directly + * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need + * to create the lookup table. The table ALWAYS contains at least two items: min and max. + * + * @param {number[]} timestamps - timestamps sorted from lowest to highest. + * @param {number} min + * @param {number} max + * @return {object[]} + * @protected + */ + buildLookupTable(timestamps, min, max) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + /** * @param {number} value * @return {string} @@ -795,6 +647,50 @@ class TimeScale extends Scale { const capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h) - 1; return capacity > 0 ? capacity : 1; } + + /** + * @protected + */ + getDataTimestamps() { + const me = this; + let timestamps = me._cache.data || []; + let i, ilen; + + if (timestamps.length) { + return timestamps; + } + + const metas = me.getMatchingVisibleMetas(); + + for (i = 0, ilen = metas.length; i < ilen; ++i) { + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(me)); + } + + // We can not assume data is in order or unique - not even for single dataset + // It seems to be somewhat faster to do sorting first + return (me._cache.data = _arrayUnique(timestamps.sort(sorter))); + } + + /** + * @protected + */ + getLabelTimestamps() { + const me = this; + const timestamps = me._cache.labels || []; + let i, ilen; + + if (timestamps.length) { + return timestamps; + } + + const labels = me.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(parse(me, labels[i])); + } + + // We could assume labels are in order and unique - but let's not + return (me._cache.labels = _arrayUnique(timestamps.sort(sorter))); + } } TimeScale.id = 'time'; diff --git a/src/scales/scale.timeseries.js b/src/scales/scale.timeseries.js new file mode 100644 index 000000000..009d8dfb1 --- /dev/null +++ b/src/scales/scale.timeseries.js @@ -0,0 +1,131 @@ +import TimeScale from './scale.time'; +import {_arrayUnique} from '../helpers/helpers.collection'; + +/** + * @param {number} a + * @param {number} b + */ +function sorter(a, b) { + return a - b; +} + +class TimeSeriesScale extends TimeScale { + + /** + * Returns all timestamps + * @protected + */ + getTimestampsForTable() { + const me = this; + let timestamps = me._cache.all || []; + + if (timestamps.length) { + return timestamps; + } + + const data = me.getDataTimestamps(); + const label = me.getLabelTimestamps(); + if (data.length && label.length) { + // If combining labels and data (data might not contain all labels), + // we need to recheck uniqueness and sort + timestamps = _arrayUnique(data.concat(label).sort(sorter)); + } else { + timestamps = data.length ? data : label; + } + timestamps = me._cache.all = timestamps; + + return timestamps; + } + + /** + * Returns an array of {time, pos} objects used to interpolate a specific `time` or position + * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is + * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other + * extremity (left + width or top + height). Note that it would be more optimized to directly + * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need + * to create the lookup table. The table ALWAYS contains at least two items: min and max. + * + * @param {number[]} timestamps - timestamps sorted from lowest to highest. + * @param {number} min + * @param {number} max + * @return {object[]} + * @protected + */ + buildLookupTable(timestamps, min, max) { + if (!timestamps.length) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + + const table = []; + const items = [min]; + let i, ilen, prev, curr, next; + + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr > min && curr < max) { + items.push(curr); + } + } + + items.push(max); + + for (i = 0, ilen = items.length; i < ilen; ++i) { + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + + // only add points that breaks the scale linearity + if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) { + table.push({time: curr, pos: i / (ilen - 1)}); + } + } + + return table; + } + + /** + * @protected + */ + getDataTimestamps() { + const me = this; + const timestamps = me._cache.data || []; + + if (timestamps.length) { + return timestamps; + } + + const metas = me.getMatchingVisibleMetas(); + return (me._cache.data = metas.length ? metas[0].controller.getAllParsedValues(me) : []); + } + + /** + * @protected + */ + getLabelTimestamps() { + const me = this; + const timestamps = me._cache.labels || []; + let i, ilen; + + if (timestamps.length) { + return timestamps; + } + + const labels = me.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(me.parse(labels[i])); + } + + // We could assume labels are in order and unique - but let's not + return (me._cache.labels = timestamps); + } +} + +TimeSeriesScale.id = 'timeseries'; + +// INTERNAL: default options, registered in src/index.js +TimeSeriesScale.defaults = TimeScale.defaults; + +export default TimeSeriesScale; diff --git a/test/fixtures/scale.time/source-auto-series.js b/test/fixtures/scale.time/source-auto-series.js index 796258123..205a9cfca 100644 --- a/test/fixtures/scale.time/source-auto-series.js +++ b/test/fixtures/scale.time/source-auto-series.js @@ -9,15 +9,14 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', time: { parser: 'YYYY', unit: 'year' }, ticks: { source: 'auto' - }, - distribution: 'series' + } }, y: { display: false diff --git a/test/fixtures/scale.time/source-data-series-offset-min-max.js b/test/fixtures/scale.time/source-data-series-offset-min-max.js index e651864b3..7a08941f8 100644 --- a/test/fixtures/scale.time/source-data-series-offset-min-max.js +++ b/test/fixtures/scale.time/source-data-series-offset-min-max.js @@ -9,7 +9,7 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', min: '2012', max: '2051', offset: true, @@ -18,8 +18,7 @@ module.exports = { }, ticks: { source: 'data' - }, - distribution: 'series' + } }, y: { display: false diff --git a/test/fixtures/scale.time/source-data-series.js b/test/fixtures/scale.time/source-data-series.js index 15f74a197..a9b6f28da 100644 --- a/test/fixtures/scale.time/source-data-series.js +++ b/test/fixtures/scale.time/source-data-series.js @@ -9,15 +9,14 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', time: { parser: 'YYYY', unit: 'year' }, ticks: { source: 'data' - }, - distribution: 'series' + } }, y: { display: false diff --git a/test/fixtures/scale.time/source-labels-series-offset-min-max.js b/test/fixtures/scale.time/source-labels-series-offset-min-max.js index 612fd5378..17c8784fb 100644 --- a/test/fixtures/scale.time/source-labels-series-offset-min-max.js +++ b/test/fixtures/scale.time/source-labels-series-offset-min-max.js @@ -9,7 +9,7 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', min: '2012', max: '2051', offset: true, @@ -18,8 +18,7 @@ module.exports = { }, ticks: { source: 'labels' - }, - distribution: 'series' + } }, y: { display: false diff --git a/test/fixtures/scale.time/source-labels-series.js b/test/fixtures/scale.time/source-labels-series.js index f5b22e244..55e5486ed 100644 --- a/test/fixtures/scale.time/source-labels-series.js +++ b/test/fixtures/scale.time/source-labels-series.js @@ -9,15 +9,14 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', time: { parser: 'YYYY', unit: 'year' }, ticks: { source: 'labels' - }, - distribution: 'series' + } }, y: { display: false diff --git a/test/fixtures/scale.time/ticks-reverse-series-max.js b/test/fixtures/scale.time/ticks-reverse-series-max.js index 72840e07d..7b893a784 100644 --- a/test/fixtures/scale.time/ticks-reverse-series-max.js +++ b/test/fixtures/scale.time/ticks-reverse-series-max.js @@ -9,12 +9,11 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', max: '2050', time: { parser: 'YYYY' }, - distribution: 'series', reverse: true, ticks: { source: 'labels' diff --git a/test/fixtures/scale.time/ticks-reverse-series-min-max.js b/test/fixtures/scale.time/ticks-reverse-series-min-max.js index 4e67f7278..e3216c668 100644 --- a/test/fixtures/scale.time/ticks-reverse-series-min-max.js +++ b/test/fixtures/scale.time/ticks-reverse-series-min-max.js @@ -9,13 +9,12 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', min: '2012', max: '2050', time: { parser: 'YYYY' }, - distribution: 'series', reverse: true, ticks: { source: 'labels' diff --git a/test/fixtures/scale.time/ticks-reverse-series-min.js b/test/fixtures/scale.time/ticks-reverse-series-min.js index 89ddb832e..fbd62b161 100644 --- a/test/fixtures/scale.time/ticks-reverse-series-min.js +++ b/test/fixtures/scale.time/ticks-reverse-series-min.js @@ -9,12 +9,11 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', min: '2012', time: { parser: 'YYYY' }, - distribution: 'series', reverse: true, ticks: { source: 'labels' diff --git a/test/fixtures/scale.time/ticks-reverse-series.js b/test/fixtures/scale.time/ticks-reverse-series.js index ba2dd3e21..ce9628e80 100644 --- a/test/fixtures/scale.time/ticks-reverse-series.js +++ b/test/fixtures/scale.time/ticks-reverse-series.js @@ -9,11 +9,10 @@ module.exports = { options: { scales: { x: { - type: 'time', + type: 'timeseries', time: { parser: 'YYYY' }, - distribution: 'series', reverse: true, ticks: { source: 'labels' diff --git a/test/specs/scale.time.tests.js b/test/specs/scale.time.tests.js index fe172fd39..4d15aa38f 100644 --- a/test/specs/scale.time.tests.js +++ b/test/specs/scale.time.tests.js @@ -79,7 +79,6 @@ describe('Time scale tests', function() { beginAtZero: false, scaleLabel: Chart.defaults.scale.scaleLabel, bounds: 'data', - distribution: 'linear', adapters: {}, ticks: { minRotation: 0, @@ -786,8 +785,8 @@ describe('Time scale tests', function() { }); }); - describe('when distribution', function() { - describe('is "series"', function() { + describe('when scale type', function() { + describe('is "timeseries"', function() { beforeEach(function() { this.chart = window.acquireChart({ type: 'line', @@ -798,11 +797,10 @@ describe('Time scale tests', function() { options: { scales: { x: { - type: 'time', + type: 'timeseries', time: { parser: 'YYYY' }, - distribution: 'series', ticks: { source: 'labels' } @@ -870,7 +868,7 @@ describe('Time scale tests', function() { expect(scale.getPixelForValue(moment('2042').valueOf())).toBeCloseToPixel(start + slice * 5); }); }); - describe('is "linear"', function() { + describe('is "time"', function() { beforeEach(function() { this.chart = window.acquireChart({ type: 'line', @@ -885,7 +883,6 @@ describe('Time scale tests', function() { time: { parser: 'YYYY' }, - distribution: 'linear', ticks: { source: 'labels' } @@ -1087,8 +1084,8 @@ describe('Time scale tests', function() { }); ['auto', 'data', 'labels'].forEach(function(source) { - ['series', 'linear'].forEach(function(distribution) { - describe('when ticks.source is "' + source + '" and distribution is "' + distribution + '"', function() { + ['timeseries', 'time'].forEach(function(type) { + describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() { beforeEach(function() { this.chart = window.acquireChart({ type: 'line', @@ -1099,15 +1096,14 @@ describe('Time scale tests', function() { options: { scales: { x: { - type: 'time', + type: type, time: { parser: 'YYYY', unit: 'year' }, ticks: { source: source - }, - distribution: distribution + } } } } @@ -1154,8 +1150,8 @@ describe('Time scale tests', function() { }); ['data', 'labels'].forEach(function(source) { - ['series', 'linear'].forEach(function(distribution) { - describe('when ticks.source is "' + source + '" and distribution is "' + distribution + '"', function() { + ['timeseries', 'time'].forEach(function(type) { + describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() { beforeEach(function() { this.chart = window.acquireChart({ type: 'line', @@ -1167,14 +1163,13 @@ describe('Time scale tests', function() { scales: { x: { id: 'x', - type: 'time', + type: type, time: { parser: 'YYYY' }, ticks: { source: source - }, - distribution: distribution + } } } } -- 2.47.2