Skip to content

Commit 2936325

Browse files
committed
fix: vertical voronois, tooltips, min/max
1 parent 91c47d5 commit 2936325

File tree

12 files changed

+2101
-1995
lines changed

12 files changed

+2101
-1995
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import ResizableBox from "../ResizableBox";
2+
import useDemoConfig from "../useDemoConfig";
3+
import React from "react";
4+
import { AxisOptions, Chart } from "react-charts";
5+
6+
export default function Bar() {
7+
const { data, randomizeData } = useDemoConfig({
8+
series: 10,
9+
dataType: "ordinal",
10+
});
11+
12+
const primaryAxis = React.useMemo<
13+
AxisOptions<typeof data[number]["data"][number]>
14+
>(
15+
() => ({
16+
isPrimary: true,
17+
scaleType: "band",
18+
position: "left",
19+
getValue: (datum) => datum.primary,
20+
}),
21+
[]
22+
);
23+
24+
const secondaryAxes = React.useMemo<
25+
AxisOptions<typeof data[number]["data"][number]>[]
26+
>(
27+
() => [
28+
{
29+
scaleType: "linear",
30+
position: "bottom",
31+
getValue: (datum) => datum.secondary,
32+
elementType: "bar",
33+
stacked: true,
34+
},
35+
],
36+
[]
37+
);
38+
39+
return (
40+
<>
41+
<button onClick={randomizeData}>Randomize Data</button>
42+
<br />
43+
<br />
44+
<ResizableBox>
45+
<Chart
46+
options={{
47+
data,
48+
primaryAxis,
49+
secondaryAxes,
50+
tooltip: true,
51+
}}
52+
/>
53+
</ResizableBox>
54+
</>
55+
);
56+
}

examples/simple/src/components/Bubble.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function Bubble() {
1717
isPrimary: true,
1818
scaleType: "time",
1919
position: "bottom",
20-
getValue: (datum) => (datum.primary as unknown) as Date,
20+
getValue: (datum) => datum.primary as unknown as Date,
2121
}),
2222
[]
2323
);

