Skip to content

Commit 581d9b8

Browse files
authored
Merge pull request #328 from emeeks/x-middles
Fix canvasInteraction in Ordinal and Network Frames, enable multi-X a…
2 parents 7f0a705 + 077a279 commit 581d9b8

File tree

11 files changed

+183
-71
lines changed

11 files changed

+183
-71
lines changed

src/components/Frame.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type Props = {
6262
matte?: boolean | Object | Node | Function,
6363
axes?: Array<AxisType>,
6464
axesTickLines?: Node,
65+
disableCanvasInteraction?: boolean,
6566
renderOrder: $ReadOnlyArray<| "pieces"
6667
| "summaries"
6768
| "connectors"
@@ -160,7 +161,8 @@ class Frame extends React.Component<Props, State> {
160161
useSpans,
161162
canvasRendering,
162163
renderOrder,
163-
additionalDefs
164+
additionalDefs,
165+
disableCanvasInteraction = false
164166
} = this.props
165167

166168
const { voronoiHover } = this.state
@@ -374,6 +376,7 @@ class Frame extends React.Component<Props, State> {
374376
rScale={rScale}
375377
projection={projection}
376378
interactionOverflow={interactionOverflow}
379+
disableCanvasInteraction={disableCanvasInteraction}
377380
/>
378381
{annotationLayer}
379382
</SpanOrDiv>

src/components/InteractionLayer.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ type Props = {
4343
customClickBehavior?: Function,
4444
customHoverBehavior?: Function,
4545
voronoiHover: Function,
46-
canvasRendering?: boolean
46+
canvasRendering?: boolean,
47+
disableCanvasInteraction: boolean
4748
}
4849

4950
type State = {
@@ -641,7 +642,8 @@ class InteractionLayer extends React.Component<Props, State> {
641642
svgSize,
642643
margin,
643644
useSpans = false,
644-
canvasRendering
645+
canvasRendering,
646+
disableCanvasInteraction
645647
} = this.props
646648
const { overlayRegions } = this.state
647649
let { enabled } = this.props
@@ -660,6 +662,7 @@ class InteractionLayer extends React.Component<Props, State> {
660662
}
661663

662664
const interactionCanvas =
665+
!disableCanvasInteraction &&
663666
canvasRendering &&
664667
this.state.overlayRegions &&
665668
this.state.interactionCanvas

src/components/NetworkFrame.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,7 @@ class NetworkFrame extends React.Component<Props, State> {
18321832
useSpans={!!useSpans}
18331833
canvasRendering={!!(canvasNodes || canvasEdges)}
18341834
renderOrder={renderOrder}
1835+
disableCanvasInteraction={true}
18351836
/>
18361837
)
18371838
}

src/components/OrdinalFrame.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,7 @@ class OrdinalFrame extends React.Component<OrdinalFrameProps, State> {
16951695
baseMarkProps={baseMarkProps}
16961696
canvasRendering={!!(canvasPieces || canvasSummaries)}
16971697
renderOrder={renderOrder}
1698+
disableCanvasInteraction={true}
16981699
/>
16991700
)
17001701
}

src/components/XYFrame.js

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
createAreas
3535
} from "./visualizationLayerBehavior/general"
3636

37-
import { relativeY, findPointByID } from "./svg/lineDrawing"
37+
import { relativeY, relativeX, findPointByID } from "./svg/lineDrawing"
3838
import AnnotationCallout from "react-annotation/lib/Types/AnnotationCallout"
3939

