diff --git a/packages/core/demo/data/index.ts b/packages/core/demo/data/index.ts index 9dca31a924..475830a54d 100644 --- a/packages/core/demo/data/index.ts +++ b/packages/core/demo/data/index.ts @@ -488,6 +488,36 @@ let allDemoGroups = [ data: timeSeriesAxisDemos.lineTimeSeriesNoExtendedDomainData, options: timeSeriesAxisDemos.lineTimeSeriesNoExtendedDomainOptions, chartType: chartTypes.LineChart + }, + { + data: timeSeriesAxisDemos.lineTimeSeriesDataTwoIdenticalLabels, + options: timeSeriesAxisDemos.lineTimeSeriesTwoIdenticalLabelsOptions, + chartType: chartTypes.LineChart + }, + { + data: timeSeriesAxisDemos.lineTimeSeriesDataAllLabelsInPrimaryFormat, + options: timeSeriesAxisDemos.lineTimeSeriesAllLabelsInPrimaryFormatOptions, + chartType: chartTypes.LineChart + } + ] + }, + { + title: "Radar", + demos: [ + { + data: radarDemos.radarData, + options: radarDemos.radarOptions, + chartType: chartTypes.RadarChart + }, + { + data: radarDemos.radarWithMissingDataData, + options: radarDemos.radarWithMissingDataOptions, + chartType: chartTypes.RadarChart + }, + { + data: radarDemos.radarDenseData, + options: radarDemos.radarDenseOptions, + chartType: chartTypes.RadarChart } ] }, diff --git a/packages/core/demo/data/time-series-axis.ts b/packages/core/demo/data/time-series-axis.ts index e0bc584146..a1f8927fbc 100644 --- a/packages/core/demo/data/time-series-axis.ts +++ b/packages/core/demo/data/time-series-axis.ts @@ -351,3 +351,70 @@ export const lineTimeSeriesNoExtendedDomainOptions = { addSpaceOnEdges: 0 } }; + +// bug two identical labels +export const lineTimeSeriesDataTwoIdenticalLabels = { + labels: ["Qty"], + datasets: [ + { + label: "Dataset 1", + data: [ + { date: new Date(2020, 0, 23, 23, 0), value: 10 }, + { date: new Date(2020, 1, 9, 23, 0), value: 10 } + ] + } + ] +}; + +export const lineTimeSeriesTwoIdenticalLabelsOptions = { + title: "Line (time series) - Two identical labels", + axes: { + left: {}, + bottom: { + scaleType: "time" + } + }, + timeScale: { + addSpaceOnEdges: 0 + } +}; + +export const lineTimeSeriesTwoIdenticalLabels2Options = { + title: "Line (time series) - Two identical labels 2", + axes: { + left: {}, + bottom: { + scaleType: "time" + } + }, + timeScale: { + addSpaceOnEdges: 0 + } +}; + +// bug all labels in primary format +export const lineTimeSeriesDataAllLabelsInPrimaryFormat = { + labels: ["Qty"], + datasets: [ + { + label: "Dataset 1", + data: [ + { date: new Date(2020, 0, 23, 1, 0), value: 10 }, + { date: new Date(2020, 0, 29, 1, 0), value: 10 } + ] + } + ] +}; + +export const lineTimeSeriesAllLabelsInPrimaryFormatOptions = { + title: "Line (time series) - All labels in primary format", + axes: { + left: {}, + bottom: { + scaleType: "time" + } + }, + timeScale: { + addSpaceOnEdges: 0 + } +}; diff --git a/packages/core/src/components/axes/axis.ts b/packages/core/src/components/axes/axis.ts index a0c53e6cc9..d2a6846b04 100644 --- a/packages/core/src/components/axes/axis.ts +++ b/packages/core/src/components/axes/axis.ts @@ -133,17 +133,16 @@ export class Axis extends Component { if (!scale.ticks(numberOfTicks).length) { axis.tickValues([]); } else { - let tickValues = scale.ticks(numberOfTicks).concat(scale.domain()).map(date => +date).sort(); - tickValues = Tools.removeArrayDuplicates(tickValues); + const tickValues = scale.nice(numberOfTicks).ticks(numberOfTicks); - // Remove labels on the edges - // If there are more than 2 labels to show - if (Tools.getProperty(options, "timeScale", "addSpaceOnEdges") && tickValues.length > 2) { - tickValues.splice(tickValues.length - 1, 1); - tickValues.splice(0, 1); - } + // Remove labels on the edges + // If there are more than 2 labels to show + if (Tools.getProperty(options, "timeScale", "addSpaceOnEdges") && tickValues.length > 2) { + tickValues.splice(tickValues.length - 1, 1); + tickValues.splice(0, 1); + } - axis.tickValues(tickValues); + axis.tickValues(tickValues); } } } diff --git a/packages/core/src/services/time-series.spec.ts b/packages/core/src/services/time-series.spec.ts index 425f4c1702..6c548c9b0c 100644 --- a/packages/core/src/services/time-series.spec.ts +++ b/packages/core/src/services/time-series.spec.ts @@ -26,7 +26,7 @@ it("should format ticks with timeInterval 15seconds", () => { [new Date(2020, 11, 11, 0, 0, 0), "Dec 11, 12:00:00 AM"], [new Date(2020, 11, 11, 0, 0, 15), "12:00:15 AM"], [new Date(2020, 11, 11, 0, 0, 30), "12:00:30 AM"], - [new Date(2020, 11, 11, 0, 0, 45), "12:00:45 AM"], + [new Date(2020, 11, 11, 0, 0, 45), "12:00:45 AM"] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); @@ -47,7 +47,7 @@ it("should format ticks with timeInterval minute", () => { [new Date(2020, 4, 22, 11, 59, 0), "11:59 AM"], [new Date(2020, 4, 22, 12, 0, 0), "12:00 PM"], [new Date(2020, 4, 22, 12, 1, 0, 0), "12:01 PM"], - [new Date(2020, 4, 22, 12, 2, 0), "12:02 PM"], + [new Date(2020, 4, 22, 12, 2, 0), "12:02 PM"] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); @@ -63,7 +63,7 @@ it("should format ticks with timeInterval 30minutes", () => { [new Date(2020, 11, 11, 0, 0), "Dec 11, 12:00 AM"], [new Date(2020, 11, 11, 0, 30), "12:30 AM"], [new Date(2020, 11, 11, 1, 0), "1:00 AM"], - [new Date(2020, 11, 11, 1, 30), "1:30 AM"], + [new Date(2020, 11, 11, 1, 30), "1:30 AM"] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); @@ -85,7 +85,7 @@ it("should format ticks with timeInterval hourly", () => { [new Date(2020, 11, 11, 12, 0), "12 PM"], [new Date(2020, 11, 11, 13, 0), "01 PM"], [new Date(2020, 11, 11, 14, 0), "02 PM"], - [new Date(2020, 11, 11, 15, 0), "03 PM"], + [new Date(2020, 11, 11, 15, 0), "03 PM"] ]; const { timestamps: timestampsDefaultFormats, formattedTicks: formattedTicksDefaultFormats } = getTimestampsAndFormattedTicks(datasetDefaultFormats); @@ -106,7 +106,7 @@ it("should format ticks with timeInterval hourly", () => { [new Date(2020, 11, 11, 12, 0), "12:00"], [new Date(2020, 11, 11, 13, 0), "13:00"], [new Date(2020, 11, 11, 14, 0), "14:00"], - [new Date(2020, 11, 11, 15, 0), "15:00"], + [new Date(2020, 11, 11, 15, 0), "15:00"] ]; const { timestamps: timestampsCustomFormats, formattedTicks: formattedTicksCustomFormats } = getTimestampsAndFormattedTicks(datasetCustomFormats); @@ -115,7 +115,7 @@ it("should format ticks with timeInterval hourly", () => { const timeScaleCustomOptions = { ...timeScaleDefaultOptions, timeIntervalFormats: { - "hourly": { primary: "MMM d, HH:mm", secondary: "HH:mm" }, + "hourly": { primary: "MMM d, HH:mm", secondary: "HH:mm" } } }; expect(format(timestampsCustomFormats, timeIntervalCustomFormats, timeScaleCustomOptions)).toEqual(formattedTicksCustomFormats); @@ -134,7 +134,7 @@ it("should format ticks with timeInterval daily", () => { [new Date(2020, 0, 31), "31"], [new Date(2020, 1, 1), "Feb 1"], [new Date(2020, 1, 2), "2"], - [new Date(2020, 1, 3), "3"], + [new Date(2020, 1, 3), "3"] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); @@ -155,7 +155,7 @@ it("should format ticks with timeInterval weekly", () => { [new Date(2020, 1, 4), "Tue"], [new Date(2020, 1, 5), "Wed"], [new Date(2020, 1, 6), "Thu"], - [new Date(2020, 1, 7), "Fri"], + [new Date(2020, 1, 7), "Fri"] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); @@ -178,7 +178,7 @@ it("should format ticks with timeInterval monthly", () => { [new Date(2019, 11), "Dec"], [new Date(2020, 0), "Jan 2020"], [new Date(2020, 1), "Feb"], - [new Date(2020, 2), "Mar"], + [new Date(2020, 2), "Mar"] ]; const { timestamps: timestampsdefaultFormats, formattedTicks: formattedTicksdefaultFormats } = getTimestampsAndFormattedTicks(datasetdefaultFormats); @@ -199,7 +199,7 @@ it("should format ticks with timeInterval monthly", () => { [new Date(2019, 11), "déc."], [new Date(2020, 0), "janv. 2020"], [new Date(2020, 1), "févr."], - [new Date(2020, 2), "mars"], + [new Date(2020, 2), "mars"] ]; const { timestamps: timestampsCustomFormats, formattedTicks: formattedTicksCustomFormats } = getTimestampsAndFormattedTicks(datasetCustomFormats); @@ -222,7 +222,7 @@ it("should format ticks with timeInterval quarterly", () => { [new Date(2019, 5), `Q2`], [new Date(2019, 7), `Q3`], [new Date(2019, 10), `Q4`], - [new Date(2020, 0), `Q1 '20`], + [new Date(2020, 0), `Q1 '20`] ]; const { timestamps, formattedTicks } = getTimestampsAndFormattedTicks(dataset); const timeInterval = computeTimeIntervalName(timestamps); diff --git a/packages/core/src/services/time-series.ts b/packages/core/src/services/time-series.ts index 7df553bcd7..673e97bf54 100644 --- a/packages/core/src/services/time-series.ts +++ b/packages/core/src/services/time-series.ts @@ -83,12 +83,13 @@ function getConsecutiveDifferences(elements: number[]): number[] { return elements.slice(1).map((elem, i) => elem - elements[i]); } -// Given a number, return the closest TIME_INTERVAL name -function closestTimeIntervalName(ms: number): string { - const index = TIME_INTERVALS.reduce((acc, [key, value]: [string, number], i) => { - const previousSpan = Math.abs(acc - ms); - const currentSpan = Math.abs(value - ms); - return previousSpan < currentSpan ? acc : i; +// Given a duration in ms, return the closest TIME_INTERVAL name +function closestTimeIntervalName(duration: number): string { + const index = TIME_INTERVALS.reduce((nearestIndex, [intervalName, delta]: [string, number], i) => { + const deltaNearest = TIME_INTERVALS[nearestIndex][1] as number; + const oldNearestSpan = Math.abs(deltaNearest - duration); + const currentSpan = Math.abs(delta - duration); + return oldNearestSpan < currentSpan ? nearestIndex : i; }, 0); return TIME_INTERVALS[index][0] as string; }