Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

Feature/voronoi container #432

Merged
merged 28 commits into from
Feb 25, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5f0683e
safety commit
boygirl Feb 6, 2017
f8e60a8
working voronoi find
boygirl Feb 6, 2017
cfd26b8
match child calculation to victory-shared-events
boygirl Feb 8, 2017
a412452
clean up selection helper
boygirl Feb 8, 2017
cd732ff
progress on nested component voronoi
boygirl Feb 8, 2017
17f4e9a
safety commit
boygirl Feb 8, 2017
5b2451a
Merge branch 'master' of https://github.com/FormidableLabs/victory-ch…
boygirl Feb 8, 2017
d9086b9
revert map / reduce replacement
boygirl Feb 9, 2017
e5138f2
working voronoi hover
boygirl Feb 9, 2017
923ba2a
fix scatter label padding
boygirl Feb 10, 2017
7f8cfc1
safety commit - individual data labels for line
boygirl Feb 13, 2017
1998018
support data labels for VictoryLine and VictoryArea
boygirl Feb 17, 2017
37889fa
merge master into feature/voronoi-container
boygirl Feb 17, 2017
faf67c1
filter 'all' from dataKeys
boygirl Feb 17, 2017
5f33a8b
clean up demos
boygirl Feb 17, 2017
387c308
multi point tooltips for voronoi container
boygirl Feb 21, 2017
e7a8913
safety commit
boygirl Feb 22, 2017
da911a5
fix flyout positioning
boygirl Feb 22, 2017
832f5d1
add theme to container props
boygirl Feb 22, 2017
b47f0f9
fix line spec
boygirl Feb 22, 2017
2b68023
add deprecation notices for label prop, clean up demos
boygirl Feb 22, 2017
de3be37
add deprecation warnings to old voronoi components
boygirl Feb 22, 2017
566233d
cooler demo
boygirl Feb 23, 2017
e1acc11
Merge branch 'master' of https://github.com/FormidableLabs/victory-ch…
boygirl Feb 23, 2017
187b359
fix lines after merge
boygirl Feb 25, 2017
8593309
reconcile flyout style with themes
boygirl Feb 25, 2017
a83d1e8
update victory-core
boygirl Feb 25, 2017
2b3ce9d
merge master into feature/voronoi-container
boygirl Feb 25, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
safety commit
  • Loading branch information
boygirl committed Feb 22, 2017
commit e7a8913da9a2f490a9b878019a5a70bceac430a3
7 changes: 5 additions & 2 deletions demo/components/victory-voronoi-container-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ class App extends React.Component {
<div style={containerStyle}>
<VictoryChart style={chartStyle}
containerComponent={
<VictoryVoronoiContainer radius={50} labels={(d) => d.l}/>
<VictoryVoronoiContainer dimension="x"
labels={(d) => d.l}
labelComponent={<VictoryTooltip pointerLength={0} cornerRadius={0}/>}
/>
}
>
<VictoryLine
Expand Down Expand Up @@ -101,7 +104,7 @@ class App extends React.Component {
fill: (datum, active) => active ? "tomato" : "black"
}
}}
containerComponent={<VictoryVoronoiContainer size={20}/>}
containerComponent={<VictoryVoronoiContainer dimension="x"/>}
size={(datum, active) => active ? 5 : 3}
data={this.state.data}
x="a"
Expand Down
93 changes: 85 additions & 8 deletions src/components/containers/victory-voronoi-container.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { VictoryContainer, VictoryTooltip, Helpers } from "victory-core";
import { VictoryContainer, VictoryTooltip, Helpers, TextSize } from "victory-core";
import VoronoiHelpers from "./voronoi-helpers";
import { omit } from "lodash";

Expand All @@ -14,12 +14,14 @@ export default class VictoryVoronoiContainer extends VictoryContainer {
radius: React.PropTypes.number,
voronoiPadding: React.PropTypes.number,
labelComponent: React.PropTypes.element,
labels: React.PropTypes.func
labels: React.PropTypes.func,
dimension: React.PropTypes.oneOf(["x", "y"])
};
static defaultProps = {
...VictoryContainer.defaultProps,
standalone: true,
labelComponent: <VictoryTooltip/>
labelComponent: <VictoryTooltip/>,
voronoiPadding: 5
};

static defaultEvents = [{
Expand All @@ -43,10 +45,80 @@ export default class VictoryVoronoiContainer extends VictoryContainer {
}
}];