4040
import {
@@ -48,7 +48,10 @@ import {
4848
projectedY,
4949
projectedYTop,
5050
projectedYMiddle,
51-
projectedYBottom
51+
projectedYBottom,
52+
projectedXMiddle,
53+
projectedXTop,
54+
projectedXBottom
5255
} from "./constants/coordinateNames"
5356
import {
5457
calculateDataExtent,
@@ -233,7 +236,10 @@ const projectedCoordinateNames = {
233236
x: projectedX,
234237
yMiddle: projectedYMiddle,
235238
yTop: projectedYTop,
236-
yBottom: projectedYBottom
239+
yBottom: projectedYBottom,
240+
xMiddle: projectedXMiddle,
241+
xTop: projectedXTop,
242+
xBottom: projectedXBottom
237243
}
238244

239245
function mapParentsToPoints(fullDataset: Array<Object>) {
@@ -619,6 +625,7 @@ class XYFrame extends React.Component<XYFrameProps, State> {
619625

620626
const existingBaselines = {}
621627

628+
622629
if (currentProps.axes) {
623630
axesTickLines = []
624631
axes = currentProps.axes.map((d, i) => {
@@ -919,20 +926,20 @@ class XYFrame extends React.Component<XYFrameProps, State> {
919926
})
920927

921928
if (!d.coordinates && !d.bounds) {
922-
const xCoord = d[projectedX] || findFirstAccessorValue(xAccessor, d)
923929
screenCoordinates = [
924-
xScale(xCoord),
930+
relativeX({
931+
point: d,
932+
projectedXMiddle,
933+
projectedX,
934+
xAccessor,
935+
xScale
936+
}),
925937
relativeY({
926938
point: d,
927-
lines,
928939
projectedYMiddle,
929940
projectedY,
930-
projectedX,
931-
xAccessor,
932941
yAccessor,
933-
yScale,
934-
xScale,
935-
idAccessor
942+
yScale
936943
})
937944
]
938945

@@ -948,7 +955,14 @@ class XYFrame extends React.Component<XYFrameProps, State> {
948955
}
949956
} else if (!d.bounds) {
950957
screenCoordinates = d.coordinates.reduce((coords, p) => {
951-
const xCoordinate = xScale(findFirstAccessorValue(xAccessor, p)) + adjustedPosition[0]
958+
const xCoordinate = relativeX({
959+
point: p,
960+
projectedXMiddle,
961+
projectedX,
962+
xAccessor,
963+
xScale
964+
})
965+
952966
const yCoordinate = relativeY({
953967
point: p,
954968
lines,
@@ -964,6 +978,9 @@ class XYFrame extends React.Component<XYFrameProps, State> {
964978
if (Array.isArray(yCoordinate)) {
965979
return [...coords, [xCoordinate, Math.min(...yCoordinate)], [xCoordinate, Math.max(...yCoordinate)]]
966980
}
981+
else if (Array.isArray(xCoordinate)) {
982+
return [...coords, [Math.min(...xCoordinate), yCoordinate], [Math.max(...xCoordinate), yCoordinate]]
983+
}
967984
else {
968985
return [...coords, [xCoordinate, yCoordinate]]
969986
}}, [])
@@ -1112,8 +1129,8 @@ class XYFrame extends React.Component<XYFrameProps, State> {
11121129
return null
11131130
}
11141131

1115-
const xCoord = d[projectedX] || findFirstAccessorValue(xAccessor, d)
1116-
const yCoord = d[projectedY] || findFirstAccessorValue(yAccessor, d)
1132+
const xCoord = d[projectedXMiddle] || d[projectedX] || findFirstAccessorValue(xAccessor, d)
1133+
const yCoord = d[projectedYMiddle] || d[projectedY] || findFirstAccessorValue(yAccessor, d)
11171134

11181135
const xString = xCoord && xCoord.toString ? xCoord.toString() : xCoord
11191136
const yString = yCoord && yCoord.toString ? yCoord.toString() : yCoord

src/components/annotationRules/xyframeRules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const pointsAlong = along => ({
5959
key={`found-circle-${i}`}
6060
r={r(p, i)}
6161
style={styleFn(p, i)}
62-
cx={xScale(p.x)}
62+
cx={xScale(p.xMiddle || p.x)}
6363
cy={yScale(p.yMiddle || p.yTop)}
6464
/>
6565
))

src/components/constants/coordinateNames.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@ export const projectedY = "y"
33
export const projectedYMiddle = "yMiddle"
44
export const projectedYTop = "yTop"
55
export const projectedYBottom = "yBottom"
6-
7-
/*
8-
Use symbols for x/y/offset to avoid conflicts when projecting the dataset
9-
But how to expose those for custom hover rules?
10-
*/
11-
12-
/*
13-
const projectedX = Symbol('x');
14-
const projectedY = Symbol('y');
15-
const projectedYMiddle = Symbol('y-middle');
16-
const projectedOffset = Symbol('offset');
17-
*/
6+
export const projectedXMiddle = "xMiddle"
7+
export const projectedXTop = "xTop"
8+
export const projectedXBottom = "xBottom"

src/components/data/dataFunctions.js

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import {
66
projectedY,
77
projectedYTop,
88
projectedYMiddle,
9-
projectedYBottom
9+
projectedYBottom,
10+
projectedXBottom,
11+
projectedXMiddle,
12+
projectedXTop
1013
} from "../constants/coordinateNames"
1114
import {
1215
differenceLine,
@@ -17,7 +20,7 @@ import {
1720
} from "../svg/lineDrawing"
1821

1922
import { contouring, hexbinning, heatmapping } from "../svg/areaDrawing"
20-
import { max, min, extent } from "d3-array"
23+
import { max, min } from "d3-array"
2124

2225
import { extentValue } from "./unflowedFunctions"
2326

@@ -127,6 +130,14 @@ export const calculateDataExtent = ({
127130
projectedPoint[projectedYTop]) /
128131
2
129132
}
133+
if (Array.isArray(x)) {
134+
projectedPoint[projectedXBottom] = Math.min(...x)
135+
projectedPoint[projectedXTop] = Math.max(...x)
136+
projectedPoint[projectedXMiddle] =
137+
(projectedPoint[projectedXBottom] +
138+
projectedPoint[projectedXTop]) /
139+
2
140+
}
130141
projectedPoints.push(projectedPoint)
131142
})
132143
})
@@ -151,7 +162,10 @@ export const calculateDataExtent = ({
151162
yProp: projectedY,
152163
yPropMiddle: projectedYMiddle,
153164
yPropTop: projectedYTop,
154-
yPropBottom: projectedYBottom
165+
yPropBottom: projectedYBottom,
166+
xPropMiddle: projectedXMiddle,
167+
xPropTop: projectedXTop,
168+
xPropBottom: projectedXBottom
155169
}
156170

157171
projectedLines = lineTransformation(lineType, optionsObject)(
@@ -227,7 +241,26 @@ export const calculateDataExtent = ({
227241
}))
228242
}
229243

230-
const calculatedXExtent = extent(fullDataset.map(d => d[projectedX]))
244+
const calculatedXExtent = [
245+
min(
246+
fullDataset.map(
247+
d =>
248+
d[projectedXBottom] === undefined
249+
? d[projectedX]
250+
: Math.min(d[projectedXTop], d[projectedXBottom])
251+
)
252+
),
253+
254+
max(
255+
fullDataset.map(
256+
d =>
257+
d[projectedXTop] === undefined
258+
? d[projectedX]
259+
: Math.max(d[projectedXBottom], d[projectedXTop])
260+
)
261+
)
262+
]
263+
231264
const calculatedYExtent = [
232265
min(
233266
fullDataset.map(
@@ -321,21 +354,7 @@ export const calculateDataExtent = ({
321354
...projectedAreas.map(d => ({ ...d })),
322355
...fullDataset.filter(d => !d.parentArea)
323356
]
324-
} /*else if (
325-
typeof areaType === "function" ||
326-
(areaType && areaType.type && typeof areaType.type === "function")
327-
) {
328-
const areaFunction = areaType.type || areaType
329-
330-
projectedAreas = areaFunction({
331-
xExtent: finalXExtent,
332-
yExtent: finalYExtent,
333-
projectedX,
334-
projectedY,
335-
fullDataset,
336-
projectedAreas
337-
})
338-
} */
357+
}
339358

340359
return {
341360
xExtent: finalXExtent,

src/components/svg/lineDrawing.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,18 @@ type LineChartTypes = {
6060

6161
type RelativeYTypes = {
6262
point: ?Object,
63-
lines: Object,
6463
projectedYMiddle: string,
6564
projectedY: string,
65+
yAccessor: Array<Function>,
66+
yScale: Function
67+
}
68+
69+
type RelativeXTypes = {
70+
point: ?Object,
71+
projectedXMiddle: string,
6672
projectedX: string,
6773
xAccessor: Array<Function>,
68-
yAccessor: Array<Function>,
69-
yScale: Function,
70-
xScale: Function,
71-
idAccessor: Function
74+
xScale: Function
7275
}
7376

7477
export const projectAreaData = ({
@@ -513,6 +516,25 @@ export function relativeY({
513516
return (baseData && yScale(baseData)) || 0
514517
}
515518

519+
export function relativeX({
520+
point,
521+
projectedXMiddle,
522+
projectedX,
523+
xAccessor,
524+
xScale
525+
}: RelativeXTypes) {
526+
const baseData =
527+
point &&
528+
(point[projectedXMiddle] ||
529+
point[projectedX] ||
530+
findFirstAccessorValue(xAccessor, point))
531+
532+
if (Array.isArray(baseData)) {
533+
return baseData.map(d => xScale(d))
534+
}
535+
return (baseData && xScale(baseData)) || 0
536+
}
537+
516538
export function findPointByID({
517539
point,
518540
idAccessor,

0 commit comments

Comments
 (0)