Skip to content

Commit d258d13

Browse files
committed
fix: do not plot undefined/NaN
1 parent c8a5867 commit d258d13

File tree

6 files changed

+56
-28
lines changed

6 files changed

+56
-28
lines changed

docs/src/pages/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const Home = props => {
113113
<div className="leading-none">
114114
<sup>
115115
* Okay, there is a time and place for them, but not
116-
often and certainlly not here 😜.
116+
often and certainly not here 😜.
117117
</sup>
118118
</div>
119119
</div>

src/components/Chart.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,10 @@ function ChartInner<TDatum>({
669669
throw new Error('Invalid elementType')
670670
})()
671671

672+
if (primaryAxis.isInvalid || secondaryAxis.isInvalid) {
673+
return null
674+
}
675+
672676
return (
673677
<Component
674678
key={axisId ?? '__default__'}

src/seriesTypes/Line.tsx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { area, line } from 'd3-shape'
22
import React from 'react'
33

44
import { Axis, Series, Datum } from '../types'
5-
import { translate } from '../utils/Utils'
5+
import { isDefined, translate } from '../utils/Utils'
66
import useChartContext from '../utils/chartContext'
77
//
88
import { monotoneX } from '../utils/curveMonotone'
@@ -36,30 +36,35 @@ export default function Line<TDatum>({
3636
{allSeries.map((series, i) => {
3737
const style = getSeriesStatusStyle(series, focusedDatum)
3838

39-
const areaPath =
40-
secondaryAxis.elementType === 'area'
41-
? area<Datum<TDatum>>(
42-
datum => getPrimary(datum, primaryAxis) ?? NaN,
43-
datum =>
44-
clampPxToAxis(
45-
getSecondaryStart(datum, secondaryAxis) ?? NaN,
46-
secondaryAxis
47-
),
48-
datum =>
49-
clampPxToAxis(
50-
getSecondary(datum, secondaryAxis) ?? NaN,
51-
secondaryAxis
52-
)
53-
).curve(curve)(series.datums) ?? undefined
54-
: undefined
39+
let areaPath: null | string = null
40+
41+
if (secondaryAxis.elementType === 'area') {
42+
const _x = (datum: Datum<TDatum>) => getPrimary(datum, primaryAxis)
43+
const _y1 = (datum: Datum<TDatum>) =>
44+
clampPxToAxis(
45+
getSecondaryStart(datum, secondaryAxis),
46+
secondaryAxis
47+
)
48+
const _y2 = (datum: Datum<TDatum>) =>
49+
clampPxToAxis(getSecondary(datum, secondaryAxis), secondaryAxis)
50+
const areaFn = area<Datum<TDatum>>(_x, _y1, _y2).curve(curve)
51+
52+
areaFn.defined(datum =>
53+
[_x(datum), _y1(datum), _y2(datum)].every(isDefined)
54+
)
55+
56+
areaPath = areaFn(series.datums)
57+
}
58+
59+
const _x = (datum: Datum<TDatum>) => getPrimary(datum, primaryAxis)
60+
const _y = (datum: Datum<TDatum>) => getSecondary(datum, secondaryAxis)
61+
const lineFn = line<Datum<TDatum>>(_x, _y).curve(curve)
62+
lineFn.defined(datum => [_x(datum), _y(datum)].every(isDefined))
5563

5664
const linePath =
5765
secondaryAxis.elementType === 'area' ||
5866
secondaryAxis.elementType === 'line'
59-
? line<Datum<TDatum>>(
60-
datum => getPrimary(datum, primaryAxis) ?? NaN,
61-
datum => getSecondary(datum, secondaryAxis) ?? NaN
62-
).curve(curve)(series.datums) ?? undefined
67+
? lineFn(series.datums) ?? undefined
6368
: undefined
6469

6570
const showDatumElements =
@@ -112,8 +117,8 @@ export default function Line<TDatum>({
112117
ref={el => {
113118
datum.element = el
114119
}}
115-
cx={getX(datum, primaryAxis, secondaryAxis)}
116-
cy={getY(datum, primaryAxis, secondaryAxis)}
120+
cx={getX(datum, primaryAxis, secondaryAxis) || 0}
121+
cy={getY(datum, primaryAxis, secondaryAxis) || 0}
117122
style={{
118123
// @ts-ignore
119124
r: radius,

src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ export type AxisTime<TDatum> = Omit<
368368
'format'
369369
> & {
370370
isPrimary?: boolean
371+
isInvalid: boolean
371372
axisFamily: 'time'
372373
scale: ScaleTime<number, number, never>
373374
outerScale: ScaleTime<number, number, never>
@@ -386,6 +387,7 @@ export type AxisLinear<TDatum> = Omit<
386387
'format'
387388
> & {
388389
isPrimary?: boolean
390+
isInvalid: boolean
389391
axisFamily: 'linear'
390392
scale: ScaleLinear<number, number, never>
391393
outerScale: ScaleLinear<number, number, never>
@@ -404,6 +406,7 @@ export type AxisBand<TDatum> = Omit<
404406
'format'
405407
> & {
406408
isPrimary?: boolean
409+
isInvalid: boolean
407410
axisFamily: 'band'
408411
scale: ScaleBand<any>
409412
outerScale: ScaleBand<any>

src/utils/Utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,7 @@ function normalizeColor(
7070
fill: style.fill || style.color || defaults.fill || defaults.color,
7171
}
7272
}
73+
74+
export function isDefined(num: number) {
75+
return typeof num === 'number' && !Number.isNaN(num)
76+
}

src/utils/buildAxis.linear.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ function buildTimeAxis<TDatum>(
108108
): AxisTime<TDatum> {
109109
const scaleFn = options.scaleType === 'localTime' ? scaleTime : scaleUtc
110110

111+
let isInvalid = false
112+
111113
// Now set the range
112114
const scale = scaleFn(range)
113115

@@ -140,15 +142,15 @@ function buildTimeAxis<TDatum>(
140142
}
141143

142144
if (minValue === undefined || maxValue === undefined) {
143-
console.info({
145+
console.info('Invalid scale min/max was detect for a chart:', {
144146
options,
145147
series,
146148
range,
147149
values: allDatums.map(d =>
148150
isPrimary ? d.primaryValue : d.secondaryValue
149151
),
150152
})
151-
throw new Error('Invalid scale min/max')
153+
isInvalid = true
152154
}
153155

154156
// Set the domain
@@ -200,6 +202,7 @@ function buildTimeAxis<TDatum>(
200202

201203
return {
202204
...options,
205+
isInvalid,
203206
axisFamily: 'time',
204207
isVertical,
205208
scale,
@@ -222,6 +225,8 @@ function buildLinearAxis<TDatum>(
222225
): AxisLinear<TDatum> {
223226
const scale = options.scaleType === 'log' ? scaleLog() : scaleLinear()
224227

228+
let isInvalid = false
229+
225230
if (options.stacked) {
226231
stackSeries(series, options)
227232
}
@@ -279,15 +284,18 @@ function buildLinearAxis<TDatum>(
279284
}
280285

281286
if (minValue === undefined || maxValue === undefined) {
282-
console.info({
287+
isInvalid = true
288+
console.info('Invalid scale min/max', {
283289
options,
284290
series,
285291
range,
286292
values: allDatums.map(d =>
287293
isPrimary ? d.primaryValue : d.secondaryValue
288294
),
289295
})
290-
throw new Error('Invalid scale min/max')
296+
minValue = minValue ?? 0
297+
maxValue = maxValue ?? 0
298+
// throw new Error('Invalid scale min/max')
291299
}
292300

293301
// Set the domain
@@ -340,6 +348,7 @@ function buildLinearAxis<TDatum>(
340348

341349
return {
342350
...options,
351+
isInvalid,
343352
axisFamily: 'linear',
344353
isVertical,
345354
scale,
@@ -361,6 +370,8 @@ function buildBandAxis<TDatum>(
361370
): AxisBand<TDatum> {
362371
series = series.filter(d => d.secondaryAxisId === options.id)
363372

373+
let isInvalid = false
374+
364375
const domain = Array.from(
365376
new Set(
366377
series
@@ -421,6 +432,7 @@ function buildBandAxis<TDatum>(
421432

422433
return {
423434
...options,
435+
isInvalid,
424436
axisFamily: 'band',
425437
isVertical,
426438
scale,

0 commit comments

Comments
 (0)