examples/simple/src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import GroupingModes from "./components/GroupingModes";
99
import Line from "./components/Line";
1010
import MultipleAxes from "./components/MultipleAxes";
1111
import Steam from "./components/Steam";
12+
import BarHorizontal from "./components/BarHorizontal";
1213
import "./styles.css";
1314
import useLagRadar from "./useLagRadar";
1415
import React from "react";
@@ -17,6 +18,7 @@ import ReactDOM from "react-dom";
1718
const components = [
1819
["Line", Line],
1920
["Bar", Bar],
21+
["Bar (Horizontal)", BarHorizontal],
2022
["Band", Band],
2123
["Area", Area],
2224
["Bubble", Bubble],

src/components/Voronoi.tsx

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22

33
//
44
import { Datum } from '../types'
5-
import { translate } from '../utils/Utils'
5+
import { getPrimary, translate } from '../utils/Utils'
66
import useChartContext from '../utils/chartContext'
77

88
export default function Voronoi<TDatum>() {
@@ -74,25 +74,19 @@ function PrimaryVoronoi<TDatum>({
7474
const next = series[0].datums[i + 1]
7575

7676
const primaryValue = primaryAxis.getValue(datum.originalDatum)
77-
const primaryPx = primaryAxis?.scale(primaryValue) ?? NaN
77+
const primaryPx = getPrimary(datum, primaryAxis)
7878

7979
let range = primaryAxis?.scale.range() ?? [0, 0]
8080

81-
if (primaryAxis?.isVertical) {
82-
range.reverse()
83-
}
84-
8581
let [primaryStart, primaryEnd] = range
8682

8783
if (prev) {
88-
const prevPx =
89-
primaryAxis?.scale(primaryAxis.getValue(prev.originalDatum)) ?? NaN
84+
const prevPx = getPrimary(prev, primaryAxis)
9085
primaryStart = primaryPx - (primaryPx - prevPx) / 2
9186
}
9287

9388
if (next) {
94-
const nextPx =
95-
primaryAxis?.scale(primaryAxis.getValue(next.originalDatum)) ?? NaN
89+
const nextPx = getPrimary(next, primaryAxis)
9690
primaryEnd = primaryPx + (nextPx - primaryPx) / 2
9791
}
9892

@@ -129,20 +123,21 @@ function PrimaryVoronoi<TDatum>({
129123
if (secondaryAxis?.stacked) {
130124
let range = secondaryAxis?.scale.range() ?? [0, 0]
131125

126+
let stackData = [datum.stackData?.[0], datum.stackData?.[1]]
127+
132128
if (secondaryAxis?.isVertical) {
133129
range.reverse()
130+
stackData.reverse()
134131
}
135132

136133
let [secondaryStart, secondaryEnd] = range
137134

138135
if (prev) {
139-
secondaryStart =
140-
secondaryAxis?.scale(datum.stackData?.[1] ?? NaN) ?? NaN
136+
secondaryStart = secondaryAxis?.scale(stackData[0] ?? NaN) ?? NaN
141137
}
142138

143139
if (next) {
144-
secondaryEnd =
145-
secondaryAxis?.scale(datum.stackData?.[0] ?? NaN) ?? NaN
140+
secondaryEnd = secondaryAxis?.scale(stackData[1] ?? NaN) ?? NaN
146141
}
147142

148143
return {
@@ -237,7 +232,11 @@ function PrimaryVoronoi<TDatum>({
237232
className: 'action-voronoi',
238233
onMouseEnter: () => handleFocus(datumBoundary.datum),
239234
style: {
240-
fill: randomFill(),
235+
fill: getOptions().dark
236+
? '#ffffff33'
237+
: 'rgba(0,0,0,0.2)',
238+
strokeWidth: 1,
239+
stroke: getOptions().dark ? 'white' : 'black',
241240
opacity: getOptions().showVoronoi ? 1 : 0,
242241
},
243242
}}
@@ -335,37 +334,3 @@ function PrimaryVoronoi<TDatum>({
335334
// </g>
336335
// )
337336
// }
338-
339-
function randomFill() {
340-
const r = randomHue(100, 200)
341-
const g = randomHue(0, r)
342-
const b = randomHue(0, g)
343-
344-
const colors = shuffle([r, g, b])
345-
346-
return `rgba(${colors.join(', ')}, .5)`
347-
}
348-
349-
function randomHue(min = 0, max = 255) {
350-
return Math.floor(min + Math.random() * Math.min(max, 255 - min))
351-
}
352-
353-
function shuffle<T>(array: T[]): T[] {
354-
var currentIndex = array.length,
355-
randomIndex
356-
357-
// While there remain elements to shuffle...
358-
while (0 !== currentIndex) {
359-
// Pick a remaining element...
360-
randomIndex = Math.floor(Math.random() * currentIndex)
361-
currentIndex--
362-
363-
// And swap it with the current element.
364-
;[array[currentIndex], array[randomIndex]] = [
365-
array[randomIndex],
366-
array[currentIndex],
367-
]
368-
}
369-
370-
return array
371-
}

src/hooks/useRect.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,8 @@ export default function useRect(
2929
}
3030
})
3131

32-
const initialRectSet = React.useRef(false)
33-
3432
useIsomorphicLayoutEffect(() => {
35-
if (enabled && element && !initialRectSet.current) {
36-
initialRectSet.current = true
33+
if (enabled && element) {
3734
setRect(element.getBoundingClientRect())
3835
}
3936
}, [element, enabled])

src/seriesTypes/Area.tsx

Lines changed: 9 additions & 24 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 { getX, getY, getYStart, translate } from '../utils/Utils'
66
import useChartContext from '../utils/chartContext'
77
//
88
import { monotoneX } from '../utils/curveMonotone'
@@ -27,21 +27,6 @@ export default function AreaComponent<TDatum>({
2727

2828
const [focusedDatum] = useFocusedDatumAtom()
2929

30-
const xAxis = primaryAxis.isVertical ? secondaryAxis : primaryAxis
31-
const yAxis = !primaryAxis.isVertical ? secondaryAxis : primaryAxis
32-
33-
const getX = (datum: Datum<TDatum>) =>
34-
xAxis.scale(
35-
xAxis.stacked ? datum.stackData?.[1] : xAxis.getValue(datum.originalDatum)
36-
)
37-
38-
const getY = (datum: Datum<TDatum>, isEnd: 0 | 1) =>
39-
yAxis.scale(
40-
yAxis.stacked
41-
? datum.stackData?.[isEnd]
42-
: yAxis.getValue(datum.originalDatum)
43-
)
44-
4530
return (
4631
<g
4732
style={{
@@ -67,15 +52,15 @@ export default function AreaComponent<TDatum>({
6752

6853
const areaPath =
6954
area<Datum<TDatum>>(
70-
datum => getX(datum) ?? NaN,
71-
datum => getY(datum, 0) ?? NaN,
72-
datum => getY(datum, 1) ?? NaN
55+
datum => getX(datum, primaryAxis, secondaryAxis) ?? NaN,
56+
datum => getYStart(datum, primaryAxis, secondaryAxis) ?? NaN,
57+
datum => getY(datum, primaryAxis, secondaryAxis) ?? NaN
7358
).curve(curve)(series.datums) ?? undefined
7459

7560
const linePath =
7661
line<Datum<TDatum>>(
77-
datum => getX(datum) ?? NaN,
78-
datum => getY(datum, 1) ?? NaN
62+
datum => getX(datum, primaryAxis, secondaryAxis) ?? NaN,
63+
datum => getY(datum, primaryAxis, secondaryAxis) ?? NaN
7964
).curve(curve)(series.datums) ?? undefined
8065

8166
return (
@@ -92,8 +77,8 @@ export default function AreaComponent<TDatum>({
9277
datum.element = el
9378
}}
9479
r={2}
95-
cx={getX(datum)}
96-
cy={getY(datum, 1) ?? NaN}
80+
cx={getX(datum, primaryAxis, secondaryAxis)}
81+
cy={getY(datum, primaryAxis, secondaryAxis) ?? NaN}
9782
stroke="rgba(33,33,33,0.5)"
9883
style={{
9984
// @ts-ignore
@@ -102,7 +87,7 @@ export default function AreaComponent<TDatum>({
10287
...style.circle,
10388
...dataStyle,
10489
...dataStyle.circle,
105-
...(!(secondaryAxis.showDatumElements ?? true)
90+
...(!(secondaryAxis.showDatumElements ?? false)
10691
? {
10792
opacity: 0,
10893
}

src/seriesTypes/Bar.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import React from 'react'
22

33
import { Axis, Series } from '../types'
4-
import { getHeight, getWidth, getX, getY, translate } from '../utils/Utils'
4+
import {
5+
getHeight,
6+
getWidth,
7+
getX,
8+
getXStart,
9+
getY,
10+
getYStart,
11+
translate,
12+
} from '../utils/Utils'
513
import useChartContext from '../utils/chartContext'
614

715
//
@@ -44,8 +52,8 @@ export default function BarComponent<TDatum>({
4452
datum.element = el
4553
}}
4654
key={i}
47-
x={getX(datum, primaryAxis, secondaryAxis) ?? NaN}
48-
y={getY(datum, primaryAxis, secondaryAxis) ?? NaN}
55+
x={getXStart(datum, primaryAxis, secondaryAxis) ?? NaN}
56+
y={getYStart(datum, primaryAxis, secondaryAxis) ?? NaN}
4957
width={getWidth(datum, primaryAxis, secondaryAxis) ?? NaN}
5058
height={getHeight(datum, primaryAxis, secondaryAxis) ?? NaN}
5159
style={{

src/seriesTypes/Line.tsx

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { 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 { getX, getY, translate } from '../utils/Utils'
66
import useChartContext from '../utils/chartContext'
77
//
88
import { monotoneX } from '../utils/curveMonotone'
@@ -31,19 +31,6 @@ export default function Line<TDatum>({
3131

3232
const [focusedDatum] = useFocusedDatumAtom()
3333

34-
const xAxis = primaryAxis.isVertical ? secondaryAxis : primaryAxis
35-
const yAxis = !primaryAxis.isVertical ? secondaryAxis : primaryAxis
36-
37-
const getX = (datum: Datum<TDatum>) =>
38-
xAxis.scale(
39-
xAxis.stacked ? datum.stackData?.[1] : xAxis.getValue(datum.originalDatum)
40-
)
41-
42-
const getY = (datum: Datum<TDatum>) =>
43-
yAxis.scale(
44-
yAxis.stacked ? datum.stackData?.[1] : yAxis.getValue(datum.originalDatum)
45-
)
46-
4734
return (
4835
<g
4936
style={{
@@ -62,8 +49,8 @@ export default function Line<TDatum>({
6249

6350
const linePath =
6451
line<Datum<TDatum>>(
65-
datum => getX(datum) ?? NaN,
66-
datum => getY(datum) ?? NaN
52+
datum => getX(datum, primaryAxis, secondaryAxis) ?? NaN,
53+
datum => getY(datum, primaryAxis, secondaryAxis) ?? NaN
6754
).curve(curve)(series.datums) ?? undefined
6855

6956
return (
@@ -78,8 +65,8 @@ export default function Line<TDatum>({
7865
datum.element = el
7966
}}
8067
r={2}
81-
cx={getX(datum)}
82-
cy={getY(datum)}
68+
cx={getX(datum, primaryAxis, secondaryAxis)}
69+
cy={getY(datum, primaryAxis, secondaryAxis)}
8370
stroke="rgba(33,33,33,0.5)"
8471
fill="transparent"
8572
style={{

0 commit comments

Comments
 (0)