getLabelPosition(point, scale) {
getLabelPadding(style) {
if (!style) {
return 0;
}
const paddings = Array.isArray(style) ? style.map((s) => s.padding) : [style.padding];
return Math.max(...paddings, 0);
}

getFlyoutSize(labelComponent, text, style) {
const padding = this.getLabelPadding(style);
const textSize = TextSize.approximateTextSize(text, style);
return {
x: labelComponent.width || textSize.width + padding,
y: labelComponent.height || textSize.height + padding
};
}

getFlyoutExtent(props, point, flyoutSize) {
const {labelComponent, mousePosition} = props;
const dataX = point._x1 !== undefined ? point._x1 : point._x;
const dataY = point._y1 !== undefined ? point._y1 : point._y;
const {x, y} = mousePosition;
const orientation = labelComponent.props && labelComponent.props.orientation;
const horizontal = labelComponent.props && labelComponent.props.horizontal;
const signs = { left: 1, right: -1, top: 1, bottom: -1 };
const pointSigns = { x: dataX < 0 ? -1 : 1, y: dataY < 0 ? -1 : 1};
const multiplier = {
x: horizontal ? signs[orientation] || pointSigns.x : 0,
y: horizontal ? 0 : signs[orientation] || pointSigns.y
};
const extent = {
x: horizontal ?
[x, x + multiplier.x * flyoutSize.x] : [x - (flyoutSize.x / 2), x + (flyoutSize.x / 2)],
y: horizontal ?
[y - (flyoutSize.y / 2), y + (flyoutSize.y / 2)] : [y, y + multiplier.y * flyoutSize.y]
};
return {
x: scale.x(point._x1 !== undefined ? point._x1 : point._x),
y: scale.y(point._y1 !== undefined ? point._y1 : point._y)
x: [Math.min(...extent.x), Math.max(...extent.x)],
y: [Math.min(...extent.y), Math.max(...extent.y)]
};
}

getLabelPosition(props, point, text, style) { // eslint-disable-line max-params
const { mousePosition, dimension, scale, labelComponent } = props;
const dataX = point._x1 !== undefined ? point._x1 : point._x;
const dataY = point._y1 !== undefined ? point._y1 : point._y;
const basePosition = {
x: scale.x(dataX),
y: scale.y(dataY)
};
if (!dimension) {
return basePosition;
}
const x = dimension === "y" ? mousePosition.x : basePosition.x;
const y = dimension === "x" ? mousePosition.y : basePosition.y;
const flyoutSize = this.getFlyoutSize(labelComponent, text, style);
const range = { x: scale.x.range, y: scale.y.range };
const extent = {
x: [range.x[0] + flyoutSize.x, range.x[1] - flyoutSize.x],
y: [range.y[0] + flyoutSize.y, range.y[1] - flyoutSize.y],
};
const flyoutExtent = this.getFlyoutExtent(props, point, flyoutSize);
const adjustments = {
x: [
flyoutExtent.x[0] < extent.x[0] ? extent.x[0] - flyoutExtent.x[0] : 0,
flyoutExtent.x[1] > extent.x[1] ? flyoutExtent.x[1] - extent.x[1] : 0
],
y: [
flyoutExtent.y[0] < extent.y[0] ? extent.y[0] - flyoutExtent.y[0] : 0,
flyoutExtent.y[1] > extent.y[1] ? flyoutExtent.y[1] - extent.y[1] : 0
]
};
return {
x: x + adjustments.x[0] - adjustments.x[1], y: y + adjustments.y[0] - adjustments.y[1]
};
}

Expand All @@ -59,12 +131,15 @@ export default class VictoryVoronoiContainer extends VictoryContainer {

getLabelProps(props, points) {
const {labels, scale} = props;
const labelPosition = this.getLabelPosition(points[0], scale);
const text = points.map((point) => Helpers.evaluateProp(labels, point, true));
const style = this.getLabelStyle(points);
const labelPosition = this.getLabelPosition(props, points[0], text, style);
console.log(labelPosition, text)
return {
active: true,
renderInPortal: false,
style,
text: points.map((point) => Helpers.evaluateProp(labels, point, true)),
text,
datum: omit(points[0], ["childName", "style", "continuous"]),
scale,
...labelPosition
Expand All @@ -78,6 +153,8 @@ export default class VictoryVoronoiContainer extends VictoryContainer {
}
if (Array.isArray(activePoints) && activePoints.length) {
return React.cloneElement(labelComponent, this.getLabelProps(props, activePoints));
} else {
return null;
}
}

Expand Down
68 changes: 38 additions & 30 deletions src/components/containers/voronoi-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,21 @@ const VoronoiHelpers = {

getDatasets(props) {
const addMeta = (data, name, child) => {
const continuous = child.type && child.type.continuous;
const style = child.props && child.props.style;
const continuous = child && child.type && child.type.continuous;
const style = child ? child.props && child.props.style : props.style;
return data.map((datum, index) => {
return assign({childName: name, eventKey: index, continuous, style}, datum);
const x = datum._x1 !== undefined ? datum._x1 : datum._x;
const y = datum._y1 !== undefined ? datum._y1 : datum._y;
return assign({
_voronoiX: props.dimension === "y" ? 0 : x,
_voronoiY: props.dimension === "x" ? 0 : y,
childName: name, eventKey: index, continuous, style
}, datum);
});
};

if (props.data) {
return props.data;
return addMeta(props.data);
}

const getData = (childProps) => {
Expand Down Expand Up @@ -49,8 +55,8 @@ const VoronoiHelpers = {
mergeDatasets(props, datasets) {
const {scale} = props;
const points = groupBy(datasets, (datum) => {
const x = scale.x(datum ._x1 !== undefined ? datum ._x1 : datum ._x);
const y = scale.y(datum ._y1 !== undefined ? datum ._y1 : datum ._y);
const x = scale.x(datum ._voronoiX);
const y = scale.y(datum ._voronoiY);
return `${x},${y}`;
});
return keys(points).map((key) => {
Expand Down Expand Up @@ -97,38 +103,40 @@ const VoronoiHelpers = {
},

onMouseLeave(evt, targetProps) {
const activePoints = targetProps.activePoints || [];
const parentMutations = [{
target: "parent",
mutation: () => {
return { activePoints: [] };
}
}];
return activePoints.length ?
activePoints.reduce((memo, point) => {
memo = memo.concat(this.getInactiveMutations(targetProps, point));
return memo;
}, [parentMutations]) : parentMutations;
// const activePoints = targetProps.activePoints || [];
// const parentMutations = [{
// target: "parent",
// mutation: () => {
// return { activePoints: []};
// }
// }];
// const inactiveMutations = activePoints.length ?
// activePoints.map((point) => this.getInactiveMutations(targetProps, point)) : [];
// return parentMutations.concat(...inactiveMutations);
},

onMouseMove(evt, targetProps) {
const activePoints = targetProps.activePoints || [];
const {x, y} = Selection.getSVGEventCoordinates(evt);
if (!this.withinBounds(targetProps, {x, y})) {
return activePoints.length ?
activePoints.reduce((memo, point) => {
memo = memo.concat(this.getInactiveMutations(point));
return memo;
}, []) : [];
}
const voronoi = this.getVoronoi(targetProps); // TODO: animation
const nearestVoronoi = voronoi.find(x, y, targetProps.radius);
// if (!this.withinBounds(targetProps, {x, y})) {
// const parentMutations = [{
// target: "parent",
// mutation: () => {
// return { activePoints: [], mousePosition: {x, y}};
// }
// }];
// const inactiveMutations = activePoints.length ?
// activePoints.map((point) => this.getInactiveMutations(targetProps, point)) : [];
// return parentMutations.concat(...inactiveMutations);
// }
const voronoi = this.getVoronoi(targetProps);
const size = targetProps.dimension ? undefined : targetProps.radius;
const nearestVoronoi = voronoi.find(x, y, size);
const points = nearestVoronoi ? nearestVoronoi.data.points : [];
const parentMutations = [{
target: "parent",
eventKey: "parent",
mutation: () => {
return { activePoints: points, voronoi };
return { activePoints: points, mousePosition: {x, y}};
}
}];
if (activePoints.length && isEqual(points, activePoints)) {
Expand All @@ -145,5 +153,5 @@ const VoronoiHelpers = {

export default {
onMouseLeave: VoronoiHelpers.onMouseLeave.bind(VoronoiHelpers),
onMouseMove: throttle(VoronoiHelpers.onMouseMove.bind(VoronoiHelpers), 1, {leading: true})
onMouseMove: throttle(VoronoiHelpers.onMouseMove.bind(VoronoiHelpers), 16, {leading: true})
};